From e3b5ed2e40365d0c60a0e0c42fccf6d94cce8398 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 8 Oct 2024 12:15:04 +0200 Subject: [PATCH 1/2] Improve the promise-caching in the `PDFDocument.fieldObjects` getter After PR 18845 we're accessing this getter more, hence it seems like a good idea to ensure that the initial `formInfo` access is covered as well. While unlikely to be a problem in practice, at least theoretically that data may not be available and the code in `fieldObjects` could thus currently be *unintentionally* invoked more than once. --- src/core/document.js | 81 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index bff44ce1e4b89..723c016e251bc 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1871,49 +1871,52 @@ class PDFDocument { } get fieldObjects() { - if (!this.formInfo.hasFields) { - return shadow(this, "fieldObjects", Promise.resolve(null)); - } + const promise = this.pdfManager + .ensureDoc("formInfo") + .then(async formInfo => { + if (!formInfo.hasFields) { + return null; + } - const promise = Promise.all([ - this.pdfManager.ensureDoc("annotationGlobals"), - this.pdfManager.ensureCatalog("acroForm"), - ]).then(async ([annotationGlobals, acroForm]) => { - if (!annotationGlobals) { - return null; - } + const [annotationGlobals, acroForm] = await Promise.all([ + this.pdfManager.ensureDoc("annotationGlobals"), + this.pdfManager.ensureCatalog("acroForm"), + ]); + if (!annotationGlobals) { + return null; + } - const visitedRefs = new RefSet(); - const allFields = Object.create(null); - const fieldPromises = new Map(); - const orphanFields = new RefSetCache(); - for (const fieldRef of await acroForm.getAsync("Fields")) { - await this.#collectFieldObjects( - "", - null, - fieldRef, - fieldPromises, - annotationGlobals, - visitedRefs, - orphanFields - ); - } + const visitedRefs = new RefSet(); + const allFields = Object.create(null); + const fieldPromises = new Map(); + const orphanFields = new RefSetCache(); + for (const fieldRef of await acroForm.getAsync("Fields")) { + await this.#collectFieldObjects( + "", + null, + fieldRef, + fieldPromises, + annotationGlobals, + visitedRefs, + orphanFields + ); + } - const allPromises = []; - for (const [name, promises] of fieldPromises) { - allPromises.push( - Promise.all(promises).then(fields => { - fields = fields.filter(field => !!field); - if (fields.length > 0) { - allFields[name] = fields; - } - }) - ); - } + const allPromises = []; + for (const [name, promises] of fieldPromises) { + allPromises.push( + Promise.all(promises).then(fields => { + fields = fields.filter(field => !!field); + if (fields.length > 0) { + allFields[name] = fields; + } + }) + ); + } - await Promise.all(allPromises); - return { allFields, orphanFields }; - }); + await Promise.all(allPromises); + return { allFields, orphanFields }; + }); return shadow(this, "fieldObjects", promise); } From 662bd022cefaa591a454f68faaac5010309e628a Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 8 Oct 2024 12:24:09 +0200 Subject: [PATCH 2/2] Reduce duplication in the `PDFDocument.calculationOrderIds` getter --- src/core/document.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index 723c016e251bc..2dab34d062000 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -1947,12 +1947,7 @@ class PDFDocument { } get calculationOrderIds() { - const acroForm = this.catalog.acroForm; - if (!acroForm?.has("CO")) { - return shadow(this, "calculationOrderIds", null); - } - - const calculationOrder = acroForm.get("CO"); + const calculationOrder = this.catalog.acroForm?.get("CO"); if (!Array.isArray(calculationOrder) || calculationOrder.length === 0) { return shadow(this, "calculationOrderIds", null); } @@ -1963,10 +1958,7 @@ class PDFDocument { ids.push(id.toString()); } } - if (ids.length === 0) { - return shadow(this, "calculationOrderIds", null); - } - return shadow(this, "calculationOrderIds", ids); + return shadow(this, "calculationOrderIds", ids.length ? ids : null); } get annotationGlobals() {