From 76a5aed05f1e69be551a66abb212c891f1f2a11a Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 10:56:10 +0100 Subject: [PATCH 1/8] Use `Map.prototype.getOrInsert()` in the `getNewAnnotationsMap` helper --- src/core/core_utils.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/core_utils.js b/src/core/core_utils.js index 5980a51f2a7b9..85aedf03b1464 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -669,12 +669,7 @@ function getNewAnnotationsMap(annotationStorage) { if (!key.startsWith(AnnotationEditorPrefix)) { continue; } - let annotations = newAnnotationsByPage.get(value.pageIndex); - if (!annotations) { - annotations = []; - newAnnotationsByPage.set(value.pageIndex, annotations); - } - annotations.push(value); + newAnnotationsByPage.getOrInsert(value.pageIndex, []).push(value); } return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null; } From 210c969c4c16b8909927c33513c4b5d9a7bd94cf Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 11:23:32 +0100 Subject: [PATCH 2/8] Use `Map.prototype.getOrInsert()` in the `#collectFieldObjects` method --- src/core/document.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index 9d65d04ac84ab..8c1696d8b0a84 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1892,10 +1892,7 @@ class PDFDocument { orphanFields.put(fieldRef, parentRef); } - if (!promises.has(name)) { - promises.set(name, []); - } - promises.get(name).push( + promises.getOrInsert(name, []).push( AnnotationFactory.create( xref, fieldRef, From 3940855511a105e5e6b1967ea85143d893282d8d Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 11:29:29 +0100 Subject: [PATCH 3/8] Use `Map.prototype.getOrInsert()` in the `_getPageAdvance` method Also, change the method to an actually private one. --- web/pdf_viewer.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index c22ede2c2c025..a3b28220a0620 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -2270,10 +2270,7 @@ class PDFViewer { this.update(); } - /** - * @private - */ - _getPageAdvance(currentPageNumber, previous = false) { + #getPageAdvance(currentPageNumber, previous = false) { switch (this._scrollMode) { case ScrollMode.WRAPPED: { const { views } = this._getVisiblePages(), @@ -2284,11 +2281,7 @@ class PDFViewer { if (percent === 0 || widthPercent < 100) { continue; } - let yArray = pageLayout.get(y); - if (!yArray) { - pageLayout.set(y, (yArray ||= [])); - } - yArray.push(id); + pageLayout.getOrInsert(y, []).push(id); } // Find the row of the current page. for (const yArray of pageLayout.values()) { @@ -2379,7 +2372,7 @@ class PDFViewer { return false; } const advance = - this._getPageAdvance(currentPageNumber, /* previous = */ false) || 1; + this.#getPageAdvance(currentPageNumber, /* previous = */ false) || 1; this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount); return true; @@ -2396,7 +2389,7 @@ class PDFViewer { return false; } const advance = - this._getPageAdvance(currentPageNumber, /* previous = */ true) || 1; + this.#getPageAdvance(currentPageNumber, /* previous = */ true) || 1; this.currentPageNumber = Math.max(currentPageNumber - advance, 1); return true; From 3e7ad8d6bf6506171d75659cfa778fcbdcce6dc1 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 11:42:42 +0100 Subject: [PATCH 4/8] Use `Map.prototype.getOrInsert()` in the `#collectParents` method --- src/core/struct_tree.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/struct_tree.js b/src/core/struct_tree.js index cdd12dfa85d7f..437d35b9a9259 100644 --- a/src/core/struct_tree.js +++ b/src/core/struct_tree.js @@ -450,12 +450,7 @@ class StructTreeRoot { for (const element of elements) { if (element.structTreeParentId) { const id = parseInt(element.structTreeParentId.split("_mc")[1], 10); - let elems = idToElements.get(id); - if (!elems) { - elems = []; - idToElements.set(id, elems); - } - elems.push(element); + idToElements.getOrInsert(id, []).push(element); } } From c7bdf5b508bd0dbfb48eaf23ce9feb6fdebb8380 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 12:00:19 +0100 Subject: [PATCH 5/8] Use `Map.prototype.getOrInsertComputed()` in the `ensureDebugMetadata` helper Also, shorten the function by using optional chaining. --- src/display/canvas_dependency_tracker.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/display/canvas_dependency_tracker.js b/src/display/canvas_dependency_tracker.js index 0d391c40655de..a8cc3350565b6 100644 --- a/src/display/canvas_dependency_tracker.js +++ b/src/display/canvas_dependency_tracker.js @@ -50,17 +50,11 @@ class BBoxReader { } } -const ensureDebugMetadata = (map, key) => { - if (!map) { - return undefined; - } - let value = map.get(key); - if (!value) { - value = { dependencies: new Set(), isRenderingOperation: false }; - map.set(key, value); - } - return value; -}; +const ensureDebugMetadata = (map, key) => + map?.getOrInsertComputed(key, () => ({ + dependencies: new Set(), + isRenderingOperation: false, + })); /** * @typedef {"lineWidth" | "lineCap" | "lineJoin" | "miterLimit" | "dash" | From 0d8bc689b9ab354f719589fbafd39ceeed472464 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 13:26:20 +0100 Subject: [PATCH 6/8] Add missing license header in `src/display/canvas_dependency_tracker.js` --- src/display/canvas_dependency_tracker.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/display/canvas_dependency_tracker.js b/src/display/canvas_dependency_tracker.js index a8cc3350565b6..40c93417ba7fd 100644 --- a/src/display/canvas_dependency_tracker.js +++ b/src/display/canvas_dependency_tracker.js @@ -1,3 +1,18 @@ +/* Copyright 2025 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Util } from "../shared/util.js"; const FORCED_DEPENDENCY_LABEL = "__forcedDependency"; From 956eb1032970777db8ec81913ceb6f87a6deb6c5 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 21 Feb 2026 22:37:30 +0100 Subject: [PATCH 7/8] Use `FinalizationRegistry` unconditionally in the `src/scripting_api/app.js` file After the QuickJS update in PR 20708 this code can now be simplified. --- src/scripting_api/app.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/scripting_api/app.js b/src/scripting_api/app.js index 3c8619615d421..1680686bc5759 100644 --- a/src/scripting_api/app.js +++ b/src/scripting_api/app.js @@ -52,18 +52,14 @@ class App extends PDFObject { ); this._timeoutIds = new WeakMap(); - if (typeof FinalizationRegistry !== "undefined") { - // About setTimeOut/setInterval return values (specs): - // The return value of this method must be held in a - // JavaScript variable. - // Otherwise, the timeout object is subject to garbage-collection, - // which would cause the clock to stop. - this._timeoutIdsRegistry = new FinalizationRegistry( - this._cleanTimeout.bind(this) - ); - } else { - this._timeoutIdsRegistry = null; - } + // About setTimeOut/setInterval return values (specs): + // The return value of this method must be held in a + // JavaScript variable. + // Otherwise, the timeout object is subject to garbage-collection, + // which would cause the clock to stop. + this._timeoutIdsRegistry = new FinalizationRegistry( + this._cleanTimeout.bind(this) + ); this._timeoutCallbackIds = new Map(); this._timeoutCallbackId = USERACTIVATION_CALLBACKID + 1; @@ -113,12 +109,12 @@ class App extends PDFObject { const timeout = Object.create(null); const id = { callbackId, interval }; this._timeoutIds.set(timeout, id); - this._timeoutIdsRegistry?.register(timeout, id); + this._timeoutIdsRegistry.register(timeout, id); return timeout; } _unregisterTimeout(timeout) { - this._timeoutIdsRegistry?.unregister(timeout); + this._timeoutIdsRegistry.unregister(timeout); const data = this._timeoutIds.get(timeout); if (!data) { From a8b1c8bd70f616fa649761d9bba2e166a917204f Mon Sep 17 00:00:00 2001 From: calixteman Date: Sat, 21 Feb 2026 22:48:36 +0100 Subject: [PATCH 8/8] Remove the leading slash in windows file path when instrumenting js files for ccov --- test/webserver.mjs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/webserver.mjs b/test/webserver.mjs index 70b270ee01caa..ac36f1451456e 100644 --- a/test/webserver.mjs +++ b/test/webserver.mjs @@ -306,7 +306,15 @@ class WebServer { // Transform with Babel and istanbul plugin const result = babel.transformSync(content, { - filename: fileURL.pathname, + // On Windows, the file URL starts with a slash (e.g. + // /C:/path/to/file.js). + // This leading slash makes the file path invalid and causes the + // instrumentation to fail, so we need to remove it before passing the + // path. + filename: + process.platform === "win32" + ? fileURL.pathname.substring(1) + : fileURL.pathname, plugins: ["babel-plugin-istanbul"], sourceMaps: false, });