From 12c12d12c3afe72c1a1b52a379a0e4842a85cd8f Mon Sep 17 00:00:00 2001 From: Updatebot Date: Thu, 30 May 2024 12:35:49 +0000 Subject: [PATCH] Bug 1899373 - Update PDF.js to 24e12d515dce2f11b392410dd6e6e9926270ac65 r=pdfjs-reviewers,frontend-codestyle-reviewers,marco Differential Revision: https://phabricator.services.mozilla.com/D211891 --- .stylelintignore | 1 + .../components/pdfjs/content/build/pdf.mjs | 257 +++++++---- .../pdfjs/content/build/pdf.scripting.mjs | 4 +- .../pdfjs/content/build/pdf.worker.mjs | 166 +++---- .../pdfjs/content/web/viewer-geckoview.css | 210 +++++++++ .../pdfjs/content/web/viewer-geckoview.mjs | 247 ++++------- .../components/pdfjs/content/web/viewer.css | 416 +++++++++--------- .../components/pdfjs/content/web/viewer.html | 8 +- .../components/pdfjs/content/web/viewer.mjs | 246 ++++------- toolkit/components/pdfjs/moz.yaml | 4 +- 10 files changed, 883 insertions(+), 676 deletions(-) diff --git a/.stylelintignore b/.stylelintignore index 7d8074cb5d14..26c927799499 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -92,6 +92,7 @@ python/mozbuild/mozbuild/test/backend/data/build/foo.css # This is third-party in a way: toolkit/components/pdfjs/content/web/debugger.css toolkit/components/pdfjs/content/web/viewer.css +toolkit/components/pdfjs/content/web/viewer-geckoview.css # Ignore web-platform tests as they are not necessarily under our control. testing/web-platform/tests/ diff --git a/toolkit/components/pdfjs/content/build/pdf.mjs b/toolkit/components/pdfjs/content/build/pdf.mjs index 3c13bbbd933e..c6e849febe67 100644 --- a/toolkit/components/pdfjs/content/build/pdf.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.mjs @@ -8872,7 +8872,7 @@ class TextLayer { #textDivProperties = new WeakMap(); #transform = null; static #ascentCache = new Map(); - static #canvasCtx = null; + static #canvasContexts = new Map(); static #pendingTextLayers = new Set(); constructor({ textContentSource, @@ -8904,7 +8904,6 @@ class TextLayer { this.#pageWidth = pageWidth; this.#pageHeight = pageHeight; setLayerDimensions(container, viewport); - TextLayer.#pendingTextLayers.add(this); this.#capability.promise.catch(() => {}).then(() => { TextLayer.#pendingTextLayers.delete(this); this.#layoutTextParams = null; @@ -8928,6 +8927,7 @@ class TextLayer { }, this.#capability.reject); }; this.#reader = this.#textContentSource.getReader(); + TextLayer.#pendingTextLayers.add(this); pump(); return this.#capability.promise; } @@ -9122,19 +9122,26 @@ class TextLayer { return; } this.#ascentCache.clear(); - this.#canvasCtx?.canvas.remove(); - this.#canvasCtx = null; + for (const { + canvas + } of this.#canvasContexts.values()) { + canvas.remove(); + } + this.#canvasContexts.clear(); } static #getCtx(lang = null) { - if (!this.#canvasCtx) { + let canvasContext = this.#canvasContexts.get(lang ||= ""); + if (!canvasContext) { const canvas = document.createElement("canvas"); canvas.className = "hiddenCanvasElement"; + canvas.lang = lang; document.body.append(canvas); - this.#canvasCtx = canvas.getContext("2d", { + canvasContext = canvas.getContext("2d", { alpha: false }); + this.#canvasContexts.set(lang, canvasContext); } - return this.#canvasCtx; + return canvasContext; } static #getAscent(fontFamily, lang) { const cachedAscent = this.#ascentCache.get(fontFamily); @@ -9327,7 +9334,7 @@ function getDocument(src) { } const docParams = { docId, - apiVersion: "4.3.83", + apiVersion: "4.3.138", data, password, disableAutoFetch, @@ -9351,11 +9358,13 @@ function getDocument(src) { const transportParams = { disableFontFace, fontExtraProperties, - enableXfa, ownerDocument, - disableAutoFetch, pdfBug, - styleElement + styleElement, + loadingParams: { + disableAutoFetch, + enableXfa + } }; worker.promise.then(function () { if (task.destroyed) { @@ -10227,6 +10236,7 @@ class WorkerTransport { ownerDocument: params.ownerDocument, styleElement: params.styleElement }); + this.loadingParams = params.loadingParams; this._params = params; this.canvasFactory = factory.canvasFactory; this.filterFactory = factory.filterFactory; @@ -10768,16 +10778,6 @@ class WorkerTransport { const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`; return this.#pageRefCache.get(refStr) ?? null; } - get loadingParams() { - const { - disableAutoFetch, - enableXfa - } = this._params; - return shadow(this, "loadingParams", { - disableAutoFetch, - enableXfa - }); - } } const INITIAL_DATA = Symbol("INITIAL_DATA"); class PDFObjects { @@ -10989,8 +10989,8 @@ class InternalRenderTask { } } } -const version = "4.3.83"; -const build = "9ee7c07b8"; +const version = "4.3.138"; +const build = "24e12d515"; ;// CONCATENATED MODULE: ./src/shared/scripting_utils.js function makeColorComp(n) { @@ -11341,6 +11341,7 @@ class AnnotationElementFactory { class AnnotationElement { #updates = null; #hasBorder = false; + #popupElement = null; constructor(parameters, { isRenderable = false, ignoreBorder = false, @@ -11389,12 +11390,14 @@ class AnnotationElement { if (rect) { this.#setRectEdited(rect); } + this.#popupElement?.popup.updateEdited(params); } resetEdited() { if (!this.#updates) { return; } this.#setRectEdited(this.#updates.rect); + this.#popupElement?.popup.resetEdited(); this.#updates = null; } #setRectEdited(rect) { @@ -11744,7 +11747,7 @@ class AnnotationElement { data } = this; container.setAttribute("aria-haspopup", "dialog"); - const popup = new PopupAnnotationElement({ + const popup = this.#popupElement = new PopupAnnotationElement({ data: { color: data.color, titleObj: data.titleObj, @@ -12946,10 +12949,11 @@ class PopupAnnotationElement extends AnnotationElement { isRenderable: AnnotationElement._hasPopupData(data) }); this.elements = elements; + this.popup = null; } render() { this.container.classList.add("popupAnnotation"); - const popup = new PopupElement({ + const popup = this.popup = new PopupElement({ container: this.container, color: this.data.color, titleObj: this.data.titleObj, @@ -12986,9 +12990,11 @@ class PopupElement { #parentRect = null; #pinned = false; #popup = null; + #position = null; #rect = null; #richText = null; #titleObj = null; + #updates = null; #wasVisible = false; constructor({ container, @@ -13032,19 +13038,6 @@ class PopupElement { if (this.#popup) { return; } - const { - page: { - view - }, - viewport: { - rawDims: { - pageWidth, - pageHeight, - pageX, - pageY - } - } - } = this.#parent; const popup = this.#popup = document.createElement("div"); popup.className = "popup"; if (this.#color) { @@ -13070,40 +13063,64 @@ class PopupElement { })); header.append(modificationDate); } - const contentsObj = this.#contentsObj; - const richText = this.#richText; - if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) { + const html = this.#html; + if (html) { XfaLayer.render({ - xfaHtml: richText.html, + xfaHtml: html, intent: "richText", div: popup }); popup.lastChild.classList.add("richText", "popupContent"); } else { - const contents = this._formatContents(contentsObj); + const contents = this._formatContents(this.#contentsObj); popup.append(contents); } - let useParentRect = !!this.#parentRect; - let rect = useParentRect ? this.#parentRect : this.#rect; - for (const element of this.#elements) { - if (!rect || Util.intersect(element.data.rect, rect) !== null) { - rect = element.data.rect; - useParentRect = true; - break; - } - } - const normalizedRect = Util.normalizeRect([rect[0], view[3] - rect[1] + view[1], rect[2], view[3] - rect[3] + view[1]]); - const HORIZONTAL_SPACE_AFTER_ANNOTATION = 5; - const parentWidth = useParentRect ? rect[2] - rect[0] + HORIZONTAL_SPACE_AFTER_ANNOTATION : 0; - const popupLeft = normalizedRect[0] + parentWidth; - const popupTop = normalizedRect[1]; - const { - style - } = this.#container; - style.left = `${100 * (popupLeft - pageX) / pageWidth}%`; - style.top = `${100 * (popupTop - pageY) / pageHeight}%`; this.#container.append(popup); } + get #html() { + const richText = this.#richText; + const contentsObj = this.#contentsObj; + if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) { + return this.#richText.html || null; + } + return null; + } + get #fontSize() { + return this.#html?.attributes?.style?.fontSize || 0; + } + get #fontColor() { + return this.#html?.attributes?.style?.color || null; + } + #makePopupContent(text) { + const popupLines = []; + const popupContent = { + str: text, + html: { + name: "div", + attributes: { + dir: "auto" + }, + children: [{ + name: "p", + children: popupLines + }] + } + }; + const lineAttributes = { + style: { + color: this.#fontColor, + fontSize: this.#fontSize ? `calc(${this.#fontSize}px * var(--scale-factor))` : "" + } + }; + for (const line of text.split("\n")) { + popupLines.push({ + name: "span", + value: line, + attributes: lineAttributes + }); + } + return popupContent; + } _formatContents({ str, dir @@ -13129,6 +13146,75 @@ class PopupElement { this.#toggle(); } } + updateEdited({ + rect, + popupContent + }) { + this.#updates ||= { + contentsObj: this.#contentsObj, + richText: this.#richText + }; + if (rect) { + this.#position = null; + } + if (popupContent) { + this.#richText = this.#makePopupContent(popupContent); + this.#contentsObj = null; + } + this.#popup?.remove(); + this.#popup = null; + } + resetEdited() { + if (!this.#updates) { + return; + } + ({ + contentsObj: this.#contentsObj, + richText: this.#richText + } = this.#updates); + this.#updates = null; + this.#popup?.remove(); + this.#popup = null; + this.#position = null; + } + #setPosition() { + if (this.#position !== null) { + return; + } + const { + page: { + view + }, + viewport: { + rawDims: { + pageWidth, + pageHeight, + pageX, + pageY + } + } + } = this.#parent; + let useParentRect = !!this.#parentRect; + let rect = useParentRect ? this.#parentRect : this.#rect; + for (const element of this.#elements) { + if (!rect || Util.intersect(element.data.rect, rect) !== null) { + rect = element.data.rect; + useParentRect = true; + break; + } + } + const normalizedRect = Util.normalizeRect([rect[0], view[3] - rect[1] + view[1], rect[2], view[3] - rect[3] + view[1]]); + const HORIZONTAL_SPACE_AFTER_ANNOTATION = 5; + const parentWidth = useParentRect ? rect[2] - rect[0] + HORIZONTAL_SPACE_AFTER_ANNOTATION : 0; + const popupLeft = normalizedRect[0] + parentWidth; + const popupTop = normalizedRect[1]; + this.#position = [100 * (popupLeft - pageX) / pageWidth, 100 * (popupTop - pageY) / pageHeight]; + const { + style + } = this.#container; + style.left = `${this.#position[0]}%`; + style.top = `${this.#position[1]}%`; + } #toggle() { this.#pinned = !this.#pinned; if (this.#pinned) { @@ -13146,6 +13232,7 @@ class PopupElement { this.render(); } if (!this.isVisible) { + this.#setPosition(); this.#container.hidden = false; this.#container.style.zIndex = parseInt(this.#container.style.zIndex) + 1000; } else if (this.#pinned) { @@ -13171,6 +13258,9 @@ class PopupElement { if (!this.#wasVisible) { return; } + if (!this.#popup) { + this.#show(); + } this.#wasVisible = false; this.#container.hidden = false; } @@ -14317,7 +14407,8 @@ class FreeTextEditor extends AnnotationEditor { } const padding = FreeTextEditor._internalPadding * this.parentScale; annotation.updateEdited({ - rect: this.getRect(padding, padding) + rect: this.getRect(padding, padding), + popupContent: this.#content }); return content; } @@ -16828,26 +16919,22 @@ class StampEditor extends AnnotationEditor { const offscreen = new OffscreenCanvas(width, height); const ctx = offscreen.getContext("2d"); ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, width, height); - offscreen.convertToBlob().then(blob => { - const fileReader = new FileReader(); - fileReader.onload = () => { - const url = fileReader.result; - this._uiManager.mlGuess({ - service: "image-to-text", - request: { - imageData: url - } - }).then(response => { - const altText = response?.output || ""; - if (this.parent && altText && !this.hasAltText()) { - this.altTextData = { - altText, - decorative: false - }; - } - }); - }; - fileReader.readAsDataURL(blob); + this._uiManager.mlGuess({ + service: "image-to-text", + request: { + data: ctx.getImageData(0, 0, width, height).data, + width, + height, + channels: 4 + } + }).then(response => { + const altText = response?.output || ""; + if (this.parent && altText && !this.hasAltText()) { + this.altTextData = { + altText, + decorative: false + }; + } }); } const ctx = canvas.getContext("2d"); @@ -17776,8 +17863,8 @@ class DrawLayer { -const pdfjsVersion = "4.3.83"; -const pdfjsBuild = "9ee7c07b8"; +const pdfjsVersion = "4.3.138"; +const pdfjsBuild = "24e12d515"; var __webpack_exports__AbortException = __webpack_exports__.AbortException; var __webpack_exports__AnnotationEditorLayer = __webpack_exports__.AnnotationEditorLayer; diff --git a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs index 3cb46a7b49e6..ce0346b32135 100644 --- a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs @@ -3956,8 +3956,8 @@ function initSandbox(params) { ;// CONCATENATED MODULE: ./src/pdf.scripting.js -const pdfjsVersion = "4.3.83"; -const pdfjsBuild = "9ee7c07b8"; +const pdfjsVersion = "4.3.138"; +const pdfjsBuild = "24e12d515"; globalThis.pdfjsScripting = { initSandbox: initSandbox }; diff --git a/toolkit/components/pdfjs/content/build/pdf.worker.mjs b/toolkit/components/pdfjs/content/build/pdf.worker.mjs index 63814fe448cd..c3f6bcf99c62 100644 --- a/toolkit/components/pdfjs/content/build/pdf.worker.mjs +++ b/toolkit/components/pdfjs/content/build/pdf.worker.mjs @@ -8844,13 +8844,17 @@ class Parser { this.shift(); return imageStream; } - _findStreamLength(startPos, signature) { + #findStreamLength(startPos) { const { stream } = this.lexer; stream.pos = startPos; const SCAN_BLOCK_LENGTH = 2048; - const signatureLength = signature.length; + const signatureLength = "endstream".length; + const END_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64]); + const endLength = END_SIGNATURE.length; + const PARTIAL_SIGNATURE = [new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]), new Uint8Array([0x73, 0x74, 0x65, 0x61, 0x6d]), new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61])]; + const normalLength = signatureLength - endLength; while (stream.pos < stream.end) { const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); const scanLength = scanBytes.length - signatureLength; @@ -8860,12 +8864,34 @@ class Parser { let pos = 0; while (pos < scanLength) { let j = 0; - while (j < signatureLength && scanBytes[pos + j] === signature[j]) { + while (j < endLength && scanBytes[pos + j] === END_SIGNATURE[j]) { j++; } - if (j >= signatureLength) { - stream.pos += pos; - return stream.pos - startPos; + if (j >= endLength) { + let found = false; + for (const part of PARTIAL_SIGNATURE) { + const partLen = part.length; + let k = 0; + while (k < partLen && scanBytes[pos + j + k] === part[k]) { + k++; + } + if (k >= normalLength) { + found = true; + break; + } + if (k >= partLen) { + const lastByte = scanBytes[pos + j + k]; + if (isWhiteSpace(lastByte)) { + info(`Found "${bytesToString([...END_SIGNATURE, ...part])}" when ` + "searching for endstream command."); + found = true; + } + break; + } + } + if (found) { + stream.pos += pos; + return stream.pos - startPos; + } } pos++; } @@ -8888,29 +8914,10 @@ class Parser { if (this.tryShift() && isCmd(this.buf2, "endstream")) { this.shift(); } else { - const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]); - let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE); - if (actualLength < 0) { - const MAX_TRUNCATION = 1; - for (let i = 1; i <= MAX_TRUNCATION; i++) { - const end = ENDSTREAM_SIGNATURE.length - i; - const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end); - const maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE); - if (maybeLength >= 0) { - const lastByte = stream.peekBytes(end + 1)[end]; - if (!isWhiteSpace(lastByte)) { - break; - } - info(`Found "${bytesToString(TRUNCATED_SIGNATURE)}" when ` + "searching for endstream command."); - actualLength = maybeLength; - break; - } - } - if (actualLength < 0) { - throw new FormatError("Missing endstream command."); - } + length = this.#findStreamLength(startPos); + if (length < 0) { + throw new FormatError("Missing endstream command."); } - length = actualLength; lexer.nextChar(); this.shift(); this.shift(); @@ -29672,7 +29679,7 @@ class PartialEvaluator { this.globalImageCache = globalImageCache; this.systemFontCache = systemFontCache; this.options = options || DefaultPartialEvaluatorOptions; - this.parsingType3Font = false; + this.type3FontRefs = null; this._regionalImageCache = new RegionalImageCache(); this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this); ImageResizer.setMaxArea(this.options.canvasMaxAreaInBytes); @@ -29684,6 +29691,9 @@ class PartialEvaluator { }); return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory); } + get parsingType3Font() { + return !!this.type3FontRefs; + } clone(newOptions = null) { const newEvaluator = Object.create(this); newEvaluator.options = Object.assign(Object.create(null), this.options, newOptions); @@ -30372,13 +30382,17 @@ class PartialEvaluator { } } if (fontRef) { - if (this.parsingType3Font && this.type3FontRefs.has(fontRef)) { + if (this.type3FontRefs?.has(fontRef)) { return errorFont(); } if (this.fontCache.has(fontRef)) { return this.fontCache.get(fontRef); } - font = this.xref.fetchIfRef(fontRef); + try { + font = this.xref.fetchIfRef(fontRef); + } catch (ex) { + warn(`loadFont - lookup failed: "${ex}".`); + } } if (!(font instanceof Dict)) { if (!this.options.ignoreErrors && !this.parsingType3Font) { @@ -32803,7 +32817,6 @@ class TranslatedFont { const type3Evaluator = evaluator.clone({ ignoreErrors: false }); - type3Evaluator.parsingType3Font = true; const type3FontRefs = new RefSet(evaluator.type3FontRefs); if (this.dict.objId && !type3FontRefs.has(this.dict.objId)) { type3FontRefs.put(this.dict.objId); @@ -53665,52 +53678,49 @@ class Page { systemFontCache: this.systemFontCache, options: this.evaluatorOptions }); - const newAnnotationsByPage = !this.xfaFactory ? getNewAnnotationsMap(annotationStorage) : null; - let deletedAnnotations = null; + const newAnnotsByPage = !this.xfaFactory ? getNewAnnotationsMap(annotationStorage) : null; + const newAnnots = newAnnotsByPage?.get(this.pageIndex); let newAnnotationsPromise = Promise.resolve(null); - if (newAnnotationsByPage) { - const newAnnotations = newAnnotationsByPage.get(this.pageIndex); - if (newAnnotations) { - const annotationGlobalsPromise = this.pdfManager.ensureDoc("annotationGlobals"); - let imagePromises; - const missingBitmaps = new Set(); - for (const { - bitmapId, - bitmap - } of newAnnotations) { - if (bitmapId && !bitmap && !missingBitmaps.has(bitmapId)) { - missingBitmaps.add(bitmapId); - } + let deletedAnnotations = null; + if (newAnnots) { + const annotationGlobalsPromise = this.pdfManager.ensureDoc("annotationGlobals"); + let imagePromises; + const missingBitmaps = new Set(); + for (const { + bitmapId, + bitmap + } of newAnnots) { + if (bitmapId && !bitmap && !missingBitmaps.has(bitmapId)) { + missingBitmaps.add(bitmapId); } - const { - isOffscreenCanvasSupported - } = this.evaluatorOptions; - if (missingBitmaps.size > 0) { - const annotationWithBitmaps = newAnnotations.slice(); - for (const [key, annotation] of annotationStorage) { - if (!key.startsWith(AnnotationEditorPrefix)) { - continue; - } - if (annotation.bitmap && missingBitmaps.has(annotation.bitmapId)) { - annotationWithBitmaps.push(annotation); - } - } - imagePromises = AnnotationFactory.generateImages(annotationWithBitmaps, this.xref, isOffscreenCanvasSupported); - } else { - imagePromises = AnnotationFactory.generateImages(newAnnotations, this.xref, isOffscreenCanvasSupported); - } - deletedAnnotations = new RefSet(); - this.#replaceIdByRef(newAnnotations, deletedAnnotations, null); - newAnnotationsPromise = annotationGlobalsPromise.then(annotationGlobals => { - if (!annotationGlobals) { - return null; - } - return AnnotationFactory.printNewAnnotations(annotationGlobals, partialEvaluator, task, newAnnotations, imagePromises); - }); } + const { + isOffscreenCanvasSupported + } = this.evaluatorOptions; + if (missingBitmaps.size > 0) { + const annotationWithBitmaps = newAnnots.slice(); + for (const [key, annotation] of annotationStorage) { + if (!key.startsWith(AnnotationEditorPrefix)) { + continue; + } + if (annotation.bitmap && missingBitmaps.has(annotation.bitmapId)) { + annotationWithBitmaps.push(annotation); + } + } + imagePromises = AnnotationFactory.generateImages(annotationWithBitmaps, this.xref, isOffscreenCanvasSupported); + } else { + imagePromises = AnnotationFactory.generateImages(newAnnots, this.xref, isOffscreenCanvasSupported); + } + deletedAnnotations = new RefSet(); + this.#replaceIdByRef(newAnnots, deletedAnnotations, null); + newAnnotationsPromise = annotationGlobalsPromise.then(annotationGlobals => { + if (!annotationGlobals) { + return null; + } + return AnnotationFactory.printNewAnnotations(annotationGlobals, partialEvaluator, task, newAnnots, imagePromises); + }); } - const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); - const pageListPromise = dataPromises.then(([contentStream]) => { + const pageListPromise = Promise.all([contentStreamPromise, resourcesPromise]).then(([contentStream]) => { const opList = new OperatorList(intent, sink); handler.send("StartRenderPage", { transparency: partialEvaluator.hasBlendModes(this.resources, this.nonBlendModesSet), @@ -54497,7 +54507,7 @@ class PDFDocument { if (type instanceof Ref) { type = await xref.fetchAsync(type); } - if (isName(type, "Page") || !obj.has("Type") && !obj.has("Kids")) { + if (isName(type, "Page") || !obj.has("Type") && !obj.has("Kids") && obj.has("Contents")) { if (!catalog.pageKidsCountCache.has(ref)) { catalog.pageKidsCountCache.put(ref, 1); } @@ -55475,7 +55485,7 @@ class WorkerMessageHandler { docId, apiVersion } = docParams; - const workerVersion = "4.3.83"; + const workerVersion = "4.3.138"; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); } @@ -56038,8 +56048,8 @@ if (typeof window === "undefined" && !isNodeJS && typeof self !== "undefined" && ;// CONCATENATED MODULE: ./src/pdf.worker.js -const pdfjsVersion = "4.3.83"; -const pdfjsBuild = "9ee7c07b8"; +const pdfjsVersion = "4.3.138"; +const pdfjsBuild = "24e12d515"; var __webpack_exports__WorkerMessageHandler = __webpack_exports__.WorkerMessageHandler; export { __webpack_exports__WorkerMessageHandler as WorkerMessageHandler }; diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.css b/toolkit/components/pdfjs/content/web/viewer-geckoview.css index 8f4872a7ba61..02dbf0797944 100644 --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.css +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.css @@ -13,6 +13,216 @@ * limitations under the License. */ +.dialog{ + --dialog-bg-color:white; + --dialog-border-color:white; + --dialog-shadow:0 2px 14px 0 rgb(58 57 68 / 0.2); + --text-primary-color:#15141a; + --text-secondary-color:#5b5b66; + --hover-filter:brightness(0.9); + --focus-ring-color:#0060df; + --focus-ring-outline:2px solid var(--focus-ring-color); + + --textarea-border-color:#8f8f9d; + --textarea-bg-color:white; + --textarea-fg-color:var(--text-secondary-color); + + --radio-bg-color:#f0f0f4; + --radio-checked-bg-color:#fbfbfe; + --radio-border-color:#8f8f9d; + --radio-checked-border-color:#0060df; + + --button-secondary-bg-color:#f0f0f4; + --button-secondary-fg-color:var(--text-primary-color); + --button-secondary-border-color:var(--button-secondary-bg-color); + --button-secondary-hover-bg-color:var(--button-secondary-bg-color); + --button-secondary-hover-fg-color:var(--button-secondary-fg-color); + --button-secondary-hover-border-color:var(--button-secondary-hover-bg-color); + + --button-primary-bg-color:#0060df; + --button-primary-fg-color:#fbfbfe; + --button-primary-hover-bg-color:var(--button-primary-bg-color); + --button-primary-hover-fg-color:var(--button-primary-fg-color); + --button-primary-hover-border-color:var(--button-primary-hover-bg-color); + + @media (prefers-color-scheme: dark){ + --dialog-bg-color:#1c1b22; + --dialog-border-color:#1c1b22; + --dialog-shadow:0 2px 14px 0 #15141a; + --text-primary-color:#fbfbfe; + --text-secondary-color:#cfcfd8; + --focus-ring-color:#0df; + --hover-filter:brightness(1.4); + + --textarea-bg-color:#42414d; + + --radio-bg-color:#2b2a33; + --radio-checked-bg-color:#15141a; + --radio-checked-border-color:#0df; + + --button-secondary-bg-color:#2b2a33; + --button-primary-bg-color:#0df; + --button-primary-fg-color:#15141a; + } + + @media screen and (forced-colors: active){ + --dialog-bg-color:Canvas; + --dialog-border-color:CanvasText; + --dialog-shadow:none; + --text-primary-color:CanvasText; + --text-secondary-color:CanvasText; + --hover-filter:none; + --focus-ring-color:ButtonBorder; + + --textarea-border-color:ButtonBorder; + --textarea-bg-color:Field; + --textarea-fg-color:ButtonText; + + --radio-bg-color:ButtonFace; + --radio-checked-bg-color:ButtonFace; + --radio-border-color:ButtonText; + --radio-checked-border-color:ButtonText; + + --button-secondary-bg-color:ButtonFace; + --button-secondary-fg-color:ButtonText; + --button-secondary-border-color:ButtonText; + --button-secondary-hover-bg-color:AccentColor; + --button-secondary-hover-fg-color:AccentColorText; + + --button-primary-bg-color:ButtonText; + --button-primary-fg-color:ButtonFace; + --button-primary-hover-bg-color:AccentColor; + --button-primary-hover-fg-color:AccentColorText; + } + + font:message-box; + font-size:13px; + font-weight:400; + line-height:150%; + border-radius:4px; + padding:12px 16px; + border:1px solid var(--dialog-border-color); + background:var(--dialog-bg-color); + color:var(--text-primary-color); + box-shadow:var(--dialog-shadow); + + .mainContainer{ + *:focus-visible{ + outline:var(--focus-ring-outline); + outline-offset:2px; + } + + .radio{ + display:flex; + flex-direction:column; + align-items:flex-start; + gap:4px; + + > .radioButton{ + display:flex; + gap:8px; + align-self:stretch; + align-items:center; + + input{ + appearance:none; + box-sizing:border-box; + width:16px; + height:16px; + border-radius:50%; + background-color:var(--radio-bg-color); + border:1px solid var(--radio-border-color); + + &:hover{ + filter:var(--hover-filter); + } + + &:checked{ + background-color:var(--radio-checked-bg-color); + border:4px solid var(--radio-checked-border-color); + } + } + } + + > .radioLabel{ + display:flex; + padding-inline-start:24px; + align-items:flex-start; + gap:10px; + align-self:stretch; + + > span{ + flex:1 0 0; + font-size:11px; + color:var(--text-secondary-color); + } + } + } + + button{ + border-radius:4px; + border:1px solid; + font:menu; + font-weight:600; + padding:4px 16px; + width:auto; + height:32px; + + &:hover{ + cursor:pointer; + filter:var(--hover-filter); + } + + &.secondaryButton{ + color:var(--button-secondary-fg-color); + background-color:var(--button-secondary-bg-color); + border-color:var(--button-secondary-border-color); + + &:hover{ + color:var(--button-secondary-hover-fg-color); + background-color:var(--button-secondary-hover-bg-color); + border-color:var(--button-secondary-hover-border-color); + } + } + + &.primaryButton{ + color:var(--button-primary-hover-fg-color); + background-color:var(--button-primary-hover-bg-color); + border-color:var(--button-primary-hover-border-color); + opacity:1; + + &:hover{ + color:var(--button-primary-hover-fg-color); + background-color:var(--button-primary-hover-bg-color); + border-color:var(--button-primary-hover-border-color); + } + } + } + + textarea{ + font:inherit; + padding:8px; + resize:none; + margin:0; + box-sizing:border-box; + border-radius:4px; + border:1px solid var(--textarea-border-color); + background:var(--textarea-bg-color); + color:var(--textarea-fg-color); + + &:focus{ + outline-offset:0; + border-color:transparent; + } + + &:disabled{ + pointer-events:none; + opacity:0.4; + } + } + } +} + .textLayer{ position:absolute; text-align:initial; diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs index a0ae4e45216d..9e7b8318613b 100644 --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs @@ -4885,17 +4885,18 @@ class TextHighlighter { class TextLayerBuilder { #enablePermissions = false; #onAppend = null; - #textContentSource = null; + #renderingDone = false; #textLayer = null; static #textLayers = new Map(); static #selectionChangeAbortController = null; constructor({ + pdfPage, highlighter = null, accessibilityManager = null, enablePermissions = false, onAppend = null }) { - this.renderingDone = false; + this.pdfPage = pdfPage; this.highlighter = highlighter; this.accessibilityManager = accessibilityManager; this.#enablePermissions = enablePermissions === true; @@ -4905,17 +4906,14 @@ class TextLayerBuilder { this.div.className = "textLayer"; } #finishRendering() { - this.renderingDone = true; + this.#renderingDone = true; const endOfContent = document.createElement("div"); endOfContent.className = "endOfContent"; this.div.append(endOfContent); this.#bindMouse(endOfContent); } - async render(viewport) { - if (!this.#textContentSource) { - throw new Error('No "textContentSource" parameter specified.'); - } - if (this.renderingDone && this.#textLayer) { + async render(viewport, textContentParams = null) { + if (this.#renderingDone && this.#textLayer) { this.#textLayer.update({ viewport, onBefore: this.hide.bind(this) @@ -4925,7 +4923,10 @@ class TextLayerBuilder { } this.cancel(); this.#textLayer = new TextLayer({ - textContentSource: this.#textContentSource, + textContentSource: this.pdfPage.streamTextContent(textContentParams || { + includeMarkedContent: true, + disableNormalization: true + }), container: this.div, viewport }); @@ -4942,13 +4943,13 @@ class TextLayerBuilder { this.accessibilityManager?.enable(); } hide() { - if (!this.div.hidden && this.renderingDone) { + if (!this.div.hidden && this.#renderingDone) { this.highlighter?.disable(); this.div.hidden = true; } } show() { - if (this.div.hidden && this.renderingDone) { + if (this.div.hidden && this.#renderingDone) { this.div.hidden = false; this.highlighter?.enable(); } @@ -4960,10 +4961,6 @@ class TextLayerBuilder { this.accessibilityManager?.disable(); TextLayerBuilder.#removeGlobalSelectionListener(this.div); } - setTextContentSource(source) { - this.cancel(); - this.#textContentSource = source; - } #bindMouse(end) { const { div @@ -4990,34 +4987,37 @@ class TextLayerBuilder { } } static #enableGlobalSelectionListener() { - if (TextLayerBuilder.#selectionChangeAbortController) { + if (this.#selectionChangeAbortController) { return; } - TextLayerBuilder.#selectionChangeAbortController = new AbortController(); + this.#selectionChangeAbortController = new AbortController(); + const { + signal + } = this.#selectionChangeAbortController; const reset = (end, textLayer) => { end.classList.remove("active"); }; document.addEventListener("pointerup", () => { - TextLayerBuilder.#textLayers.forEach(reset); + this.#textLayers.forEach(reset); }, { - signal: TextLayerBuilder.#selectionChangeAbortController.signal + signal }); document.addEventListener("selectionchange", () => { const selection = document.getSelection(); if (selection.rangeCount === 0) { - TextLayerBuilder.#textLayers.forEach(reset); + this.#textLayers.forEach(reset); return; } const activeTextLayers = new Set(); for (let i = 0; i < selection.rangeCount; i++) { const range = selection.getRangeAt(i); - for (const textLayerDiv of TextLayerBuilder.#textLayers.keys()) { + for (const textLayerDiv of this.#textLayers.keys()) { if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) { activeTextLayers.add(textLayerDiv); } } } - for (const [textLayerDiv, endDiv] of TextLayerBuilder.#textLayers) { + for (const [textLayerDiv, endDiv] of this.#textLayers) { if (activeTextLayers.has(textLayerDiv)) { endDiv.classList.add("active"); } else { @@ -5025,7 +5025,7 @@ class TextLayerBuilder { } } }, { - signal: TextLayerBuilder.#selectionChangeAbortController.signal + signal }); } } @@ -5185,6 +5185,13 @@ class PDFPageView { findController: this.#layerProperties.findController })); } + #dispatchLayerRendered(name, error) { + this.eventBus.dispatch(name, { + source: this, + pageNumber: this.id, + error + }); + } async #renderAnnotationLayer() { let error = null; try { @@ -5193,11 +5200,7 @@ class PDFPageView { console.error(`#renderAnnotationLayer: "${ex}".`); error = ex; } finally { - this.eventBus.dispatch("annotationlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("annotationlayerrendered", error); } } async #renderAnnotationEditorLayer() { @@ -5208,11 +5211,7 @@ class PDFPageView { console.error(`#renderAnnotationEditorLayer: "${ex}".`); error = ex; } finally { - this.eventBus.dispatch("annotationeditorlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("annotationeditorlayerrendered", error); } } async #renderDrawLayer() { @@ -5238,32 +5237,16 @@ class PDFPageView { this.#addLayer(this.xfaLayer.div, "xfaLayer"); this.l10n.resume(); } - this.eventBus.dispatch("xfalayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("xfalayerrendered", error); } } async #renderTextLayer() { - const { - pdfPage, - textLayer, - viewport - } = this; - if (!textLayer) { + if (!this.textLayer) { return; } let error = null; try { - if (!textLayer.renderingDone) { - const readableStream = pdfPage.streamTextContent({ - includeMarkedContent: true, - disableNormalization: true - }); - textLayer.setTextContentSource(readableStream); - } - await textLayer.render(viewport); + await this.textLayer.render(this.viewport); } catch (ex) { if (ex instanceof AbortException) { return; @@ -5271,11 +5254,7 @@ class PDFPageView { console.error(`#renderTextLayer: "${ex}".`); error = ex; } - this.eventBus.dispatch("textlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("textlayerrendered", error); this.#renderStructTreeLayer(); } async #renderStructTreeLayer() { @@ -5613,6 +5592,7 @@ class PDFPageView { if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) { this._accessibilityManager ||= new TextAccessibilityManager(); this.textLayer = new TextLayerBuilder({ + pdfPage, highlighter: this._textHighlighter, accessibilityManager: this._accessibilityManager, enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS, @@ -5715,7 +5695,7 @@ class PDFPageView { annotationCanvasMap: this._annotationCanvasMap, pageColors }; - const renderTask = this.renderTask = this.pdfPage.render(renderContext); + const renderTask = this.renderTask = pdfPage.render(renderContext); renderTask.onContinue = renderContinueCallback; const resultPromise = renderTask.promise.then(async () => { showCanvas?.(true); @@ -5883,7 +5863,7 @@ class PDFViewer { #scaleTimeoutId = null; #textLayerMode = TextLayerMode.ENABLE; constructor(options) { - const viewerVersion = "4.3.83"; + const viewerVersion = "4.3.138"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } @@ -6529,7 +6509,8 @@ class PDFViewer { #setScaleUpdatePages(newScale, newValue, { noScroll = false, preset = false, - drawingDelay = -1 + drawingDelay = -1, + origin = null }) { this._currentScaleValue = newValue.toString(); if (this.#isSameScale(newScale)) { @@ -6554,6 +6535,7 @@ class PDFViewer { this.refresh(); }, drawingDelay); } + const previousScale = this._currentScale; this._currentScale = newScale; if (!noScroll) { let page = this._currentPageNumber, @@ -6569,6 +6551,12 @@ class PDFViewer { destArray: dest, allowNegativeOffset: true }); + if (Array.isArray(origin)) { + const scaleDiff = newScale / previousScale - 1; + const [top, left] = this.containerTopLeft; + this.container.scrollLeft += (origin[0] - left) * scaleDiff; + this.container.scrollTop += (origin[1] - top) * scaleDiff; + } } this.eventBus.dispatch("scalechanging", { source: this, @@ -7141,48 +7129,46 @@ class PDFViewer { this.currentPageNumber = Math.max(currentPageNumber - advance, 1); return true; } - increaseScale({ + updateScale({ drawingDelay, - scaleFactor, - steps - } = {}) { + scaleFactor = null, + steps = null, + origin + }) { + if (steps === null && scaleFactor === null) { + throw new Error("Invalid updateScale options: either `steps` or `scaleFactor` must be provided."); + } if (!this.pdfDocument) { return; } let newScale = this._currentScale; - if (scaleFactor > 1) { + if (scaleFactor > 0 && scaleFactor !== 1) { newScale = Math.round(newScale * scaleFactor * 100) / 100; - } else { - steps ??= 1; + } else if (steps) { + const delta = steps > 0 ? DEFAULT_SCALE_DELTA : 1 / DEFAULT_SCALE_DELTA; + const round = steps > 0 ? Math.ceil : Math.floor; + steps = Math.abs(steps); do { - newScale = Math.ceil((newScale * DEFAULT_SCALE_DELTA).toFixed(2) * 10) / 10; - } while (--steps > 0 && newScale < MAX_SCALE); + newScale = round((newScale * delta).toFixed(2) * 10) / 10; + } while (--steps > 0); } - this.#setScale(Math.min(MAX_SCALE, newScale), { + newScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale)); + this.#setScale(newScale, { noScroll: false, - drawingDelay + drawingDelay, + origin }); } - decreaseScale({ - drawingDelay, - scaleFactor, - steps - } = {}) { - if (!this.pdfDocument) { - return; - } - let newScale = this._currentScale; - if (scaleFactor > 0 && scaleFactor < 1) { - newScale = Math.round(newScale * scaleFactor * 100) / 100; - } else { - steps ??= 1; - do { - newScale = Math.floor((newScale / DEFAULT_SCALE_DELTA).toFixed(2) * 10) / 10; - } while (--steps > 0 && newScale > MIN_SCALE); - } - this.#setScale(Math.max(MIN_SCALE, newScale), { - noScroll: false, - drawingDelay + increaseScale(options = {}) { + this.updateScale({ + ...options, + steps: options.steps ?? 1 + }); + } + decreaseScale(options = {}) { + this.updateScale({ + ...options, + steps: -(options.steps ?? 1) }); } #updateContainerHeightCss(height = this.container.clientHeight) { @@ -7795,25 +7781,22 @@ const PDFViewerApplication = { get initializedPromise() { return this._initializedCapability.promise; }, - zoomIn(steps, scaleFactor) { + updateZoom(steps, scaleFactor, origin) { if (this.pdfViewer.isInPresentationMode) { return; } - this.pdfViewer.increaseScale({ + this.pdfViewer.updateScale({ drawingDelay: AppOptions.get("defaultZoomDelay"), steps, - scaleFactor + scaleFactor, + origin }); }, - zoomOut(steps, scaleFactor) { - if (this.pdfViewer.isInPresentationMode) { - return; - } - this.pdfViewer.decreaseScale({ - drawingDelay: AppOptions.get("defaultZoomDelay"), - steps, - scaleFactor - }); + zoomIn() { + this.updateZoom(1); + }, + zoomOut() { + this.updateZoom(-1); }, zoomReset() { if (this.pdfViewer.isInPresentationMode) { @@ -7951,6 +7934,7 @@ const PDFViewerApplication = { this._contentDispositionFilename = args.filename; } AppOptions.set("docBaseUrl", this.baseUrl); + args.useSystemFonts = false; const apiParams = AppOptions.getAll(OptionKind.API); const loadingTask = getDocument({ ...apiParams, @@ -8787,17 +8771,6 @@ const PDFViewerApplication = { this[prop] = factor / newFactor; return newFactor; }, - _centerAtPos(previousScale, x, y) { - const { - pdfViewer - } = this; - const scaleDiff = pdfViewer.currentScale / previousScale - 1; - if (scaleDiff !== 0) { - const [top, left] = pdfViewer.containerTopLeft; - pdfViewer.container.scrollLeft += (x - left) * scaleDiff; - pdfViewer.container.scrollTop += (y - top) * scaleDiff; - } - }, _unblockDocumentLoadEvent() { document.blockUnblockOnload?.(false); this._unblockDocumentLoadEvent = () => {}; @@ -9102,21 +9075,15 @@ function webViewerWheel(evt) { let scaleFactor = Math.exp(-evt.deltaY / 100); const isBuiltInMac = FeatureTest.platform.isMac; const isPinchToZoom = evt.ctrlKey && !PDFViewerApplication._isCtrlKeyDown && deltaMode === WheelEvent.DOM_DELTA_PIXEL && evt.deltaX === 0 && (Math.abs(scaleFactor - 1) < 0.05 || isBuiltInMac) && evt.deltaZ === 0; + const origin = [evt.clientX, evt.clientY]; if (isPinchToZoom || evt.ctrlKey && supportsMouseWheelZoomCtrlKey || evt.metaKey && supportsMouseWheelZoomMetaKey) { evt.preventDefault(); if (PDFViewerApplication._isScrolling || zoomDisabledTimeout || document.visibilityState === "hidden" || PDFViewerApplication.overlayManager.active) { return; } - const previousScale = pdfViewer.currentScale; if (isPinchToZoom && supportsPinchToZoom) { - scaleFactor = PDFViewerApplication._accumulateFactor(previousScale, scaleFactor, "_wheelUnusedFactor"); - if (scaleFactor < 1) { - PDFViewerApplication.zoomOut(null, scaleFactor); - } else if (scaleFactor > 1) { - PDFViewerApplication.zoomIn(null, scaleFactor); - } else { - return; - } + scaleFactor = PDFViewerApplication._accumulateFactor(pdfViewer.currentScale, scaleFactor, "_wheelUnusedFactor"); + PDFViewerApplication.updateZoom(null, scaleFactor, origin); } else { const delta = normalizeWheelEventDirection(evt); let ticks = 0; @@ -9130,15 +9097,8 @@ function webViewerWheel(evt) { const PIXELS_PER_LINE_SCALE = 30; ticks = PDFViewerApplication._accumulateTicks(delta / PIXELS_PER_LINE_SCALE, "_wheelUnusedTicks"); } - if (ticks < 0) { - PDFViewerApplication.zoomOut(-ticks); - } else if (ticks > 0) { - PDFViewerApplication.zoomIn(ticks); - } else { - return; - } + PDFViewerApplication.updateZoom(ticks, null, origin); } - PDFViewerApplication._centerAtPos(previousScale, evt.clientX, evt.clientY); } } function webViewerTouchStart(evt) { @@ -9224,30 +9184,17 @@ function webViewerTouchMove(evt) { } } evt.preventDefault(); + const origin = [(page0X + page1X) / 2, (page0Y + page1Y) / 2]; const distance = Math.hypot(page0X - page1X, page0Y - page1Y) || 1; const pDistance = Math.hypot(pTouch0X - pTouch1X, pTouch0Y - pTouch1Y) || 1; - const previousScale = pdfViewer.currentScale; if (supportsPinchToZoom) { - const newScaleFactor = PDFViewerApplication._accumulateFactor(previousScale, distance / pDistance, "_touchUnusedFactor"); - if (newScaleFactor < 1) { - PDFViewerApplication.zoomOut(null, newScaleFactor); - } else if (newScaleFactor > 1) { - PDFViewerApplication.zoomIn(null, newScaleFactor); - } else { - return; - } + const newScaleFactor = PDFViewerApplication._accumulateFactor(pdfViewer.currentScale, distance / pDistance, "_touchUnusedFactor"); + PDFViewerApplication.updateZoom(null, newScaleFactor, origin); } else { const PIXELS_PER_LINE_SCALE = 30; const ticks = PDFViewerApplication._accumulateTicks((distance - pDistance) / PIXELS_PER_LINE_SCALE, "_touchUnusedTicks"); - if (ticks < 0) { - PDFViewerApplication.zoomOut(-ticks); - } else if (ticks > 0) { - PDFViewerApplication.zoomIn(ticks); - } else { - return; - } + PDFViewerApplication.updateZoom(ticks, null, origin); } - PDFViewerApplication._centerAtPos(previousScale, (page0X + page1X) / 2, (page0Y + page1Y) / 2); } function webViewerTouchEnd(evt) { if (!PDFViewerApplication._touchInfo) { @@ -9547,8 +9494,8 @@ function webViewerReportTelemetry({ -const pdfjsVersion = "4.3.83"; -const pdfjsBuild = "9ee7c07b8"; +const pdfjsVersion = "4.3.138"; +const pdfjsBuild = "24e12d515"; const AppConstants = null; window.PDFViewerApplication = PDFViewerApplication; window.PDFViewerApplicationConstants = AppConstants; diff --git a/toolkit/components/pdfjs/content/web/viewer.css b/toolkit/components/pdfjs/content/web/viewer.css index 48d1626ad782..0764fdec120c 100644 --- a/toolkit/components/pdfjs/content/web/viewer.css +++ b/toolkit/components/pdfjs/content/web/viewer.css @@ -13,6 +13,216 @@ * limitations under the License. */ +.dialog{ + --dialog-bg-color:white; + --dialog-border-color:white; + --dialog-shadow:0 2px 14px 0 rgb(58 57 68 / 0.2); + --text-primary-color:#15141a; + --text-secondary-color:#5b5b66; + --hover-filter:brightness(0.9); + --focus-ring-color:#0060df; + --focus-ring-outline:2px solid var(--focus-ring-color); + + --textarea-border-color:#8f8f9d; + --textarea-bg-color:white; + --textarea-fg-color:var(--text-secondary-color); + + --radio-bg-color:#f0f0f4; + --radio-checked-bg-color:#fbfbfe; + --radio-border-color:#8f8f9d; + --radio-checked-border-color:#0060df; + + --button-secondary-bg-color:#f0f0f4; + --button-secondary-fg-color:var(--text-primary-color); + --button-secondary-border-color:var(--button-secondary-bg-color); + --button-secondary-hover-bg-color:var(--button-secondary-bg-color); + --button-secondary-hover-fg-color:var(--button-secondary-fg-color); + --button-secondary-hover-border-color:var(--button-secondary-hover-bg-color); + + --button-primary-bg-color:#0060df; + --button-primary-fg-color:#fbfbfe; + --button-primary-hover-bg-color:var(--button-primary-bg-color); + --button-primary-hover-fg-color:var(--button-primary-fg-color); + --button-primary-hover-border-color:var(--button-primary-hover-bg-color); + + @media (prefers-color-scheme: dark){ + --dialog-bg-color:#1c1b22; + --dialog-border-color:#1c1b22; + --dialog-shadow:0 2px 14px 0 #15141a; + --text-primary-color:#fbfbfe; + --text-secondary-color:#cfcfd8; + --focus-ring-color:#0df; + --hover-filter:brightness(1.4); + + --textarea-bg-color:#42414d; + + --radio-bg-color:#2b2a33; + --radio-checked-bg-color:#15141a; + --radio-checked-border-color:#0df; + + --button-secondary-bg-color:#2b2a33; + --button-primary-bg-color:#0df; + --button-primary-fg-color:#15141a; + } + + @media screen and (forced-colors: active){ + --dialog-bg-color:Canvas; + --dialog-border-color:CanvasText; + --dialog-shadow:none; + --text-primary-color:CanvasText; + --text-secondary-color:CanvasText; + --hover-filter:none; + --focus-ring-color:ButtonBorder; + + --textarea-border-color:ButtonBorder; + --textarea-bg-color:Field; + --textarea-fg-color:ButtonText; + + --radio-bg-color:ButtonFace; + --radio-checked-bg-color:ButtonFace; + --radio-border-color:ButtonText; + --radio-checked-border-color:ButtonText; + + --button-secondary-bg-color:ButtonFace; + --button-secondary-fg-color:ButtonText; + --button-secondary-border-color:ButtonText; + --button-secondary-hover-bg-color:AccentColor; + --button-secondary-hover-fg-color:AccentColorText; + + --button-primary-bg-color:ButtonText; + --button-primary-fg-color:ButtonFace; + --button-primary-hover-bg-color:AccentColor; + --button-primary-hover-fg-color:AccentColorText; + } + + font:message-box; + font-size:13px; + font-weight:400; + line-height:150%; + border-radius:4px; + padding:12px 16px; + border:1px solid var(--dialog-border-color); + background:var(--dialog-bg-color); + color:var(--text-primary-color); + box-shadow:var(--dialog-shadow); + + .mainContainer{ + *:focus-visible{ + outline:var(--focus-ring-outline); + outline-offset:2px; + } + + .radio{ + display:flex; + flex-direction:column; + align-items:flex-start; + gap:4px; + + > .radioButton{ + display:flex; + gap:8px; + align-self:stretch; + align-items:center; + + input{ + appearance:none; + box-sizing:border-box; + width:16px; + height:16px; + border-radius:50%; + background-color:var(--radio-bg-color); + border:1px solid var(--radio-border-color); + + &:hover{ + filter:var(--hover-filter); + } + + &:checked{ + background-color:var(--radio-checked-bg-color); + border:4px solid var(--radio-checked-border-color); + } + } + } + + > .radioLabel{ + display:flex; + padding-inline-start:24px; + align-items:flex-start; + gap:10px; + align-self:stretch; + + > span{ + flex:1 0 0; + font-size:11px; + color:var(--text-secondary-color); + } + } + } + + button{ + border-radius:4px; + border:1px solid; + font:menu; + font-weight:600; + padding:4px 16px; + width:auto; + height:32px; + + &:hover{ + cursor:pointer; + filter:var(--hover-filter); + } + + &.secondaryButton{ + color:var(--button-secondary-fg-color); + background-color:var(--button-secondary-bg-color); + border-color:var(--button-secondary-border-color); + + &:hover{ + color:var(--button-secondary-hover-fg-color); + background-color:var(--button-secondary-hover-bg-color); + border-color:var(--button-secondary-hover-border-color); + } + } + + &.primaryButton{ + color:var(--button-primary-hover-fg-color); + background-color:var(--button-primary-hover-bg-color); + border-color:var(--button-primary-hover-border-color); + opacity:1; + + &:hover{ + color:var(--button-primary-hover-fg-color); + background-color:var(--button-primary-hover-bg-color); + border-color:var(--button-primary-hover-border-color); + } + } + } + + textarea{ + font:inherit; + padding:8px; + resize:none; + margin:0; + box-sizing:border-box; + border-radius:4px; + border:1px solid var(--textarea-border-color); + background:var(--textarea-bg-color); + color:var(--textarea-fg-color); + + &:focus{ + outline-offset:0; + border-color:transparent; + } + + &:disabled{ + pointer-events:none; + opacity:0.4; + } + } + } +} + .textLayer{ position:absolute; text-align:initial; @@ -1726,103 +1936,10 @@ } } -#altTextDialog{ - --dialog-bg-color:white; - --dialog-border-color:white; - --dialog-shadow:0 2px 14px 0 rgb(58 57 68 / 0.2); - --text-primary-color:#15141a; - --text-secondary-color:#5b5b66; - --hover-filter:brightness(0.9); - --focus-ring-color:#0060df; - --focus-ring-outline:2px solid var(--focus-ring-color); - - --textarea-border-color:#8f8f9d; - --textarea-bg-color:white; - --textarea-fg-color:var(--text-secondary-color); - - --radio-bg-color:#f0f0f4; - --radio-checked-bg-color:#fbfbfe; - --radio-border-color:#8f8f9d; - --radio-checked-border-color:#0060df; - - --button-cancel-bg-color:#f0f0f4; - --button-cancel-fg-color:var(--text-primary-color); - --button-cancel-border-color:var(--button-cancel-bg-color); - --button-cancel-hover-bg-color:var(--button-cancel-bg-color); - --button-cancel-hover-fg-color:var(--button-cancel-fg-color); - --button-cancel-hover-border-color:var(--button-cancel-hover-bg-color); - - --button-save-bg-color:#0060df; - --button-save-fg-color:#fbfbfe; - --button-save-hover-bg-color:var(--button-save-bg-color); - --button-save-hover-fg-color:var(--button-save-fg-color); - --button-save-hover-border-color:var(--button-save-hover-bg-color); - - @media (prefers-color-scheme: dark){ - --dialog-bg-color:#1c1b22; - --dialog-border-color:#1c1b22; - --dialog-shadow:0 2px 14px 0 #15141a; - --text-primary-color:#fbfbfe; - --text-secondary-color:#cfcfd8; - --focus-ring-color:#0df; - --hover-filter:brightness(1.4); - - --textarea-bg-color:#42414d; - - --radio-bg-color:#2b2a33; - --radio-checked-bg-color:#15141a; - --radio-checked-border-color:#0df; - - --button-cancel-bg-color:#2b2a33; - --button-save-bg-color:#0df; - --button-save-fg-color:#15141a; - } - - @media screen and (forced-colors: active){ - --dialog-bg-color:Canvas; - --dialog-border-color:CanvasText; - --dialog-shadow:none; - --text-primary-color:CanvasText; - --text-secondary-color:CanvasText; - --hover-filter:none; - --focus-ring-color:ButtonBorder; - - --textarea-border-color:ButtonBorder; - --textarea-bg-color:Field; - --textarea-fg-color:ButtonText; - - --radio-bg-color:ButtonFace; - --radio-checked-bg-color:ButtonFace; - --radio-border-color:ButtonText; - --radio-checked-border-color:ButtonText; - - --button-cancel-bg-color:ButtonFace; - --button-cancel-fg-color:ButtonText; - --button-cancel-border-color:ButtonText; - --button-cancel-hover-bg-color:AccentColor; - --button-cancel-hover-fg-color:AccentColorText; - - --button-save-bg-color:ButtonText; - --button-save-fg-color:ButtonFace; - --button-save-hover-bg-color:AccentColor; - --button-save-hover-fg-color:AccentColorText; - } - - font:message-box; - font-size:13px; - font-weight:400; - line-height:150%; - border-radius:4px; - padding:12px 16px; - border:1px solid var(--dialog-border-color); - background:var(--dialog-bg-color); - color:var(--text-primary-color); - box-shadow:var(--dialog-shadow); - +.dialog.altText{ &::backdrop{ mask:url(#alttext-manager-mask); } - &.positioned{ margin:0; } @@ -1836,58 +1953,6 @@ align-items:flex-start; gap:16px; - & *:focus-visible{ - outline:var(--focus-ring-outline); - outline-offset:2px; - } - - & .radio{ - display:flex; - flex-direction:column; - align-items:flex-start; - gap:4px; - - & .radioButton{ - display:flex; - gap:8px; - align-self:stretch; - align-items:center; - - & input{ - appearance:none; - box-sizing:border-box; - width:16px; - height:16px; - border-radius:50%; - background-color:var(--radio-bg-color); - border:1px solid var(--radio-border-color); - - &:hover{ - filter:var(--hover-filter); - } - - &:checked{ - background-color:var(--radio-checked-bg-color); - border:4px solid var(--radio-checked-border-color); - } - } - } - - & .radioLabel{ - display:flex; - padding-inline-start:24px; - align-items:flex-start; - gap:10px; - align-self:stretch; - - & span{ - flex:1 0 0; - font-size:11px; - color:var(--text-secondary-color); - } - } - } - & #overallDescription{ display:flex; flex-direction:column; @@ -1917,27 +1982,8 @@ padding-inline:24px 10px; textarea{ - font:inherit; width:100%; min-height:75px; - padding:8px; - resize:none; - margin:0; - box-sizing:border-box; - border-radius:4px; - border:1px solid var(--textarea-border-color); - background:var(--textarea-bg-color); - color:var(--textarea-fg-color); - - &:focus{ - outline-offset:0; - border-color:transparent; - } - - &:disabled{ - pointer-events:none; - opacity:0.4; - } } } } @@ -1948,46 +1994,6 @@ align-items:flex-start; gap:8px; align-self:stretch; - - button{ - border-radius:4px; - border:1px solid; - font:menu; - font-weight:600; - padding:4px 16px; - width:auto; - height:32px; - - &:hover{ - cursor:pointer; - filter:var(--hover-filter); - } - - &#altTextCancel{ - color:var(--button-cancel-fg-color); - background-color:var(--button-cancel-bg-color); - border-color:var(--button-cancel-border-color); - - &:hover{ - color:var(--button-cancel-hover-fg-color); - background-color:var(--button-cancel-hover-bg-color); - border-color:var(--button-cancel-hover-border-color); - } - } - - &#altTextSave{ - color:var(--button-save-hover-fg-color); - background-color:var(--button-save-hover-bg-color); - border-color:var(--button-save-hover-border-color); - opacity:1; - - &:hover{ - color:var(--button-save-hover-fg-color); - background-color:var(--button-save-hover-bg-color); - border-color:var(--button-save-hover-border-color); - } - } - } } } } diff --git a/toolkit/components/pdfjs/content/web/viewer.html b/toolkit/components/pdfjs/content/web/viewer.html index 941e17b58d7a..268041286231 100644 --- a/toolkit/components/pdfjs/content/web/viewer.html +++ b/toolkit/components/pdfjs/content/web/viewer.html @@ -441,8 +441,8 @@ See https://github.com/adobe-type-tools/cmap-resources - -
+ +
Choose an option @@ -479,8 +479,8 @@ See https://github.com/adobe-type-tools/cmap-resources
- - + +
diff --git a/toolkit/components/pdfjs/content/web/viewer.mjs b/toolkit/components/pdfjs/content/web/viewer.mjs index fab026282333..a69614dc5f04 100644 --- a/toolkit/components/pdfjs/content/web/viewer.mjs +++ b/toolkit/components/pdfjs/content/web/viewer.mjs @@ -7449,17 +7449,18 @@ class TextHighlighter { class TextLayerBuilder { #enablePermissions = false; #onAppend = null; - #textContentSource = null; + #renderingDone = false; #textLayer = null; static #textLayers = new Map(); static #selectionChangeAbortController = null; constructor({ + pdfPage, highlighter = null, accessibilityManager = null, enablePermissions = false, onAppend = null }) { - this.renderingDone = false; + this.pdfPage = pdfPage; this.highlighter = highlighter; this.accessibilityManager = accessibilityManager; this.#enablePermissions = enablePermissions === true; @@ -7469,17 +7470,14 @@ class TextLayerBuilder { this.div.className = "textLayer"; } #finishRendering() { - this.renderingDone = true; + this.#renderingDone = true; const endOfContent = document.createElement("div"); endOfContent.className = "endOfContent"; this.div.append(endOfContent); this.#bindMouse(endOfContent); } - async render(viewport) { - if (!this.#textContentSource) { - throw new Error('No "textContentSource" parameter specified.'); - } - if (this.renderingDone && this.#textLayer) { + async render(viewport, textContentParams = null) { + if (this.#renderingDone && this.#textLayer) { this.#textLayer.update({ viewport, onBefore: this.hide.bind(this) @@ -7489,7 +7487,10 @@ class TextLayerBuilder { } this.cancel(); this.#textLayer = new TextLayer({ - textContentSource: this.#textContentSource, + textContentSource: this.pdfPage.streamTextContent(textContentParams || { + includeMarkedContent: true, + disableNormalization: true + }), container: this.div, viewport }); @@ -7506,13 +7507,13 @@ class TextLayerBuilder { this.accessibilityManager?.enable(); } hide() { - if (!this.div.hidden && this.renderingDone) { + if (!this.div.hidden && this.#renderingDone) { this.highlighter?.disable(); this.div.hidden = true; } } show() { - if (this.div.hidden && this.renderingDone) { + if (this.div.hidden && this.#renderingDone) { this.div.hidden = false; this.highlighter?.enable(); } @@ -7524,10 +7525,6 @@ class TextLayerBuilder { this.accessibilityManager?.disable(); TextLayerBuilder.#removeGlobalSelectionListener(this.div); } - setTextContentSource(source) { - this.cancel(); - this.#textContentSource = source; - } #bindMouse(end) { const { div @@ -7554,34 +7551,37 @@ class TextLayerBuilder { } } static #enableGlobalSelectionListener() { - if (TextLayerBuilder.#selectionChangeAbortController) { + if (this.#selectionChangeAbortController) { return; } - TextLayerBuilder.#selectionChangeAbortController = new AbortController(); + this.#selectionChangeAbortController = new AbortController(); + const { + signal + } = this.#selectionChangeAbortController; const reset = (end, textLayer) => { end.classList.remove("active"); }; document.addEventListener("pointerup", () => { - TextLayerBuilder.#textLayers.forEach(reset); + this.#textLayers.forEach(reset); }, { - signal: TextLayerBuilder.#selectionChangeAbortController.signal + signal }); document.addEventListener("selectionchange", () => { const selection = document.getSelection(); if (selection.rangeCount === 0) { - TextLayerBuilder.#textLayers.forEach(reset); + this.#textLayers.forEach(reset); return; } const activeTextLayers = new Set(); for (let i = 0; i < selection.rangeCount; i++) { const range = selection.getRangeAt(i); - for (const textLayerDiv of TextLayerBuilder.#textLayers.keys()) { + for (const textLayerDiv of this.#textLayers.keys()) { if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) { activeTextLayers.add(textLayerDiv); } } } - for (const [textLayerDiv, endDiv] of TextLayerBuilder.#textLayers) { + for (const [textLayerDiv, endDiv] of this.#textLayers) { if (activeTextLayers.has(textLayerDiv)) { endDiv.classList.add("active"); } else { @@ -7589,7 +7589,7 @@ class TextLayerBuilder { } } }, { - signal: TextLayerBuilder.#selectionChangeAbortController.signal + signal }); } } @@ -7749,6 +7749,13 @@ class PDFPageView { findController: this.#layerProperties.findController })); } + #dispatchLayerRendered(name, error) { + this.eventBus.dispatch(name, { + source: this, + pageNumber: this.id, + error + }); + } async #renderAnnotationLayer() { let error = null; try { @@ -7757,11 +7764,7 @@ class PDFPageView { console.error(`#renderAnnotationLayer: "${ex}".`); error = ex; } finally { - this.eventBus.dispatch("annotationlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("annotationlayerrendered", error); } } async #renderAnnotationEditorLayer() { @@ -7772,11 +7775,7 @@ class PDFPageView { console.error(`#renderAnnotationEditorLayer: "${ex}".`); error = ex; } finally { - this.eventBus.dispatch("annotationeditorlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("annotationeditorlayerrendered", error); } } async #renderDrawLayer() { @@ -7802,32 +7801,16 @@ class PDFPageView { this.#addLayer(this.xfaLayer.div, "xfaLayer"); this.l10n.resume(); } - this.eventBus.dispatch("xfalayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("xfalayerrendered", error); } } async #renderTextLayer() { - const { - pdfPage, - textLayer, - viewport - } = this; - if (!textLayer) { + if (!this.textLayer) { return; } let error = null; try { - if (!textLayer.renderingDone) { - const readableStream = pdfPage.streamTextContent({ - includeMarkedContent: true, - disableNormalization: true - }); - textLayer.setTextContentSource(readableStream); - } - await textLayer.render(viewport); + await this.textLayer.render(this.viewport); } catch (ex) { if (ex instanceof AbortException) { return; @@ -7835,11 +7818,7 @@ class PDFPageView { console.error(`#renderTextLayer: "${ex}".`); error = ex; } - this.eventBus.dispatch("textlayerrendered", { - source: this, - pageNumber: this.id, - error - }); + this.#dispatchLayerRendered("textlayerrendered", error); this.#renderStructTreeLayer(); } async #renderStructTreeLayer() { @@ -8177,6 +8156,7 @@ class PDFPageView { if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) { this._accessibilityManager ||= new TextAccessibilityManager(); this.textLayer = new TextLayerBuilder({ + pdfPage, highlighter: this._textHighlighter, accessibilityManager: this._accessibilityManager, enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS, @@ -8279,7 +8259,7 @@ class PDFPageView { annotationCanvasMap: this._annotationCanvasMap, pageColors }; - const renderTask = this.renderTask = this.pdfPage.render(renderContext); + const renderTask = this.renderTask = pdfPage.render(renderContext); renderTask.onContinue = renderContinueCallback; const resultPromise = renderTask.promise.then(async () => { showCanvas?.(true); @@ -8447,7 +8427,7 @@ class PDFViewer { #scaleTimeoutId = null; #textLayerMode = TextLayerMode.ENABLE; constructor(options) { - const viewerVersion = "4.3.83"; + const viewerVersion = "4.3.138"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } @@ -9093,7 +9073,8 @@ class PDFViewer { #setScaleUpdatePages(newScale, newValue, { noScroll = false, preset = false, - drawingDelay = -1 + drawingDelay = -1, + origin = null }) { this._currentScaleValue = newValue.toString(); if (this.#isSameScale(newScale)) { @@ -9118,6 +9099,7 @@ class PDFViewer { this.refresh(); }, drawingDelay); } + const previousScale = this._currentScale; this._currentScale = newScale; if (!noScroll) { let page = this._currentPageNumber, @@ -9133,6 +9115,12 @@ class PDFViewer { destArray: dest, allowNegativeOffset: true }); + if (Array.isArray(origin)) { + const scaleDiff = newScale / previousScale - 1; + const [top, left] = this.containerTopLeft; + this.container.scrollLeft += (origin[0] - left) * scaleDiff; + this.container.scrollTop += (origin[1] - top) * scaleDiff; + } } this.eventBus.dispatch("scalechanging", { source: this, @@ -9735,48 +9723,46 @@ class PDFViewer { this.currentPageNumber = Math.max(currentPageNumber - advance, 1); return true; } - increaseScale({ + updateScale({ drawingDelay, - scaleFactor, - steps - } = {}) { + scaleFactor = null, + steps = null, + origin + }) { + if (steps === null && scaleFactor === null) { + throw new Error("Invalid updateScale options: either `steps` or `scaleFactor` must be provided."); + } if (!this.pdfDocument) { return; } let newScale = this._currentScale; - if (scaleFactor > 1) { + if (scaleFactor > 0 && scaleFactor !== 1) { newScale = Math.round(newScale * scaleFactor * 100) / 100; - } else { - steps ??= 1; + } else if (steps) { + const delta = steps > 0 ? DEFAULT_SCALE_DELTA : 1 / DEFAULT_SCALE_DELTA; + const round = steps > 0 ? Math.ceil : Math.floor; + steps = Math.abs(steps); do { - newScale = Math.ceil((newScale * DEFAULT_SCALE_DELTA).toFixed(2) * 10) / 10; - } while (--steps > 0 && newScale < MAX_SCALE); + newScale = round((newScale * delta).toFixed(2) * 10) / 10; + } while (--steps > 0); } - this.#setScale(Math.min(MAX_SCALE, newScale), { + newScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, newScale)); + this.#setScale(newScale, { noScroll: false, - drawingDelay + drawingDelay, + origin }); } - decreaseScale({ - drawingDelay, - scaleFactor, - steps - } = {}) { - if (!this.pdfDocument) { - return; - } - let newScale = this._currentScale; - if (scaleFactor > 0 && scaleFactor < 1) { - newScale = Math.round(newScale * scaleFactor * 100) / 100; - } else { - steps ??= 1; - do { - newScale = Math.floor((newScale / DEFAULT_SCALE_DELTA).toFixed(2) * 10) / 10; - } while (--steps > 0 && newScale > MIN_SCALE); - } - this.#setScale(Math.max(MIN_SCALE, newScale), { - noScroll: false, - drawingDelay + increaseScale(options = {}) { + this.updateScale({ + ...options, + steps: options.steps ?? 1 + }); + } + decreaseScale(options = {}) { + this.updateScale({ + ...options, + steps: -(options.steps ?? 1) }); } #updateContainerHeightCss(height = this.container.clientHeight) { @@ -10852,25 +10838,22 @@ const PDFViewerApplication = { get initializedPromise() { return this._initializedCapability.promise; }, - zoomIn(steps, scaleFactor) { + updateZoom(steps, scaleFactor, origin) { if (this.pdfViewer.isInPresentationMode) { return; } - this.pdfViewer.increaseScale({ + this.pdfViewer.updateScale({ drawingDelay: AppOptions.get("defaultZoomDelay"), steps, - scaleFactor + scaleFactor, + origin }); }, - zoomOut(steps, scaleFactor) { - if (this.pdfViewer.isInPresentationMode) { - return; - } - this.pdfViewer.decreaseScale({ - drawingDelay: AppOptions.get("defaultZoomDelay"), - steps, - scaleFactor - }); + zoomIn() { + this.updateZoom(1); + }, + zoomOut() { + this.updateZoom(-1); }, zoomReset() { if (this.pdfViewer.isInPresentationMode) { @@ -11877,17 +11860,6 @@ const PDFViewerApplication = { this[prop] = factor / newFactor; return newFactor; }, - _centerAtPos(previousScale, x, y) { - const { - pdfViewer - } = this; - const scaleDiff = pdfViewer.currentScale / previousScale - 1; - if (scaleDiff !== 0) { - const [top, left] = pdfViewer.containerTopLeft; - pdfViewer.container.scrollLeft += (x - left) * scaleDiff; - pdfViewer.container.scrollTop += (y - top) * scaleDiff; - } - }, _unblockDocumentLoadEvent() { document.blockUnblockOnload?.(false); this._unblockDocumentLoadEvent = () => {}; @@ -12192,21 +12164,15 @@ function webViewerWheel(evt) { let scaleFactor = Math.exp(-evt.deltaY / 100); const isBuiltInMac = FeatureTest.platform.isMac; const isPinchToZoom = evt.ctrlKey && !PDFViewerApplication._isCtrlKeyDown && deltaMode === WheelEvent.DOM_DELTA_PIXEL && evt.deltaX === 0 && (Math.abs(scaleFactor - 1) < 0.05 || isBuiltInMac) && evt.deltaZ === 0; + const origin = [evt.clientX, evt.clientY]; if (isPinchToZoom || evt.ctrlKey && supportsMouseWheelZoomCtrlKey || evt.metaKey && supportsMouseWheelZoomMetaKey) { evt.preventDefault(); if (PDFViewerApplication._isScrolling || zoomDisabledTimeout || document.visibilityState === "hidden" || PDFViewerApplication.overlayManager.active) { return; } - const previousScale = pdfViewer.currentScale; if (isPinchToZoom && supportsPinchToZoom) { - scaleFactor = PDFViewerApplication._accumulateFactor(previousScale, scaleFactor, "_wheelUnusedFactor"); - if (scaleFactor < 1) { - PDFViewerApplication.zoomOut(null, scaleFactor); - } else if (scaleFactor > 1) { - PDFViewerApplication.zoomIn(null, scaleFactor); - } else { - return; - } + scaleFactor = PDFViewerApplication._accumulateFactor(pdfViewer.currentScale, scaleFactor, "_wheelUnusedFactor"); + PDFViewerApplication.updateZoom(null, scaleFactor, origin); } else { const delta = normalizeWheelEventDirection(evt); let ticks = 0; @@ -12220,15 +12186,8 @@ function webViewerWheel(evt) { const PIXELS_PER_LINE_SCALE = 30; ticks = PDFViewerApplication._accumulateTicks(delta / PIXELS_PER_LINE_SCALE, "_wheelUnusedTicks"); } - if (ticks < 0) { - PDFViewerApplication.zoomOut(-ticks); - } else if (ticks > 0) { - PDFViewerApplication.zoomIn(ticks); - } else { - return; - } + PDFViewerApplication.updateZoom(ticks, null, origin); } - PDFViewerApplication._centerAtPos(previousScale, evt.clientX, evt.clientY); } } function webViewerTouchStart(evt) { @@ -12314,30 +12273,17 @@ function webViewerTouchMove(evt) { } } evt.preventDefault(); + const origin = [(page0X + page1X) / 2, (page0Y + page1Y) / 2]; const distance = Math.hypot(page0X - page1X, page0Y - page1Y) || 1; const pDistance = Math.hypot(pTouch0X - pTouch1X, pTouch0Y - pTouch1Y) || 1; - const previousScale = pdfViewer.currentScale; if (supportsPinchToZoom) { - const newScaleFactor = PDFViewerApplication._accumulateFactor(previousScale, distance / pDistance, "_touchUnusedFactor"); - if (newScaleFactor < 1) { - PDFViewerApplication.zoomOut(null, newScaleFactor); - } else if (newScaleFactor > 1) { - PDFViewerApplication.zoomIn(null, newScaleFactor); - } else { - return; - } + const newScaleFactor = PDFViewerApplication._accumulateFactor(pdfViewer.currentScale, distance / pDistance, "_touchUnusedFactor"); + PDFViewerApplication.updateZoom(null, newScaleFactor, origin); } else { const PIXELS_PER_LINE_SCALE = 30; const ticks = PDFViewerApplication._accumulateTicks((distance - pDistance) / PIXELS_PER_LINE_SCALE, "_touchUnusedTicks"); - if (ticks < 0) { - PDFViewerApplication.zoomOut(-ticks); - } else if (ticks > 0) { - PDFViewerApplication.zoomIn(ticks); - } else { - return; - } + PDFViewerApplication.updateZoom(ticks, null, origin); } - PDFViewerApplication._centerAtPos(previousScale, (page0X + page1X) / 2, (page0Y + page1Y) / 2); } function webViewerTouchEnd(evt) { if (!PDFViewerApplication._touchInfo) { @@ -12637,8 +12583,8 @@ function webViewerReportTelemetry({ -const pdfjsVersion = "4.3.83"; -const pdfjsBuild = "9ee7c07b8"; +const pdfjsVersion = "4.3.138"; +const pdfjsBuild = "24e12d515"; const AppConstants = null; window.PDFViewerApplication = PDFViewerApplication; window.PDFViewerApplicationConstants = AppConstants; diff --git a/toolkit/components/pdfjs/moz.yaml b/toolkit/components/pdfjs/moz.yaml index d98cd0add102..fd334dcc4ee2 100644 --- a/toolkit/components/pdfjs/moz.yaml +++ b/toolkit/components/pdfjs/moz.yaml @@ -20,8 +20,8 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: 9ee7c07b837d0a849ed75272d48947eb33812a45 (2024-05-21T10:28:28Z). - revision: 9ee7c07b837d0a849ed75272d48947eb33812a45 + release: 24e12d515dce2f11b392410dd6e6e9926270ac65 (2024-05-28T16:48:09Z). + revision: 24e12d515dce2f11b392410dd6e6e9926270ac65 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/