Compare commits

..

12 Commits

Author SHA1 Message Date
Jonas Jenwald
a8ad7d6485
Merge pull request #19645 from Snuffleupagus/OutputScale-pixelRatio
Add an `OutputScale` static method to get the `devicePixelRatio`
2025-03-12 21:22:16 +01:00
Jonas Jenwald
319d239f41 Add an OutputScale static method to get the devicePixelRatio
Currently we lookup the `devicePixelRatio`, with fallback handling, in a number of spots in the code-base.
Rather than duplicating code we can instead add a new static method in the `OutputScale` class, since that one is now exposed in the API.
2025-03-12 21:07:06 +01:00
Jonas Jenwald
e4795f639c
Merge pull request #19644 from Snuffleupagus/crypto-PDFBase
Introduce a common base class for the `PDF17` and `PDF20` crypto classes
2025-03-12 21:05:39 +01:00
Jonas Jenwald
643c44b631
Merge pull request #19643 from Snuffleupagus/l10n-update
Update l10n files
2025-03-12 21:02:24 +01:00
Jonas Jenwald
0cbb2b1d13
Merge pull request #19646 from Snuffleupagus/dont-cache-MIN_TOUCH_DISTANCE_TO_PINCH
Don't shadow the `TouchManager.prototype.MIN_TOUCH_DISTANCE_TO_PINCH` value
2025-03-12 21:02:02 +01:00
Jonas Jenwald
bec6287b0a
Merge pull request #19647 from Snuffleupagus/bug-1953099
Let `Lexer.prototype.getNumber` treat more cases of a single minus sign as zero (bug 1953099)
2025-03-12 19:34:07 +01:00
calixteman
7bc7416111
Merge pull request #19642 from calixteman/bug1953003
[Editor] Fix the style of the buttons in dialog (bug 1953003)
2025-03-12 19:24:53 +01:00
Jonas Jenwald
ee34c5c648 Let Lexer.prototype.getNumber treat more cases of a single minus sign as zero (bug 1953099)
This patch extends the approach of PR 14543, by also treating e.g. minus signs followed by '(' or '<' as zero.
Inside of a /Contents stream those characters will generally mean the start of one or more glyphs.
2025-03-12 17:50:13 +01:00
Jonas Jenwald
92adc7ea1b Don't shadow the TouchManager.prototype.MIN_TOUCH_DISTANCE_TO_PINCH value
The `devicePixelRatio` may change if the window resolution changes, which can happen e.g. if the viewer is moved to another monitor.
2025-03-12 14:53:20 +01:00
Jonas Jenwald
2ff6829e47 Introduce a common base class for the PDF17 and PDF20 crypto classes
With the exception of a different hashing function these classes are identical, and the base class thus help reduce code duplication.

This patch reduces the size of the `gulp mozcentral` build with 1344 bytes, which isn't a lot but still cannot hurt.
2025-03-12 12:25:55 +01:00
Jonas Jenwald
4ebcc996d0 Update l10n files
Given the recently added l10n-strings, let's do yet another update before the upcoming release to avoid needlessly "broken" translations.
2025-03-12 09:58:52 +01:00
Calixte Denizet
216e17afc5 [Editor] Fix the style of the buttons in dialog (bug 1953003)
This patch fixes:
 - the style of the primary/secondary buttons in the dialog which weren't fully compliant to the last specs.
 - the style of the input field in HCM (wrong background)
 - the color of the link in the image tab.
2025-03-11 20:03:23 +01:00
22 changed files with 190 additions and 91 deletions

View File

@ -529,8 +529,8 @@ pdfjs-editor-add-signature-dialog-title = Gehitu sinadura
## Tab names ## Tab names
# Type is a verb (you can type your name as signature) # Type is a verb (you can type your name as signature)
pdfjs-editor-add-signature-type-button = Mota pdfjs-editor-add-signature-type-button = Idatzi
.title = Mota .title = Idatzi
# Draw is a verb (you can draw your signature) # Draw is a verb (you can draw your signature)
pdfjs-editor-add-signature-draw-button = Marraztu pdfjs-editor-add-signature-draw-button = Marraztu
.title = Marraztu .title = Marraztu

View File

@ -316,6 +316,9 @@ pdfjs-highlight-floating-button1 =
.title = Evidenzie .title = Evidenzie
.aria-label = Evidenzie .aria-label = Evidenzie
pdfjs-highlight-floating-button-label = Evidenzie pdfjs-highlight-floating-button-label = Evidenzie
pdfjs-editor-signature-button =
.title = Zonte firme
pdfjs-editor-signature-button-label = Zonte firme
## Remove button for the various kind of editor. ## Remove button for the various kind of editor.
@ -345,6 +348,9 @@ pdfjs-editor-stamp-add-image-button-label = Zonte imagjin
pdfjs-editor-free-highlight-thickness-input = Spessôr pdfjs-editor-free-highlight-thickness-input = Spessôr
pdfjs-editor-free-highlight-thickness-title = pdfjs-editor-free-highlight-thickness-title =
.title = Modifiche il spessôr de selezion pai elements che no son testuâi .title = Modifiche il spessôr de selezion pai elements che no son testuâi
pdfjs-editor-signature-add-signature-button =
.title = Zonte gnove firme
pdfjs-editor-signature-add-signature-button-label = Zonte gnove firme
# .default-content is used as a placeholder in an empty text editor. # .default-content is used as a placeholder in an empty text editor.
pdfjs-free-text2 = pdfjs-free-text2 =
.aria-label = Editôr di test .aria-label = Editôr di test
@ -570,12 +576,18 @@ pdfjs-editor-add-signature-error-close-button = Siere
pdfjs-editor-add-signature-cancel-button = Anule pdfjs-editor-add-signature-cancel-button = Anule
pdfjs-editor-add-signature-add-button = Zonte pdfjs-editor-add-signature-add-button = Zonte
pdfjs-editor-edit-signature-update-button = Inzorne
## Main menu for adding/removing signatures ## Main menu for adding/removing signatures
pdfjs-editor-delete-signature-button =
.title = Gjave firme
pdfjs-editor-delete-signature-button-label = Gjave firme
## Editor toolbar ## Editor toolbar
pdfjs-editor-add-signature-edit-button-label = Modifiche descrizion
## Edit signature description dialog ## Edit signature description dialog
pdfjs-editor-edit-signature-dialog-title = Modifiche descrizion

View File

@ -316,6 +316,9 @@ pdfjs-highlight-floating-button1 =
.title = Markearje .title = Markearje
.aria-label = Markearje .aria-label = Markearje
pdfjs-highlight-floating-button-label = Markearje pdfjs-highlight-floating-button-label = Markearje
pdfjs-editor-signature-button =
.title = Hantekening tafoegje
pdfjs-editor-signature-button-label = Hantekening tafoegje
## Remove button for the various kind of editor. ## Remove button for the various kind of editor.
@ -345,6 +348,9 @@ pdfjs-editor-stamp-add-image-button-label = Ofbylding tafoegje
pdfjs-editor-free-highlight-thickness-input = Tsjokte pdfjs-editor-free-highlight-thickness-input = Tsjokte
pdfjs-editor-free-highlight-thickness-title = pdfjs-editor-free-highlight-thickness-title =
.title = Tsjokte wizigje by aksintuearring fan oare items as tekst .title = Tsjokte wizigje by aksintuearring fan oare items as tekst
pdfjs-editor-signature-add-signature-button =
.title = Nije hantekening tafoegje
pdfjs-editor-signature-add-signature-button-label = Nije hantekening tafoegje
# .default-content is used as a placeholder in an empty text editor. # .default-content is used as a placeholder in an empty text editor.
pdfjs-free-text2 = pdfjs-free-text2 =
.aria-label = Tekstbewurker .aria-label = Tekstbewurker
@ -570,12 +576,17 @@ pdfjs-editor-add-signature-error-close-button = Slute
pdfjs-editor-add-signature-cancel-button = Annulearje pdfjs-editor-add-signature-cancel-button = Annulearje
pdfjs-editor-add-signature-add-button = Tafoegje pdfjs-editor-add-signature-add-button = Tafoegje
pdfjs-editor-edit-signature-update-button = Bywurkje
## Main menu for adding/removing signatures ## Main menu for adding/removing signatures
pdfjs-editor-delete-signature-button =
.title = Hantekening fuortsmite
pdfjs-editor-delete-signature-button-label = Hantekening fuortsmite
## Editor toolbar ## Editor toolbar
pdfjs-editor-add-signature-edit-button-label = Beskriuwing bewurkje
## Edit signature description dialog ## Edit signature description dialog

View File

@ -566,6 +566,9 @@ pdfjs-editor-add-signature-clear-button-label = Emboguete teraguapy
pdfjs-editor-add-signature-clear-button = pdfjs-editor-add-signature-clear-button =
.title = Emboguete teraguapy .title = Emboguete teraguapy
pdfjs-editor-add-signature-save-checkbox = Eñongatu teraguapy pdfjs-editor-add-signature-save-checkbox = Eñongatu teraguapy
pdfjs-editor-add-signature-save-warning-message = Ehupytýma 5 mboheraguapy ñongatupyre. Embogue peteĩ eñongatukuaa jey hag̃ua.
pdfjs-editor-add-signature-image-upload-error-title = Ndaikatúi ojehupi pe taãnga
pdfjs-editor-add-signature-image-upload-error-description = Ehechajey ne ñanduti oikópa térã ahaã ambue taãnga ndive.
pdfjs-editor-add-signature-error-close-button = Mboty pdfjs-editor-add-signature-error-close-button = Mboty
## Dialog buttons ## Dialog buttons

View File

@ -39,6 +39,9 @@ pdfjs-open-file-button-label = Բացել
pdfjs-print-button = pdfjs-print-button =
.title = Տպել .title = Տպել
pdfjs-print-button-label = Տպել pdfjs-print-button-label = Տպել
pdfjs-save-button =
.title = Պահպանել
pdfjs-save-button-label = Պահպանել
# Used in Firefox for Android as a label for the download button (“download” is a verb). # Used in Firefox for Android as a label for the download button (“download” is a verb).
# Length of the translation matters since we are in a mobile context, with limited screen estate. # Length of the translation matters since we are in a mobile context, with limited screen estate.
pdfjs-download-button-label = Ներբեռնել pdfjs-download-button-label = Ներբեռնել
@ -256,6 +259,7 @@ pdfjs-free-text-default-content = Սկսել մուտքագրումը…
## Alt-text dialog ## Alt-text dialog
pdfjs-editor-alt-text-save-button = Պահպանել
## Editor resizers ## Editor resizers
## This is used in an aria label to help to understand the role of the resizer. ## This is used in an aria label to help to understand the role of the resizer.

View File

@ -525,6 +525,7 @@ pdfjs-editor-undo-bar-close-button-label = Kapat
## Add a signature dialog ## Add a signature dialog
pdfjs-editor-add-signature-dialog-label = Bu pencereden PDF belgesine eklemek üzere imza oluşturabilirsiniz. Adınızı düzenleyebilir (adınız alt metin olarak da kullanılır) ve isterseniz ileride tekrar kullanmak üzere imzayı kaydedebilirsiniz.
pdfjs-editor-add-signature-dialog-title = İmza ekle pdfjs-editor-add-signature-dialog-title = İmza ekle
## Tab names ## Tab names

View File

@ -173,8 +173,8 @@ pdfjs-print-progress-message = 正在準備列印文件…
# $progress (Number) - percent value # $progress (Number) - percent value
pdfjs-print-progress-percent = { $progress }% pdfjs-print-progress-percent = { $progress }%
pdfjs-print-progress-close-button = 取消 pdfjs-print-progress-close-button = 取消
pdfjs-printing-not-supported = 警告: 此瀏覽器未完整支援列印功能。 pdfjs-printing-not-supported = 警告此瀏覽器未完整支援列印功能。
pdfjs-printing-not-ready = 警告: 此 PDF 未完成下載以供列印。 pdfjs-printing-not-ready = 警告此 PDF 未完成下載以供列印。
## Tooltips and alt text for side panel toolbar buttons ## Tooltips and alt text for side panel toolbar buttons

View File

@ -632,13 +632,26 @@ class AES256Cipher extends AESBaseCipher {
} }
} }
class PDF17 { class PDFBase {
constructor() {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
this.constructor === PDFBase
) {
unreachable("Cannot initialize PDFBase.");
}
}
_hash(password, input, userBytes) {
unreachable("Abstract method `_hash` called");
}
checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
const hashData = new Uint8Array(password.length + 56); const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerValidationSalt, password.length); hashData.set(ownerValidationSalt, password.length);
hashData.set(userBytes, password.length + ownerValidationSalt.length); hashData.set(userBytes, password.length + ownerValidationSalt.length);
const result = calculateSHA256(hashData, 0, hashData.length); const result = this._hash(password, hashData, userBytes);
return isArrayEqual(result, ownerPassword); return isArrayEqual(result, ownerPassword);
} }
@ -646,7 +659,7 @@ class PDF17 {
const hashData = new Uint8Array(password.length + 8); const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userValidationSalt, password.length); hashData.set(userValidationSalt, password.length);
const result = calculateSHA256(hashData, 0, hashData.length); const result = this._hash(password, hashData, []);
return isArrayEqual(result, userPassword); return isArrayEqual(result, userPassword);
} }
@ -655,7 +668,7 @@ class PDF17 {
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerKeySalt, password.length); hashData.set(ownerKeySalt, password.length);
hashData.set(userBytes, password.length + ownerKeySalt.length); hashData.set(userBytes, password.length + ownerKeySalt.length);
const key = calculateSHA256(hashData, 0, hashData.length); const key = this._hash(password, hashData, userBytes);
const cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
} }
@ -665,14 +678,20 @@ class PDF17 {
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userKeySalt, password.length); hashData.set(userKeySalt, password.length);
// `key` is the decryption key for the UE string. // `key` is the decryption key for the UE string.
const key = calculateSHA256(hashData, 0, hashData.length); const key = this._hash(password, hashData, []);
const cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
} }
} }
class PDF20 { class PDF17 extends PDFBase {
#hash(password, input, userBytes) { _hash(password, input, userBytes) {
return calculateSHA256(input, 0, input.length);
}
}
class PDF20 extends PDFBase {
_hash(password, input, userBytes) {
// This refers to Algorithm 2.B as defined in ISO 32000-2. // This refers to Algorithm 2.B as defined in ISO 32000-2.
let k = calculateSHA256(input, 0, input.length).subarray(0, 32); let k = calculateSHA256(input, 0, input.length).subarray(0, 32);
let e = [0]; let e = [0];
@ -713,43 +732,6 @@ class PDF20 {
} }
return k.subarray(0, 32); return k.subarray(0, 32);
} }
checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0);
hashData.set(ownerValidationSalt, password.length);
hashData.set(userBytes, password.length + ownerValidationSalt.length);
const result = this.#hash(password, hashData, userBytes);
return isArrayEqual(result, ownerPassword);
}
checkUserPassword(password, userValidationSalt, userPassword) {
const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0);
hashData.set(userValidationSalt, password.length);
const result = this.#hash(password, hashData, []);
return isArrayEqual(result, userPassword);
}
getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0);
hashData.set(ownerKeySalt, password.length);
hashData.set(userBytes, password.length + ownerKeySalt.length);
const key = this.#hash(password, hashData, userBytes);
const cipher = new AES256Cipher(key);
return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
}
getUserKey(password, userKeySalt, userEncryption) {
const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0);
hashData.set(userKeySalt, password.length);
// `key` is the decryption key for the UE string.
const key = this.#hash(password, hashData, []);
const cipher = new AES256Cipher(key);
return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
}
} }
class CipherTransform { class CipherTransform {

View File

@ -933,9 +933,14 @@ class Lexer {
if (ch < /* '0' = */ 0x30 || ch > /* '9' = */ 0x39) { if (ch < /* '0' = */ 0x30 || ch > /* '9' = */ 0x39) {
const msg = `Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`; const msg = `Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`;
if (isWhiteSpace(ch) || ch === /* EOF = */ -1) { if (
isWhiteSpace(ch) ||
/* '(' = */ ch === 0x28 ||
/* '<' = */ ch === 0x3c ||
ch === /* EOF = */ -1
) {
// This is consistent with Adobe Reader (fixes issue9252.pdf, // This is consistent with Adobe Reader (fixes issue9252.pdf,
// issue15604.pdf, bug1753983.pdf). // issue15604.pdf, bug1753983.pdf, bug1953099.pdf).
info(`Lexer.getNumber - "${msg}".`); info(`Lexer.getNumber - "${msg}".`);
return 0; return 0;
} }

View File

@ -30,6 +30,7 @@ import {
import { import {
getCurrentTransform, getCurrentTransform,
getCurrentTransformInverse, getCurrentTransformInverse,
OutputScale,
PixelsPerInch, PixelsPerInch,
} from "./display_utils.js"; } from "./display_utils.js";
import { import {
@ -811,7 +812,7 @@ function getImageSmoothingEnabled(transform, interpolate) {
scale[0] = Math.fround(scale[0]); scale[0] = Math.fround(scale[0]);
scale[1] = Math.fround(scale[1]); scale[1] = Math.fround(scale[1]);
const actualScale = Math.fround( const actualScale = Math.fround(
(globalThis.devicePixelRatio || 1) * PixelsPerInch.PDF_TO_CSS_UNITS OutputScale.pixelRatio * PixelsPerInch.PDF_TO_CSS_UNITS
); );
return scale[0] <= actualScale && scale[1] <= actualScale; return scale[0] <= actualScale && scale[1] <= actualScale;
} }

View File

@ -620,7 +620,7 @@ function setLayerDimensions(
*/ */
class OutputScale { class OutputScale {
constructor() { constructor() {
const pixelRatio = window.devicePixelRatio || 1; const { pixelRatio } = OutputScale;
/** /**
* @type {number} Horizontal scale. * @type {number} Horizontal scale.
@ -673,6 +673,10 @@ class OutputScale {
} }
return false; return false;
} }
static get pixelRatio() {
return globalThis.devicePixelRatio || 1;
}
} }
// See https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types // See https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types

View File

@ -23,7 +23,7 @@ import {
Util, Util,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { setLayerDimensions } from "./display_utils.js"; import { OutputScale, setLayerDimensions } from "./display_utils.js";
/** /**
* @typedef {Object} TextLayerParameters * @typedef {Object} TextLayerParameters
@ -115,7 +115,7 @@ class TextLayer {
} }
this.#container = this.#rootContainer = container; this.#container = this.#rootContainer = container;
this.#scale = viewport.scale * (globalThis.devicePixelRatio || 1); this.#scale = viewport.scale * OutputScale.pixelRatio;
this.#rotation = viewport.rotation; this.#rotation = viewport.rotation;
this.#layoutTextParams = { this.#layoutTextParams = {
div: null, div: null,
@ -205,7 +205,7 @@ class TextLayer {
* @returns {undefined} * @returns {undefined}
*/ */
update({ viewport, onBefore = null }) { update({ viewport, onBefore = null }) {
const scale = viewport.scale * (globalThis.devicePixelRatio || 1); const scale = viewport.scale * OutputScale.pixelRatio;
const rotation = viewport.rotation; const rotation = viewport.rotation;
if (rotation !== this.#rotation) { if (rotation !== this.#rotation) {

View File

@ -13,8 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { shadow } from "../shared/util.js"; import { OutputScale, stopEvent } from "./display_utils.js";
import { stopEvent } from "./display_utils.js";
class TouchManager { class TouchManager {
#container; #container;
@ -65,6 +64,10 @@ class TouchManager {
}); });
} }
/**
* NOTE: Don't shadow this value since `devicePixelRatio` may change if the
* window resolution changes, e.g. if the viewer is moved to another monitor.
*/
get MIN_TOUCH_DISTANCE_TO_PINCH() { get MIN_TOUCH_DISTANCE_TO_PINCH() {
// The 35 is coming from: // The 35 is coming from:
// https://searchfox.org/mozilla-central/source/gfx/layers/apz/src/GestureEventListener.cpp#36 // https://searchfox.org/mozilla-central/source/gfx/layers/apz/src/GestureEventListener.cpp#36
@ -72,11 +75,7 @@ class TouchManager {
// The properties TouchEvent::screenX/Y are in screen CSS pixels: // The properties TouchEvent::screenX/Y are in screen CSS pixels:
// https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenX#examples // https://developer.mozilla.org/en-US/docs/Web/API/Touch/screenX#examples
// MIN_TOUCH_DISTANCE_TO_PINCH is in CSS pixels. // MIN_TOUCH_DISTANCE_TO_PINCH is in CSS pixels.
return shadow( return 35 / OutputScale.pixelRatio;
this,
"MIN_TOUCH_DISTANCE_TO_PINCH",
35 / (window.devicePixelRatio || 1)
);
} }
#onTouchStart(evt) { #onTouchStart(evt) {

View File

@ -20,6 +20,7 @@ const {
DrawLayer, DrawLayer,
getDocument, getDocument,
GlobalWorkerOptions, GlobalWorkerOptions,
OutputScale,
PixelsPerInch, PixelsPerInch,
shadow, shadow,
TextLayer, TextLayer,
@ -876,7 +877,7 @@ class Driver {
page => { page => {
// Default to creating the test images at the devices pixel ratio, // Default to creating the test images at the devices pixel ratio,
// unless the test explicitly specifies an output scale. // unless the test explicitly specifies an output scale.
const outputScale = task.outputScale || window.devicePixelRatio; const outputScale = task.outputScale || OutputScale.pixelRatio;
let viewport = page.getViewport({ let viewport = page.getViewport({
scale: PixelsPerInch.PDF_TO_CSS_UNITS, scale: PixelsPerInch.PDF_TO_CSS_UNITS,
}); });

View File

@ -16,6 +16,7 @@
!bug1727053.pdf !bug1727053.pdf
!issue18408_reduced.pdf !issue18408_reduced.pdf
!bug1907000_reduced.pdf !bug1907000_reduced.pdf
!bug1953099.pdf
!issue11913.pdf !issue11913.pdf
!issue2391-1.pdf !issue2391-1.pdf
!issue2391-2.pdf !issue2391-2.pdf

BIN
test/pdfs/bug1953099.pdf Normal file

Binary file not shown.

View File

@ -10414,6 +10414,14 @@
"link": true, "link": true,
"type": "eq" "type": "eq"
}, },
{
"id": "bug1953099",
"file": "pdfs/bug1953099.pdf",
"md5": "15295cfa4999ccc08442423fca96c28f",
"rounds": 1,
"link": false,
"type": "eq"
},
{ {
"id": "bug1899804_print", "id": "bug1899804_print",
"file": "pdfs/bug1899804.pdf", "file": "pdfs/bug1899804.pdf",

View File

@ -152,7 +152,17 @@ describe("parser", function () {
}); });
it("should treat a single decimal point, or minus/plus sign, as zero", function () { it("should treat a single decimal point, or minus/plus sign, as zero", function () {
const validNums = [".", "-", "+", "-.", "+.", "-\r\n.", "+\r\n."]; const validNums = [
".",
"-",
"+",
"-.",
"+.",
"-\r\n.",
"+\r\n.",
"-(",
"-<",
];
for (const number of validNums) { for (const number of validNums) {
const validInput = new StringStream(number); const validInput = new StringStream(number);
const validLexer = new Lexer(validInput); const validLexer = new Lexer(validInput);

View File

@ -50,6 +50,7 @@ import {
InvalidPDFException, InvalidPDFException,
isDataScheme, isDataScheme,
isPdfFile, isPdfFile,
OutputScale,
PDFWorker, PDFWorker,
ResponseException, ResponseException,
shadow, shadow,
@ -2091,7 +2092,7 @@ const PDFViewerApplication = {
pdfViewer.refresh(); pdfViewer.refresh();
} }
const mediaQueryList = window.matchMedia( const mediaQueryList = window.matchMedia(
`(resolution: ${window.devicePixelRatio || 1}dppx)` `(resolution: ${OutputScale.pixelRatio}dppx)`
); );
mediaQueryList.addEventListener("change", addWindowResolutionChange, { mediaQueryList.addEventListener("change", addWindowResolutionChange, {
once: true, once: true,

View File

@ -33,23 +33,32 @@
--radio-border-color: #8f8f9d; --radio-border-color: #8f8f9d;
--radio-checked-border-color: #0060df; --radio-checked-border-color: #0060df;
--button-secondary-bg-color: #f0f0f4; --button-secondary-bg-color: rgb(21 20 26 / 0.07);
--button-secondary-fg-color: var(--text-primary-color); --button-secondary-fg-color: var(--text-primary-color);
--button-secondary-border-color: var(--button-secondary-bg-color); --button-secondary-border-color: var(--button-secondary-bg-color);
--button-secondary-hover-bg-color: var(--button-secondary-bg-color); --button-secondary-active-bg-color: rgb(21 20 26 / 0.21);
--button-secondary-active-fg-color: var(--button-secondary-fg-color);
--button-secondary-active-border-color: var(--button-secondary-bg-color);
--button-secondary-hover-bg-color: rgb(21 20 26 / 0.14);
--button-secondary-hover-fg-color: var(--button-secondary-fg-color); --button-secondary-hover-fg-color: var(--button-secondary-fg-color);
--button-secondary-hover-border-color: var(--button-secondary-hover-bg-color); --button-secondary-hover-border-color: var(--button-secondary-hover-bg-color);
--button-primary-bg-color: #0060df; --button-primary-bg-color: #0060df;
--button-primary-fg-color: #fbfbfe; --button-primary-fg-color: #fbfbfe;
--button-primary-border-color: var(--button-primary-bg-color); --button-primary-border-color: var(--button-primary-bg-color);
--button-primary-hover-bg-color: var(--button-primary-bg-color); --button-primary-active-bg-color: #054096;
--button-primary-active-fg-color: var(--button-primary-fg-color);
--button-primary-active-border-color: var(--button-primary-active-bg-color);
--button-primary-hover-bg-color: #0250bb;
--button-primary-hover-fg-color: var(--button-primary-fg-color); --button-primary-hover-fg-color: var(--button-primary-fg-color);
--button-primary-hover-border-color: var(--button-primary-hover-bg-color); --button-primary-hover-border-color: var(--button-primary-hover-bg-color);
--button-disabled-bg-color: color-mix(in srgb, currentcolor, transparent 60%); --button-disabled-bg-color: color-mix(in srgb, currentcolor, transparent 60%);
--button-disabled-fg-color: var(--button-disabled-bg-color); --button-disabled-fg-color: var(--button-disabled-bg-color);
--input-text-bg-color: white;
--input-text-fg-color: var(--text-primary-color);
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
--dialog-bg-color: #1c1b22; --dialog-bg-color: #1c1b22;
--dialog-border-color: #1c1b22; --dialog-border-color: #1c1b22;
@ -67,9 +76,15 @@
--radio-checked-bg-color: #15141a; --radio-checked-bg-color: #15141a;
--radio-checked-border-color: #0df; --radio-checked-border-color: #0df;
--button-secondary-bg-color: #2b2a33; --button-secondary-bg-color: rgb(251 251 254 / 0.07);
--button-secondary-active-bg-color: rgb(251 251 254 / 0.21);
--button-secondary-hover-bg-color: rgb(251 251 254 / 0.14);
--button-primary-bg-color: #0df; --button-primary-bg-color: #0df;
--button-primary-fg-color: #15141a; --button-primary-fg-color: #15141a;
--button-primary-active-bg-color: #aaf2ff;
--button-primary-hover-bg-color: #80ebff;
--input-text-bg-color: #42414d;
} }
@media screen and (forced-colors: active) { @media screen and (forced-colors: active) {
@ -92,19 +107,31 @@
--radio-border-color: ButtonText; --radio-border-color: ButtonText;
--radio-checked-border-color: ButtonText; --radio-checked-border-color: ButtonText;
--button-secondary-bg-color: ButtonFace; --button-secondary-bg-color: HighlightText;
--button-secondary-fg-color: ButtonText; --button-secondary-fg-color: ButtonText;
--button-secondary-border-color: ButtonText; --button-secondary-border-color: ButtonText;
--button-secondary-hover-bg-color: AccentColor; --button-secondary-active-bg-color: HighlightText;
--button-secondary-hover-fg-color: AccentColorText; --button-secondary-active-fg-color: SelectedItem;
--button-secondary-active-border-color: ButtonText;
--button-secondary-hover-bg-color: HighlightText;
--button-secondary-hover-fg-color: SelectedItem;
--button-secondary-hover-border-color: SelectedItem;
--button-primary-bg-color: ButtonText; --button-primary-bg-color: ButtonText;
--button-primary-fg-color: ButtonFace; --button-primary-fg-color: HighlightText;
--button-primary-hover-bg-color: AccentColor; --button-primary-border-color: ButtonText;
--button-primary-hover-fg-color: AccentColorText; --button-primary-active-bg-color: SelectedItem;
--button-primary-active-fg-color: HighlightText;
--button-primary-active-border-color: ButtonText;
--button-primary-hover-bg-color: SelectedItem;
--button-primary-hover-fg-color: HighlightText;
--button-primary-hover-border-color: SelectedItem;
--button-disabled-bg-color: GrayText; --button-disabled-bg-color: GrayText;
--button-disabled-fg-color: ButtonFace; --button-disabled-fg-color: ButtonFace;
--input-text-bg-color: HighlightText;
--input-text-fg-color: FieldText;
} }
font: message-box; font: message-box;
@ -205,7 +232,8 @@
border-radius: 4px; border-radius: 4px;
border: 1px solid; border: 1px solid;
font: menu; font: menu;
font-weight: 600; font-weight: 590;
font-size: 13px;
padding: 4px 16px; padding: 4px 16px;
width: auto; width: auto;
height: 32px; height: 32px;
@ -217,6 +245,7 @@
> span { > span {
color: inherit; color: inherit;
font: inherit;
} }
&.secondaryButton { &.secondaryButton {
@ -229,6 +258,12 @@
background-color: var(--button-secondary-hover-bg-color); background-color: var(--button-secondary-hover-bg-color);
border-color: var(--button-secondary-hover-border-color); border-color: var(--button-secondary-hover-border-color);
} }
&:active {
color: var(--button-secondary-active-fg-color);
background-color: var(--button-secondary-active-bg-color);
border-color: var(--button-secondary-active-border-color);
}
} }
&.primaryButton { &.primaryButton {
@ -242,6 +277,12 @@
background-color: var(--button-primary-hover-bg-color); background-color: var(--button-primary-hover-bg-color);
border-color: var(--button-primary-hover-border-color); border-color: var(--button-primary-hover-border-color);
} }
&:active {
color: var(--button-primary-active-fg-color);
background-color: var(--button-primary-active-bg-color);
border-color: var(--button-primary-active-border-color);
}
} }
&:disabled { &:disabled {
@ -282,6 +323,11 @@
} }
} }
input[type="text"] {
background-color: var(--input-text-bg-color);
color: var(--input-text-fg-color);
}
.messageBar { .messageBar {
--message-bar-bg-color: #ffebcd; --message-bar-bg-color: #ffebcd;
--message-bar-fg-color: #15141a; --message-bar-fg-color: #15141a;

View File

@ -14,6 +14,7 @@
*/ */
import { BasePDFPageView } from "./base_pdf_page_view.js"; import { BasePDFPageView } from "./base_pdf_page_view.js";
import { OutputScale } from "pdfjs-lib";
import { RenderingStates } from "./ui_utils.js"; import { RenderingStates } from "./ui_utils.js";
/** @typedef {import("./interfaces").IRenderableView} IRenderableView */ /** @typedef {import("./interfaces").IRenderableView} IRenderableView */
@ -153,7 +154,7 @@ class PDFPageDetailView extends BasePDFPageView {
// but we can reduce it to make sure that we stay within the maxCanvasPixels // but we can reduce it to make sure that we stay within the maxCanvasPixels
// limit. // limit.
const visiblePixels = const visiblePixels =
visibleWidth * visibleHeight * (window.devicePixelRatio || 1) ** 2; visibleWidth * visibleHeight * OutputScale.pixelRatio ** 2;
const maxDetailToVisibleLinearRatio = Math.sqrt( const maxDetailToVisibleLinearRatio = Math.sqrt(
maxCanvasPixels / visiblePixels maxCanvasPixels / visiblePixels
); );
@ -228,18 +229,18 @@ class PDFPageDetailView extends BasePDFPageView {
const area = this.#detailArea; const area = this.#detailArea;
const { devicePixelRatio = 1 } = window; const { pixelRatio } = OutputScale;
const transform = [ const transform = [
devicePixelRatio, pixelRatio,
0, 0,
0, 0,
devicePixelRatio, pixelRatio,
-area.minX * devicePixelRatio, -area.minX * pixelRatio,
-area.minY * devicePixelRatio, -area.minY * pixelRatio,
]; ];
canvas.width = area.width * devicePixelRatio; canvas.width = area.width * pixelRatio;
canvas.height = area.height * devicePixelRatio; canvas.height = area.height * pixelRatio;
const { style } = canvas; const { style } = canvas;
style.width = `${(area.width * 100) / width}%`; style.width = `${(area.width * 100) / width}%`;
style.height = `${(area.height * 100) / height}%`; style.height = `${(area.height * 100) / height}%`;

View File

@ -50,10 +50,14 @@
--primary-color: var(--text-primary-color); --primary-color: var(--text-primary-color);
--description-input-color: var(--primary-color); --description-input-color: var(--primary-color);
--border-color: #8f8f9d; --border-color: #8f8f9d;
--open-link-fg: var(--link-fg-color);
--open-link-hover-fg: var(--link-hover-fg-color);
@media screen and (forced-colors: active) { @media screen and (forced-colors: active) {
--primary-color: ButtonText; --primary-color: ButtonText;
--border-color: ButtonText; --border-color: ButtonText;
--open-link-fg: ButtonText;
--open-link-hover-fg: ButtonText;
} }
width: 570px; width: 570px;
@ -82,9 +86,7 @@
.inputWithClearButton { .inputWithClearButton {
--button-dimension: 24px; --button-dimension: 24px;
--clear-button-icon: url(images/messageBar_closingButton.svg);
--closing-button-icon: url(images/messageBar_closingButton.svg);
--closing-button-color: var(--primary-color);
width: 100%; width: 100%;
position: relative; position: relative;
@ -97,10 +99,8 @@
height: 32px; height: 32px;
padding-inline: 8px calc(4px + var(--button-dimension)); padding-inline: 8px calc(4px + var(--button-dimension));
box-sizing: border-box; box-sizing: border-box;
background-color: transparent;
border-radius: 4px; border-radius: 4px;
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
color: var(--description-input-color);
} }
.clearInputButton { .clearInputButton {
@ -110,9 +110,9 @@
display: inline-block; display: inline-block;
width: var(--button-dimension); width: var(--button-dimension);
height: var(--button-dimension); height: var(--button-dimension);
background-color: var(--closing-button-color); background-color: var(--input-text-fg-color);
mask-size: cover; mask-size: cover;
mask-image: var(--closing-button-icon); mask-image: var(--clear-button-icon);
padding: 0; padding: 0;
border: 0; border: 0;
} }
@ -465,9 +465,18 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
span {
color: var(--signature-placeholder-color);
}
a { a {
color: var(--open-link-fg);
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;
&:hover {
color: var(--open-link-hover-fg);
}
} }
} }