Skip to content

Commit aaf9b3b

Browse files
Merge pull request #20821 from Snuffleupagus/scripting-sumPrecise-upsert
Use `Math.sumPrecise` and `Map.prototype.getOrInsertComputed` in the scripting implementation
2 parents d34a15e + 49e8240 commit aaf9b3b

3 files changed

Lines changed: 49 additions & 27 deletions

File tree

src/scripting_api/aform.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ class AForm {
368368

369369
AFSimple_Calculate(cFunction, cFields) {
370370
const actions = {
371-
AVG: args => args.reduce((acc, value) => acc + value, 0) / args.length,
372-
SUM: args => args.reduce((acc, value) => acc + value, 0),
371+
AVG: args => Math.sumPrecise(args) / args.length,
372+
SUM: args => Math.sumPrecise(args),
373373
PRD: args => args.reduce((acc, value) => acc * value, 1),
374374
MIN: args => Math.min(...args),
375375
MAX: args => Math.max(...args),

src/scripting_api/app_utils.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,39 @@ function serializeError(error) {
2626
return { command: "error", value };
2727
}
2828

29+
// Helpers for simple `Map.prototype.getOrInsertComputed()` invocations,
30+
// to avoid duplicate function creation.
31+
const makeArr = () => [];
32+
const makeMap = () => new Map();
33+
34+
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
35+
// TODO: Remove this once `Math.sumPrecise` is supported in QuickJS.
36+
//
37+
// Note that this isn't a "proper" polyfill, but since we're only using it to
38+
// replace `Array.prototype.reduce()` invocations it should be fine.
39+
if (typeof Math.sumPrecise !== "function") {
40+
Math.sumPrecise = function (numbers) {
41+
return numbers.reduce((a, b) => a + b, 0);
42+
};
43+
}
44+
45+
// TODO: Remove this once `Map.prototype.getOrInsertComputed` is supported in
46+
// QuickJS.
47+
if (typeof Map.prototype.getOrInsertComputed !== "function") {
48+
// eslint-disable-next-line no-extend-native
49+
Map.prototype.getOrInsertComputed = function (key, callbackFn) {
50+
if (!this.has(key)) {
51+
this.set(key, callbackFn(key));
52+
}
53+
return this.get(key);
54+
};
55+
}
56+
}
57+
2958
export {
3059
FORMS_VERSION,
60+
makeArr,
61+
makeMap,
3162
serializeError,
3263
USERACTIVATION_CALLBACKID,
3364
USERACTIVATION_MAXTIME_VALIDITY,

src/scripting_api/doc.js

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
* limitations under the License.
1414
*/
1515

16+
import { makeArr, makeMap, serializeError } from "./app_utils.js";
1617
import { createActionsMap } from "./common.js";
1718
import { PDFObject } from "./pdf_object.js";
1819
import { PrintParams } from "./print_params.js";
19-
import { serializeError } from "./app_utils.js";
2020
import { ZoomType } from "./constants.js";
2121

2222
const DOC_EXTERNAL = false;
@@ -32,6 +32,10 @@ class InfoProxyHandler {
3232
}
3333

3434
class Doc extends PDFObject {
35+
#pageActions = null;
36+
37+
#otherPageActions = null;
38+
3539
constructor(data) {
3640
super(data);
3741

@@ -96,11 +100,9 @@ class Doc extends PDFObject {
96100
this._zoom = data.zoom || 100;
97101
this._actions = createActionsMap(data.actions);
98102
this._globalEval = data.globalEval;
99-
this._pageActions = null;
100103
this._userActivation = false;
101104
this._disablePrinting = false;
102105
this._disableSaving = false;
103-
this._otherPageActions = null;
104106
}
105107

106108
_initActions() {
@@ -170,14 +172,14 @@ class Doc extends PDFObject {
170172

171173
_dispatchPageEvent(name, actions, pageNumber) {
172174
if (name === "PageOpen") {
173-
this._pageActions ||= new Map();
174-
if (!this._pageActions.has(pageNumber)) {
175-
this._pageActions.set(pageNumber, createActionsMap(actions));
175+
this.#pageActions ??= new Map();
176+
if (!this.#pageActions.has(pageNumber)) {
177+
this.#pageActions.set(pageNumber, createActionsMap(actions));
176178
}
177179
this._pageNum = pageNumber - 1;
178180
}
179181

180-
for (const acts of [this._pageActions, this._otherPageActions]) {
182+
for (const acts of [this.#pageActions, this.#otherPageActions]) {
181183
actions = acts?.get(pageNumber)?.get(name);
182184
if (actions) {
183185
for (const action of actions) {
@@ -212,27 +214,16 @@ class Doc extends PDFObject {
212214
const po = field.obj._actions.get("PageOpen");
213215
const pc = field.obj._actions.get("PageClose");
214216
if (po || pc) {
215-
this._otherPageActions ||= new Map();
216-
let actions = this._otherPageActions.get(field.obj._page + 1);
217-
if (!actions) {
218-
actions = new Map();
219-
this._otherPageActions.set(field.obj._page + 1, actions);
220-
}
217+
this.#otherPageActions ??= new Map();
218+
const actions = this.#otherPageActions.getOrInsertComputed(
219+
field.obj._page + 1,
220+
makeMap
221+
);
221222
if (po) {
222-
let poActions = actions.get("PageOpen");
223-
if (!poActions) {
224-
poActions = [];
225-
actions.set("PageOpen", poActions);
226-
}
227-
poActions.push(...po);
223+
actions.getOrInsertComputed("PageOpen", makeArr).push(...po);
228224
}
229225
if (pc) {
230-
let pcActions = actions.get("PageClose");
231-
if (!pcActions) {
232-
pcActions = [];
233-
actions.set("PageClose", pcActions);
234-
}
235-
pcActions.push(...pc);
226+
actions.getOrInsertComputed("PageClose", makeArr).push(...pc);
236227
}
237228
}
238229
}

0 commit comments

Comments
 (0)