Use Map.prototype.getOrInsertComputed in the scripting implementation

This adds a basic non-MOZCENTRAL polyfill for now, which we should be able to remove once the next QuickJS version is released; note the pending changelog at f1139494d1/Changelog (L7)
This commit is contained in:
Jonas Jenwald 2026-03-07 12:41:23 +01:00
parent ca428aadae
commit 49e8240c19
2 changed files with 35 additions and 25 deletions

View File

@ -26,6 +26,11 @@ function serializeError(error) {
return { command: "error", value }; return { command: "error", value };
} }
// Helpers for simple `Map.prototype.getOrInsertComputed()` invocations,
// to avoid duplicate function creation.
const makeArr = () => [];
const makeMap = () => new Map();
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) { if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
// TODO: Remove this once `Math.sumPrecise` is supported in QuickJS. // TODO: Remove this once `Math.sumPrecise` is supported in QuickJS.
// //
@ -36,10 +41,24 @@ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
return numbers.reduce((a, b) => a + b, 0); return numbers.reduce((a, b) => a + b, 0);
}; };
} }
// TODO: Remove this once `Map.prototype.getOrInsertComputed` is supported in
// QuickJS.
if (typeof Map.prototype.getOrInsertComputed !== "function") {
// eslint-disable-next-line no-extend-native
Map.prototype.getOrInsertComputed = function (key, callbackFn) {
if (!this.has(key)) {
this.set(key, callbackFn(key));
}
return this.get(key);
};
}
} }
export { export {
FORMS_VERSION, FORMS_VERSION,
makeArr,
makeMap,
serializeError, serializeError,
USERACTIVATION_CALLBACKID, USERACTIVATION_CALLBACKID,
USERACTIVATION_MAXTIME_VALIDITY, USERACTIVATION_MAXTIME_VALIDITY,

View File

@ -13,10 +13,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { makeArr, makeMap, serializeError } from "./app_utils.js";
import { createActionsMap } from "./common.js"; import { createActionsMap } from "./common.js";
import { PDFObject } from "./pdf_object.js"; import { PDFObject } from "./pdf_object.js";
import { PrintParams } from "./print_params.js"; import { PrintParams } from "./print_params.js";
import { serializeError } from "./app_utils.js";
import { ZoomType } from "./constants.js"; import { ZoomType } from "./constants.js";
const DOC_EXTERNAL = false; const DOC_EXTERNAL = false;
@ -32,6 +32,10 @@ class InfoProxyHandler {
} }
class Doc extends PDFObject { class Doc extends PDFObject {
#pageActions = null;
#otherPageActions = null;
constructor(data) { constructor(data) {
super(data); super(data);
@ -96,11 +100,9 @@ class Doc extends PDFObject {
this._zoom = data.zoom || 100; this._zoom = data.zoom || 100;
this._actions = createActionsMap(data.actions); this._actions = createActionsMap(data.actions);
this._globalEval = data.globalEval; this._globalEval = data.globalEval;
this._pageActions = null;
this._userActivation = false; this._userActivation = false;
this._disablePrinting = false; this._disablePrinting = false;
this._disableSaving = false; this._disableSaving = false;
this._otherPageActions = null;
} }
_initActions() { _initActions() {
@ -170,14 +172,14 @@ class Doc extends PDFObject {
_dispatchPageEvent(name, actions, pageNumber) { _dispatchPageEvent(name, actions, pageNumber) {
if (name === "PageOpen") { if (name === "PageOpen") {
this._pageActions ||= new Map(); this.#pageActions ??= new Map();
if (!this._pageActions.has(pageNumber)) { if (!this.#pageActions.has(pageNumber)) {
this._pageActions.set(pageNumber, createActionsMap(actions)); this.#pageActions.set(pageNumber, createActionsMap(actions));
} }
this._pageNum = pageNumber - 1; this._pageNum = pageNumber - 1;
} }
for (const acts of [this._pageActions, this._otherPageActions]) { for (const acts of [this.#pageActions, this.#otherPageActions]) {
actions = acts?.get(pageNumber)?.get(name); actions = acts?.get(pageNumber)?.get(name);
if (actions) { if (actions) {
for (const action of actions) { for (const action of actions) {
@ -212,27 +214,16 @@ class Doc extends PDFObject {
const po = field.obj._actions.get("PageOpen"); const po = field.obj._actions.get("PageOpen");
const pc = field.obj._actions.get("PageClose"); const pc = field.obj._actions.get("PageClose");
if (po || pc) { if (po || pc) {
this._otherPageActions ||= new Map(); this.#otherPageActions ??= new Map();
let actions = this._otherPageActions.get(field.obj._page + 1); const actions = this.#otherPageActions.getOrInsertComputed(
if (!actions) { field.obj._page + 1,
actions = new Map(); makeMap
this._otherPageActions.set(field.obj._page + 1, actions); );
}
if (po) { if (po) {
let poActions = actions.get("PageOpen"); actions.getOrInsertComputed("PageOpen", makeArr).push(...po);
if (!poActions) {
poActions = [];
actions.set("PageOpen", poActions);
}
poActions.push(...po);
} }
if (pc) { if (pc) {
let pcActions = actions.get("PageClose"); actions.getOrInsertComputed("PageClose", makeArr).push(...pc);
if (!pcActions) {
pcActions = [];
actions.set("PageClose", pcActions);
}
pcActions.push(...pc);
} }
} }
} }