tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit baedb7894c76552439fbf59b328a851ccb76c140
parent 5d95a0922d711aabc29e3b3e5ab9dd2d16d1f084
Author: Updatebot <updatebot@mozilla.com>
Date:   Fri, 17 Oct 2025 07:55:35 +0000

Bug 1994502 - Update PDF.js to 3eca60735ba27d0c6ec16b60b88dd6f1f5297e1c r=pdfjs-reviewers,calixte

Differential Revision: https://phabricator.services.mozilla.com/D268746

Diffstat:
Mtoolkit/components/pdfjs/content/build/pdf.mjs | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mtoolkit/components/pdfjs/content/build/pdf.scripting.mjs | 4++--
Mtoolkit/components/pdfjs/content/build/pdf.worker.mjs | 178++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mtoolkit/components/pdfjs/content/web/viewer-geckoview.mjs | 12+++++-------
Mtoolkit/components/pdfjs/content/web/viewer.mjs | 12+++++-------
Mtoolkit/components/pdfjs/moz.yaml | 4++--
6 files changed, 288 insertions(+), 153 deletions(-)

diff --git a/toolkit/components/pdfjs/content/build/pdf.mjs b/toolkit/components/pdfjs/content/build/pdf.mjs @@ -21,8 +21,8 @@ */ /** - * pdfjsVersion = 5.4.315 - * pdfjsBuild = 8ba18075f + * pdfjsVersion = 5.4.329 + * pdfjsBuild = 3eca60735 */ /******/ // The require scope /******/ var __webpack_require__ = {}; @@ -108,6 +108,11 @@ const PermissionFlag = { ASSEMBLE: 0x400, PRINT_HIGH_QUALITY: 0x800 }; +const MeshFigureType = { + TRIANGLES: 1, + LATTICE: 2, + PATCH: 3 +}; const TextRenderingMode = { FILL: 0, STROKE: 1, @@ -5572,6 +5577,9 @@ class AnnotationEditor { return this.#comment ||= new Comment(this); } addStandaloneCommentButton() { + if (!this._uiManager.hasCommentManager()) { + return; + } if (this.#commentStandaloneButton) { if (this._uiManager.isEditingMode()) { this.#commentStandaloneButton.classList.remove("hidden"); @@ -8292,7 +8300,7 @@ function drawFigure(data, figure, context) { const cs = figure.colors; let i, ii; switch (figure.type) { - case "lattice": + case MeshFigureType.LATTICE: const verticesPerRow = figure.verticesPerRow; const rows = Math.floor(ps.length / verticesPerRow) - 1; const cols = verticesPerRow - 1; @@ -8304,7 +8312,7 @@ function drawFigure(data, figure, context) { } } break; - case "triangles": + case MeshFigureType.TRIANGLES: for (i = 0, ii = ps.length; i < ii; i += 3) { drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]); } @@ -12794,7 +12802,7 @@ function getDocument(src = {}) { } const docParams = { docId, - apiVersion: "5.4.315", + apiVersion: "5.4.329", data, password, disableAutoFetch, @@ -14371,8 +14379,8 @@ class InternalRenderTask { } } } -const version = "5.4.315"; -const build = "8ba18075f"; +const version = "5.4.329"; +const build = "3eca60735"; ;// ./src/display/editor/color_picker.js @@ -14844,6 +14852,7 @@ class AnnotationElement { this.hasJSActions = parameters.hasJSActions; this._fieldObjects = parameters.fieldObjects; this.parent = parameters.parent; + this.hasOwnCommentButton = false; if (isRenderable) { this.contentElement = this.container = this._createContainer(ignoreBorder); } @@ -15348,7 +15357,7 @@ class AnnotationElement { contentsObj = data.contentsObj; modificationDate = data.modificationDate; } - const popup = this.#popupElement = new PopupAnnotationElement({ + this.#popupElement = new PopupAnnotationElement({ data: { color: data.color, titleObj: data.titleObj, @@ -15365,9 +15374,6 @@ class AnnotationElement { parent: this.parent, elements: [this] }); - if (!this.parent._commentManager) { - this.parent.div.append(popup.render()); - } } get hasPopupElement() { return !!(this.#popupElement || this.popup || this.data.popupRef); @@ -15499,7 +15505,6 @@ class EditorAnnotationElement extends AnnotationElement { return; } this._createPopup(editor.comment); - this.extraPopupElement.popup.renderCommentButton(); } get hasCommentButton() { return this.enableComment && this.editor.hasComment; @@ -15520,6 +15525,7 @@ class EditorAnnotationElement extends AnnotationElement { return this.editor.getData(); } remove() { + this.parent.removeAnnotation(this.data.id); this.container.remove(); this.container = null; this.removePopup(); @@ -15775,6 +15781,7 @@ class TextAnnotationElement extends AnnotationElement { type: this.data.name })); if (!this.data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.append(image); @@ -16773,9 +16780,7 @@ class PopupElement { this.#firstElement = elements[0]; this.#dateObj = PDFDateString.toDateObject(modificationDate); this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup()); - if (commentManager) { - this.renderCommentButton(); - } else { + if (!commentManager) { this.#addEventListeners(); this.#container.hidden = true; if (open) { @@ -16818,6 +16823,9 @@ class PopupElement { } renderCommentButton() { if (this.#commentButton) { + if (!this.#commentButton.parentNode) { + this.#firstElement.container.after(this.#commentButton); + } return; } if (!this.#commentButtonPosition) { @@ -16829,7 +16837,7 @@ class PopupElement { const { signal } = this.#popupAbortController = new AbortController(); - const hasOwnButton = !!this.#firstElement.extraPopupElement; + const hasOwnButton = this.#firstElement.hasOwnCommentButton; const togglePopup = () => { this.#commentManager.toggleCommentPopup(this, true, undefined, !hasOwnButton); }; @@ -16888,7 +16896,9 @@ class PopupElement { if (this.#firstElement.extraPopupElement && !this.#firstElement.editor) { return; } - this.renderCommentButton(); + if (!this.#commentButton) { + this.renderCommentButton(); + } const [x, y] = this.#commentButtonPosition; const { style @@ -16900,7 +16910,9 @@ class PopupElement { if (this.#firstElement.extraPopupElement) { return; } - this.renderCommentButton(); + if (!this.#commentButton) { + this.renderCommentButton(); + } this.#commentButton.style.backgroundColor = this.commentButtonColor || ""; } get commentButtonColor() { @@ -17298,6 +17310,7 @@ class FreeTextAnnotationElement extends AnnotationElement { this.container.append(content); } if (!this.data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this._editOnDoubleClick(); @@ -17331,6 +17344,7 @@ class LineAnnotationElement extends AnnotationElement { svg.append(line); this.container.append(svg); if (!data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } return this.container; @@ -17370,6 +17384,7 @@ class SquareAnnotationElement extends AnnotationElement { svg.append(square); this.container.append(svg); if (!data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } return this.container; @@ -17409,6 +17424,7 @@ class CircleAnnotationElement extends AnnotationElement { svg.append(circle); this.container.append(svg); if (!data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } return this.container; @@ -17461,6 +17477,7 @@ class PolylineAnnotationElement extends AnnotationElement { svg.append(polyline); this.container.append(svg); if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } return this.container; @@ -17489,6 +17506,7 @@ class CaretAnnotationElement extends AnnotationElement { render() { this.container.classList.add("caretAnnotation"); if (!this.data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } return this.container; @@ -17567,6 +17585,7 @@ class InkAnnotationElement extends AnnotationElement { g.append(polyline); } if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.append(svg); @@ -17624,6 +17643,7 @@ class HighlightAnnotationElement extends AnnotationElement { } } = this; if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.classList.add("highlightAnnotation"); @@ -17653,6 +17673,7 @@ class UnderlineAnnotationElement extends AnnotationElement { } } = this; if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.classList.add("underlineAnnotation"); @@ -17681,6 +17702,7 @@ class SquigglyAnnotationElement extends AnnotationElement { } } = this; if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.classList.add("squigglyAnnotation"); @@ -17709,6 +17731,7 @@ class StrikeOutAnnotationElement extends AnnotationElement { } } = this; if (!popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this.container.classList.add("strikeoutAnnotation"); @@ -17733,6 +17756,7 @@ class StampAnnotationElement extends AnnotationElement { this.container.classList.add("stampAnnotation"); this.container.setAttribute("role", "img"); if (!this.data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } this._editOnDoubleClick(); @@ -17782,6 +17806,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement { } }); if (!data.popupRef && this.hasPopupData) { + this.hasOwnCommentButton = true; this._createPopup(); } else { trigger.classList.add("popupTriggerArea"); @@ -17806,6 +17831,8 @@ class AnnotationLayer { #editableAnnotations = new Map(); #structTreeLayer = null; #linkService = null; + #elements = []; + #hasAriaAttributesFromStructTree = false; constructor({ div, accessibilityManager, @@ -17833,34 +17860,6 @@ class AnnotationLayer { hasEditableAnnotations() { return this.#editableAnnotations.size > 0; } - async #appendElement(element, id, popupElements) { - const { - contentElement, - container - } = element; - const annotationId = contentElement.id = `${AnnotationPrefix}${id}`; - const ariaAttributes = await this.#structTreeLayer?.getAriaAttributes(annotationId); - if (ariaAttributes) { - for (const [key, value] of ariaAttributes) { - contentElement.setAttribute(key, value); - } - } - if (popupElements) { - popupElements.at(-1).container.after(container); - } else { - this.#moveElementInDOM(container, contentElement); - } - } - #moveElementInDOM(container, contentElement) { - this.div.append(container); - this.#accessibilityManager?.moveElementInDOM(this.div, container, contentElement, false, node => node.nodeName === "SECTION", (prevNode, node) => { - if (prevNode.nextElementSibling.nodeName === "BUTTON") { - prevNode.nextElementSibling.after(node); - } else { - prevNode.after(node); - } - }); - } async render(params) { const { annotations @@ -17868,6 +17867,7 @@ class AnnotationLayer { const layer = this.div; setLayerDimensions(layer, this.viewport); const popupToElements = new Map(); + const popupAnnotations = []; const elementParams = { data: null, layer, @@ -17898,6 +17898,10 @@ class AnnotationLayer { if (!elements) { continue; } + if (!this._commentManager) { + popupAnnotations.push(data); + continue; + } elementParams.elements = elements; } elementParams.data = data; @@ -17905,27 +17909,115 @@ class AnnotationLayer { if (!element.isRenderable) { continue; } - if (!isPopupAnnotation && data.popupRef) { - const elements = popupToElements.get(data.popupRef); - if (!elements) { - popupToElements.set(data.popupRef, [element]); - } else { - elements.push(element); + if (!isPopupAnnotation) { + this.#elements.push(element); + if (data.popupRef) { + const elements = popupToElements.get(data.popupRef); + if (!elements) { + popupToElements.set(data.popupRef, [element]); + } else { + elements.push(element); + } } } const rendered = element.render(); if (data.hidden) { rendered.style.visibility = "hidden"; } - await this.#appendElement(element, data.id, elementParams.elements); - element.extraPopupElement?.popup?.renderCommentButton(); if (element._isEditable) { this.#editableAnnotations.set(element.data.id, element); this._annotationEditorUIManager?.renderAnnotationElement(element); } } + await this.#addElementsToDOM(); + for (const data of popupAnnotations) { + const elements = elementParams.elements = popupToElements.get(data.id); + elementParams.data = data; + const element = AnnotationElementFactory.create(elementParams); + if (!element.isRenderable) { + continue; + } + const rendered = element.render(); + element.contentElement.id = `${AnnotationPrefix}${data.id}`; + if (data.hidden) { + rendered.style.visibility = "hidden"; + } + elements.at(-1).container.after(rendered); + } this.#setAnnotationCanvasMap(); } + async #addElementsToDOM() { + if (this.#elements.length === 0) { + return; + } + this.div.replaceChildren(); + const promises = []; + if (!this.#hasAriaAttributesFromStructTree) { + this.#hasAriaAttributesFromStructTree = true; + for (const { + contentElement, + data: { + id + } + } of this.#elements) { + const annotationId = contentElement.id = `${AnnotationPrefix}${id}`; + promises.push(this.#structTreeLayer?.getAriaAttributes(annotationId).then(ariaAttributes => { + if (ariaAttributes) { + for (const [key, value] of ariaAttributes) { + contentElement.setAttribute(key, value); + } + } + })); + } + } + this.#elements.sort(({ + data: { + rect: [a0, a1, a2, a3] + } + }, { + data: { + rect: [b0, b1, b2, b3] + } + }) => { + if (a0 === a2 && a1 === a3) { + return +1; + } + if (b0 === b2 && b1 === b3) { + return -1; + } + const top1 = a3; + const bot1 = a1; + const mid1 = (a1 + a3) / 2; + const top2 = b3; + const bot2 = b1; + const mid2 = (b1 + b3) / 2; + if (mid1 >= top2 && mid2 <= bot1) { + return -1; + } + if (mid2 >= top1 && mid1 <= bot2) { + return +1; + } + const centerX1 = (a0 + a2) / 2; + const centerX2 = (b0 + b2) / 2; + return centerX1 - centerX2; + }); + const fragment = document.createDocumentFragment(); + for (const element of this.#elements) { + fragment.append(element.container); + if (this._commentManager) { + (element.extraPopupElement?.popup || element.popup)?.renderCommentButton(); + } else if (element.extraPopupElement) { + fragment.append(element.extraPopupElement.render()); + } + } + this.div.append(fragment); + await Promise.all(promises); + if (this.#accessibilityManager) { + for (const element of this.#elements) { + this.#accessibilityManager.addPointerInTextLayer(element.contentElement, false); + } + } + } async addLinkAnnotations(annotations) { const elementParams = { data: null, @@ -17942,8 +18034,10 @@ class AnnotationLayer { continue; } element.render(); - await this.#appendElement(element, data.id, null); + element.contentElement.id = `${AnnotationPrefix}${data.id}`; + this.#elements.push(element); } + await this.#addElementsToDOM(); } update({ viewport @@ -18019,24 +18113,31 @@ class AnnotationLayer { linkService: this.#linkService, annotationStorage: this.#annotationStorage }); - const rendered = element.render(); - rendered.id = `${AnnotationPrefix}${id}`; - this.#moveElementInDOM(rendered, rendered); + element.render(); + element.contentElement.id = `${AnnotationPrefix}${id}`; element.createOrUpdatePopup(); + this.#elements.push(element); return element; } - togglePointerEvents(enabled = false) { - this.div.classList.toggle("disabled", !enabled); + removeAnnotation(id) { + const index = this.#elements.findIndex(el => el.data.id === id); + if (index < 0) { + return; + } + const [element] = this.#elements.splice(index, 1); + this.#accessibilityManager?.removePointerInTextLayer(element.contentElement); } updateFakeAnnotations(editors) { if (editors.length === 0) { return; } - window.requestAnimationFrame(() => setTimeout(() => { - for (const editor of editors) { - editor.updateFakeAnnotationElement(this); - } - }, 10)); + for (const editor of editors) { + editor.updateFakeAnnotationElement(this); + } + this.#addElementsToDOM(); + } + togglePointerEvents(enabled = false) { + this.div.classList.toggle("disabled", !enabled); } static get _defaultBorderStyle() { return shadow(this, "_defaultBorderStyle", Object.freeze({ diff --git a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs @@ -21,8 +21,8 @@ */ /** - * pdfjsVersion = 5.4.315 - * pdfjsBuild = 8ba18075f + * pdfjsVersion = 5.4.329 + * pdfjsBuild = 3eca60735 */ var __webpack_exports__ = {}; diff --git a/toolkit/components/pdfjs/content/build/pdf.worker.mjs b/toolkit/components/pdfjs/content/build/pdf.worker.mjs @@ -21,8 +21,8 @@ */ /** - * pdfjsVersion = 5.4.315 - * pdfjsBuild = 8ba18075f + * pdfjsVersion = 5.4.329 + * pdfjsBuild = 3eca60735 */ /******/ // The require scope /******/ var __webpack_require__ = {}; @@ -108,6 +108,11 @@ const PermissionFlag = { ASSEMBLE: 0x400, PRINT_HIGH_QUALITY: 0x800 }; +const MeshFigureType = { + TRIANGLES: 1, + LATTICE: 2, + PATCH: 3 +}; const TextRenderingMode = { FILL: 0, STROKE: 1, @@ -27583,7 +27588,7 @@ class MeshShading extends BaseShading { reader.align(); } this.figures.push({ - type: "triangles", + type: MeshFigureType.TRIANGLES, coords: new Int32Array(ps), colors: new Int32Array(ps) }); @@ -27600,7 +27605,7 @@ class MeshShading extends BaseShading { colors.push(color); } this.figures.push({ - type: "lattice", + type: MeshFigureType.LATTICE, coords: new Int32Array(ps), colors: new Int32Array(ps), verticesPerRow @@ -27717,7 +27722,7 @@ class MeshShading extends BaseShading { ps[10] = coords.length; coords.push([(-4 * coords[ps[15]][0] - coords[ps[0]][0] + 6 * (coords[ps[11]][0] + coords[ps[14]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9, (-4 * coords[ps[15]][1] - coords[ps[0]][1] + 6 * (coords[ps[11]][1] + coords[ps[14]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9]); this.figures.push({ - type: "patch", + type: MeshFigureType.PATCH, coords: new Int32Array(ps), colors: new Int32Array(cs) }); @@ -27842,7 +27847,7 @@ class MeshShading extends BaseShading { break; } this.figures.push({ - type: "patch", + type: MeshFigureType.PATCH, coords: new Int32Array(ps), colors: new Int32Array(cs) }); @@ -27850,7 +27855,7 @@ class MeshShading extends BaseShading { } _buildFigureFromPatch(index) { const figure = this.figures[index]; - assert(figure.type === "patch", "Unexpected patch mesh figure"); + assert(figure.type === MeshFigureType.PATCH, "Unexpected patch mesh figure"); const coords = this.coords, colors = this.colors; const pi = figure.coords; @@ -27915,7 +27920,7 @@ class MeshShading extends BaseShading { figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15]; figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3]; this.figures[index] = { - type: "lattice", + type: MeshFigureType.LATTICE, coords: figureCoords, colors: figureColors, verticesPerRow @@ -36848,6 +36853,28 @@ class StructTreeRoot { this.ref = rootRef instanceof Ref ? rootRef : null; this.roleMap = new Map(); this.structParentIds = null; + this.kidRefToPosition = undefined; + } + getKidPosition(kidRef) { + if (this.kidRefToPosition === undefined) { + const obj = this.dict.get("K"); + if (Array.isArray(obj)) { + const map = this.kidRefToPosition = new Map(); + for (let i = 0, ii = obj.length; i < ii; i++) { + const ref = obj[i]; + if (ref) { + map.set(ref.toString(), i); + } + } + } else if (obj instanceof Dict) { + this.kidRefToPosition = new Map([[obj.objId, 0]]); + } else if (!obj) { + this.kidRefToPosition = new Map(); + } else { + this.kidRefToPosition = null; + } + } + return this.kidRefToPosition ? this.kidRefToPosition.get(kidRef) ?? NaN : -1; } init() { this.readRoleMap(); @@ -37502,29 +37529,14 @@ class StructTreePage { return element; } addTopLevelNode(dict, element) { - const obj = this.rootDict.get("K"); - if (!obj) { + const index = this.root.getKidPosition(dict.objId); + if (isNaN(index)) { return false; } - if (obj instanceof Dict) { - if (obj.objId !== dict.objId) { - return false; - } - this.nodes[0] = element; - return true; - } - if (!Array.isArray(obj)) { - return true; - } - let save = false; - for (let i = 0; i < obj.length; i++) { - const kidRef = obj[i]; - if (kidRef?.toString() === dict.objId) { - this.nodes[i] = element; - save = true; - } + if (index !== -1) { + this.nodes[index] = element; } - return save; + return true; } get serializable() { function nodeToSerializable(node, parent, level = 0) { @@ -53477,10 +53489,10 @@ class DatasetReader { ;// ./src/core/intersector.js class SingleIntersector { #annotation; - #minX = Infinity; - #minY = Infinity; - #maxX = -Infinity; - #maxY = -Infinity; + minX = Infinity; + minY = Infinity; + maxX = -Infinity; + maxY = -Infinity; #quadPoints = null; #text = []; #extraChars = []; @@ -53490,24 +53502,21 @@ class SingleIntersector { this.#annotation = annotation; const quadPoints = annotation.data.quadPoints; if (!quadPoints) { - [this.#minX, this.#minY, this.#maxX, this.#maxY] = annotation.data.rect; + [this.minX, this.minY, this.maxX, this.maxY] = annotation.data.rect; return; } for (let i = 0, ii = quadPoints.length; i < ii; i += 8) { - this.#minX = Math.min(this.#minX, quadPoints[i]); - this.#maxX = Math.max(this.#maxX, quadPoints[i + 2]); - this.#minY = Math.min(this.#minY, quadPoints[i + 5]); - this.#maxY = Math.max(this.#maxY, quadPoints[i + 1]); + this.minX = Math.min(this.minX, quadPoints[i]); + this.maxX = Math.max(this.maxX, quadPoints[i + 2]); + this.minY = Math.min(this.minY, quadPoints[i + 5]); + this.maxY = Math.max(this.maxY, quadPoints[i + 1]); } if (quadPoints.length > 8) { this.#quadPoints = quadPoints; } } - overlaps(other) { - return !(this.#minX >= other.#maxX || this.#maxX <= other.#minX || this.#minY >= other.#maxY || this.#maxY <= other.#minY); - } #intersects(x, y) { - if (this.#minX >= x || this.#maxX <= x || this.#minY >= y || this.#maxY <= y) { + if (this.minX >= x || this.maxX <= x || this.minY >= y || this.maxY <= y) { return false; } const quadPoints = this.#quadPoints; @@ -53558,52 +53567,81 @@ class SingleIntersector { this.#annotation.data.overlaidText = this.#text.join(""); } } +const STEPS = 64; class Intersector { - #intersectors = new Map(); + #intersectors = []; + #grid = []; + #minX; + #maxX; + #minY; + #maxY; + #invXRatio; + #invYRatio; constructor(annotations) { + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + const intersectors = this.#intersectors; for (const annotation of annotations) { if (!annotation.data.quadPoints && !annotation.data.rect) { continue; } const intersector = new SingleIntersector(annotation); - for (const [otherIntersector, overlapping] of this.#intersectors) { - if (otherIntersector.overlaps(intersector)) { - if (!overlapping) { - this.#intersectors.set(otherIntersector, new Set([intersector])); - } else { - overlapping.add(intersector); - } - } - } - this.#intersectors.set(intersector, null); - } + intersectors.push(intersector); + minX = Math.min(minX, intersector.minX); + minY = Math.min(minY, intersector.minY); + maxX = Math.max(maxX, intersector.maxX); + maxY = Math.max(maxY, intersector.maxY); + } + this.#minX = minX; + this.#minY = minY; + this.#maxX = maxX; + this.#maxY = maxY; + this.#invXRatio = (STEPS - 1) / (maxX - minX); + this.#invYRatio = (STEPS - 1) / (maxY - minY); + for (const intersector of intersectors) { + const iMin = this.#getGridIndex(intersector.minX, intersector.minY); + const iMax = this.#getGridIndex(intersector.maxX, intersector.maxY); + const w = (iMax - iMin) % STEPS; + const h = Math.floor((iMax - iMin) / STEPS); + for (let i = iMin; i <= iMin + h * STEPS; i += STEPS) { + for (let j = 0; j <= w; j++) { + let existing = this.#grid[i + j]; + if (!existing) { + this.#grid[i + j] = existing = []; + } + existing.push(intersector); + } + } + } + } + #getGridIndex(x, y) { + const i = Math.floor((x - this.#minX) * this.#invXRatio); + const j = Math.floor((y - this.#minY) * this.#invYRatio); + return i + j * STEPS; } addGlyph(transform, width, height, glyph) { const x = transform[4] + width / 2; const y = transform[5] + height / 2; - let overlappingIntersectors; - for (const [intersector, overlapping] of this.#intersectors) { - if (overlappingIntersectors) { - if (overlappingIntersectors.has(intersector)) { - intersector.addGlyph(x, y, glyph); - } else { - intersector.disableExtraChars(); - } - continue; - } - if (!intersector.addGlyph(x, y, glyph)) { - continue; - } - overlappingIntersectors = overlapping; + if (x < this.#minX || y < this.#minY || x > this.#maxX || y > this.#maxY) { + return; + } + const intersectors = this.#grid[this.#getGridIndex(x, y)]; + if (!intersectors) { + return; + } + for (const intersector of intersectors) { + intersector.addGlyph(x, y, glyph); } } addExtraChar(char) { - for (const intersector of this.#intersectors.keys()) { + for (const intersector of this.#intersectors) { intersector.addExtraChar(char); } } setText() { - for (const intersector of this.#intersectors.keys()) { + for (const intersector of this.#intersectors) { intersector.setText(); } } @@ -58126,7 +58164,7 @@ class WorkerMessageHandler { docId, apiVersion } = docParams; - const workerVersion = "5.4.315"; + const workerVersion = "5.4.329"; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); } diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs @@ -21,8 +21,8 @@ */ /** - * pdfjsVersion = 5.4.315 - * pdfjsBuild = 8ba18075f + * pdfjsVersion = 5.4.329 + * pdfjsBuild = 3eca60735 */ /******/ // The require scope /******/ var __webpack_require__ = {}; @@ -6941,21 +6941,19 @@ class TextAccessibilityManager { const parent = child.parentNode; return parent?.classList.contains("markedContent") ? parent.id : null; } - moveElementInDOM(container, element, contentElement, isRemovable, filter, inserter) { + moveElementInDOM(container, element, contentElement, isRemovable) { const id = this.addPointerInTextLayer(contentElement, isRemovable); if (!container.hasChildNodes()) { container.append(element); return id; } - const children = Array.from(container.childNodes).filter(node => node !== element && (!filter || filter(node))); + const children = Array.from(container.childNodes).filter(node => node !== element); if (children.length === 0) { return id; } const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0); if (index === 0) { children[0].before(element); - } else if (inserter) { - inserter(children[index - 1], element); } else { children[index - 1].after(element); } @@ -8215,7 +8213,7 @@ class PDFViewer { #textLayerMode = TextLayerMode.ENABLE; #viewerAlert = null; constructor(options) { - const viewerVersion = "5.4.315"; + const viewerVersion = "5.4.329"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } diff --git a/toolkit/components/pdfjs/content/web/viewer.mjs b/toolkit/components/pdfjs/content/web/viewer.mjs @@ -21,8 +21,8 @@ */ /** - * pdfjsVersion = 5.4.315 - * pdfjsBuild = 8ba18075f + * pdfjsVersion = 5.4.329 + * pdfjsBuild = 3eca60735 */ /******/ // The require scope /******/ var __webpack_require__ = {}; @@ -10126,21 +10126,19 @@ class TextAccessibilityManager { const parent = child.parentNode; return parent?.classList.contains("markedContent") ? parent.id : null; } - moveElementInDOM(container, element, contentElement, isRemovable, filter, inserter) { + moveElementInDOM(container, element, contentElement, isRemovable) { const id = this.addPointerInTextLayer(contentElement, isRemovable); if (!container.hasChildNodes()) { container.append(element); return id; } - const children = Array.from(container.childNodes).filter(node => node !== element && (!filter || filter(node))); + const children = Array.from(container.childNodes).filter(node => node !== element); if (children.length === 0) { return id; } const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0); if (index === 0) { children[0].before(element); - } else if (inserter) { - inserter(children[index - 1], element); } else { children[index - 1].after(element); } @@ -11400,7 +11398,7 @@ class PDFViewer { #textLayerMode = TextLayerMode.ENABLE; #viewerAlert = null; constructor(options) { - const viewerVersion = "5.4.315"; + const viewerVersion = "5.4.329"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } diff --git 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: 8ba18075f2655361795a34930ea6cd4f7ac891c8 (2025-10-08T14:55:01Z). - revision: 8ba18075f2655361795a34930ea6cd4f7ac891c8 + release: 3eca60735ba27d0c6ec16b60b88dd6f1f5297e1c (2025-10-14T18:25:40Z). + revision: 3eca60735ba27d0c6ec16b60b88dd6f1f5297e1c # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/