From f20f0bcc78c43dac8b100192419b6b3111bd5696 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sat, 22 Aug 2020 23:33:19 +0200 Subject: [PATCH] Move the AcroForm logic from the document to the catalog The `AcroForm` entry is part of the catalog, not of the document, so its logic should be placed there instead. The document should look in the catalog to fetch it, and not have knowledge of `catDict`, which is a member internal to the catalog. Moreover, make the AcroForm member private on the document instance. It's only used internally and was also never intended to be public. For users it's exposed by the `getMetadata` API endpoint as `IsAcroFormPresent`. Only a boolean is exposed, so we now also only store the boolean on the document instance. Finally, the annotation code needs access to the full AcroForm dictionary, so it's updated to fetch the data from the catalog instead of the document that now only holds the boolean. --- src/core/annotation.js | 2 +- src/core/document.js | 22 +++++++--------------- src/core/obj.js | 16 ++++++++++++++++ test/unit/annotation_spec.js | 8 +++++--- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/core/annotation.js b/src/core/annotation.js index 5fe3d8654..8c1b8eaa3 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -51,7 +51,7 @@ class AnnotationFactory { * instance. */ static create(xref, ref, pdfManager, idFactory) { - return pdfManager.ensureDoc("acroForm").then(acroForm => { + return pdfManager.ensureCatalog("acroForm").then(acroForm => { return pdfManager.ensure(this, "_create", [ xref, ref, diff --git a/src/core/document.js b/src/core/document.js index 4513ae71d..98ef34638 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -584,21 +584,13 @@ class PDFDocument { } // Check if AcroForms are present in the document. - try { - this.acroForm = this.catalog.catDict.get("AcroForm"); - if (this.acroForm) { - this.xfa = this.acroForm.get("XFA"); - const fields = this.acroForm.get("Fields"); - if ((!Array.isArray(fields) || fields.length === 0) && !this.xfa) { - this.acroForm = null; // No fields and no XFA, so it's not a form. - } + this._hasAcroForm = !!this.catalog.acroForm; + if (this._hasAcroForm) { + this.xfa = this.catalog.acroForm.get("XFA"); + const fields = this.catalog.acroForm.get("Fields"); + if ((!Array.isArray(fields) || fields.length === 0) && !this.xfa) { + this._hasAcroForm = false; // No fields and no XFA, so it's not a form. } - } catch (ex) { - if (ex instanceof MissingDataException) { - throw ex; - } - info("Cannot fetch AcroForm entry; assuming no AcroForms are present"); - this.acroForm = null; } } @@ -730,7 +722,7 @@ class PDFDocument { const docInfo = { PDFFormatVersion: version, IsLinearized: !!this.linearization, - IsAcroFormPresent: !!this.acroForm, + IsAcroFormPresent: this._hasAcroForm, IsXFAPresent: !!this.xfa, IsCollectionPresent: !!this.catalog.collection, }; diff --git a/src/core/obj.js b/src/core/obj.js index eaf885a7f..e7d8303a0 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -100,6 +100,22 @@ class Catalog { return shadow(this, "collection", collection); } + get acroForm() { + let acroForm = null; + try { + const obj = this.catDict.get("AcroForm"); + if (isDict(obj) && obj.size > 0) { + acroForm = obj; + } + } catch (ex) { + if (ex instanceof MissingDataException) { + throw ex; + } + info("Cannot fetch AcroForm entry; assuming no forms are present."); + } + return shadow(this, "acroForm", acroForm); + } + get metadata() { const streamRef = this.catDict.getRaw("Metadata"); if (!isRef(streamRef)) { diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index f948a926d..d7fef39bf 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -41,7 +41,9 @@ describe("annotation", function () { constructor(params) { this.docBaseUrl = params.docBaseUrl || null; this.pdfDocument = { - acroForm: new Dict(), + catalog: { + acroForm: new Dict(), + }, }; } @@ -56,8 +58,8 @@ describe("annotation", function () { }); } - ensureDoc(prop, args) { - return this.ensure(this.pdfDocument, prop, args); + ensureCatalog(prop, args) { + return this.ensure(this.pdfDocument.catalog, prop, args); } }