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.
This commit is contained in:
Tim van der Meij 2020-08-22 23:33:19 +02:00
parent b41a2f4d5a
commit f20f0bcc78
No known key found for this signature in database
GPG Key ID: 8C3FD2925A5F2762
4 changed files with 29 additions and 19 deletions

View File

@ -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,

View File

@ -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,
};

View File

@ -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)) {

View File

@ -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);
}
}