Skip to content

Commit

Permalink
Fix missing annotation parent in using the one from the Fields entry
Browse files Browse the repository at this point in the history
Fixes #15096.
  • Loading branch information
calixteman committed Oct 4, 2024
1 parent 7c1883a commit 3103dea
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 11 deletions.
16 changes: 15 additions & 1 deletion src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class AnnotationFactory {
* @params {Object} annotationGlobals
* @param {Object} idFactory
* @param {boolean} [collectFields]
* @param {Object} [orphanFields]
* @param {Object} [pageRef]
* @returns {Promise} A promise that is resolved with an {Annotation}
* instance.
Expand All @@ -122,6 +123,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields,
orphanFields,
pageRef
) {
const pageIndex = collectFields
Expand All @@ -134,6 +136,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields,
orphanFields,
pageIndex,
pageRef,
]);
Expand All @@ -148,6 +151,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields = false,
orphanFields = null,
pageIndex = null,
pageRef = null
) {
Expand All @@ -173,6 +177,7 @@ class AnnotationFactory {
id,
annotationGlobals,
collectFields,
orphanFields,
needAppearances:
!collectFields && acroForm.get("NeedAppearances") === true,
pageIndex,
Expand Down Expand Up @@ -623,7 +628,11 @@ function getTransformMatrix(rect, bbox, matrix) {

class Annotation {
constructor(params) {
const { dict, xref, annotationGlobals } = params;
const { dict, xref, annotationGlobals, ref, orphanFields } = params;
const parentRef = orphanFields?.get(ref);
if (parentRef) {
dict.set("Parent", parentRef);
}

this.setTitle(dict.get("T"));
this.setContents(dict.get("Contents"));
Expand Down Expand Up @@ -3172,6 +3181,11 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
}
}

if (!this.parent) {
// If there is no parent then we must set the value in the field.
dict.set("V", name);
}

dict.set("AS", name);
dict.set("M", `D:${getModificationDate()}`);
if (flags !== undefined) {
Expand Down
38 changes: 30 additions & 8 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -787,12 +787,16 @@ class Page {
if (annots.length === 0) {
return annots;
}
const annotationGlobals =
await this.pdfManager.ensureDoc("annotationGlobals");

const [annotationGlobals, fieldObjects] = await Promise.all([
this.pdfManager.ensureDoc("annotationGlobals"),
this.pdfManager.ensureDoc("fieldObjects"),
]);
if (!annotationGlobals) {
return [];
}

const orphanFields = fieldObjects?.orphanFields;
const annotationPromises = [];
for (const annotationRef of annots) {
annotationPromises.push(
Expand All @@ -802,6 +806,7 @@ class Page {
annotationGlobals,
this._localIdFactory,
/* collectFields */ false,
orphanFields,
this.ref
).catch(function (reason) {
warn(`_parsedAnnotations: "${reason}".`);
Expand Down Expand Up @@ -1776,10 +1781,12 @@ class PDFDocument {

async #collectFieldObjects(
name,
parentRef,
fieldRef,
promises,
annotationGlobals,
visitedRefs
visitedRefs,
orphanFields
) {
const { xref } = this;

Expand All @@ -1797,7 +1804,7 @@ class PDFDocument {
} else {
let obj = field;
while (true) {
obj = obj.getRaw("Parent");
obj = obj.getRaw("Parent") || parentRef;
if (obj instanceof Ref) {
if (visitedRefs.has(obj)) {
break;
Expand All @@ -1815,6 +1822,15 @@ class PDFDocument {
}
}

if (
parentRef &&
!field.has("Parent") &&
isName(field.get("Subtype"), "Widget")
) {
// We've a parent from the Fields array, but the field hasn't.
orphanFields.put(fieldRef, parentRef);
}

if (!promises.has(name)) {
promises.set(name, []);
}
Expand All @@ -1825,6 +1841,7 @@ class PDFDocument {
annotationGlobals,
/* idFactory = */ null,
/* collectFields */ true,
orphanFields,
/* pageRef */ null
)
.then(annotation => annotation?.getFieldObject())
Expand All @@ -1842,10 +1859,12 @@ class PDFDocument {
for (const kid of kids) {
await this.#collectFieldObjects(
name,
fieldRef,
kid,
promises,
annotationGlobals,
visitedRefs
visitedRefs,
orphanFields
);
}
}
Expand All @@ -1867,13 +1886,16 @@ class PDFDocument {
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
visitedRefs,
orphanFields
);
}

Expand All @@ -1890,7 +1912,7 @@ class PDFDocument {
}

await Promise.all(allPromises);
return allFields;
return { allFields, orphanFields };
});

return shadow(this, "fieldObjects", promise);
Expand All @@ -1914,7 +1936,7 @@ class PDFDocument {
return true;
}
if (fieldObjects) {
return Object.values(fieldObjects).some(fieldObject =>
return Object.values(fieldObjects.allFields).some(fieldObject =>
fieldObject.some(object => object.actions !== null)
);
}
Expand Down
4 changes: 3 additions & 1 deletion src/core/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,9 @@ class WorkerMessageHandler {
});

handler.on("GetFieldObjects", function (data) {
return pdfManager.ensureDoc("fieldObjects");
return pdfManager
.ensureDoc("fieldObjects")
.then(fieldObjects => fieldObjects?.allFields || null);
});

handler.on("HasJSActions", function (data) {
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -673,3 +673,4 @@
!highlight_popup.pdf
!issue18072.pdf
!stamps.pdf
!issue15096.pdf
Binary file added test/pdfs/issue15096.pdf
Binary file not shown.
17 changes: 17 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10667,5 +10667,22 @@
"popupRef": "44R"
}
}
},
{
"id": "issue15096",
"file": "pdfs/issue15096.pdf",
"md5": "5c3515177acd6e146d177adac802277d",
"rounds": 1,
"type": "eq",
"save": true,
"annotations": true,
"annotationStorage": {
"62R": {
"value": true
},
"66R": {
"value": false
}
}
}
]
2 changes: 1 addition & 1 deletion test/unit/document_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ describe("document", function () {

acroForm.set("Fields", [parentRef]);
pdfDocument = getDocument(acroForm, xref);
fields = await pdfDocument.fieldObjects;
fields = (await pdfDocument.fieldObjects).allFields;

for (const [name, objs] of Object.entries(fields)) {
fields[name] = objs.map(obj => obj.id);
Expand Down

0 comments on commit 3103dea

Please sign in to comment.