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 3, 2024
1 parent ebbd019 commit 84bf34f
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 11 deletions.
15 changes: 14 additions & 1 deletion src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields,
orphanFields,
pageRef
) {
const pageIndex = collectFields
Expand All @@ -134,6 +135,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields,
orphanFields,
pageIndex,
pageRef,
]);
Expand All @@ -148,6 +150,7 @@ class AnnotationFactory {
annotationGlobals,
idFactory,
collectFields = false,
orphanFields = null,
pageIndex = null,
pageRef = null
) {
Expand All @@ -173,6 +176,7 @@ class AnnotationFactory {
id,
annotationGlobals,
collectFields,
orphanFields,
needAppearances:
!collectFields && acroForm.get("NeedAppearances") === true,
pageIndex,
Expand Down Expand Up @@ -623,7 +627,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 +3180,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
31 changes: 25 additions & 6 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ class Page {
return [];
}

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

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

Expand All @@ -1797,7 +1801,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 +1819,15 @@ class PDFDocument {
}
}

if (
parentRef &&
field.get("Subtype") === Name.get("Widget") &&
!field.getRaw("Parent")
) {
// 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 +1838,7 @@ class PDFDocument {
annotationGlobals,
/* idFactory = */ null,
/* collectFields */ true,
orphanFields,
/* pageRef */ null
)
.then(annotation => annotation?.getFieldObject())
Expand All @@ -1842,10 +1856,12 @@ class PDFDocument {
for (const kid of kids) {
await this.#collectFieldObjects(
name,
fieldRef,
kid,
promises,
annotationGlobals,
visitedRefs
visitedRefs,
orphanFields
);
}
}
Expand All @@ -1867,13 +1883,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 +1909,7 @@ class PDFDocument {
}

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

return shadow(this, "fieldObjects", promise);
Expand All @@ -1914,7 +1933,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
}
}
}
]
6 changes: 3 additions & 3 deletions test/unit/document_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,12 @@ describe("document", function () {
const acroForm = new Dict();

let pdfDocument = getDocument(acroForm);
let fields = await pdfDocument.fieldObjects;
let fields = (await pdfDocument.fieldObjects) || null;
expect(fields).toEqual(null);

acroForm.set("Fields", []);
pdfDocument = getDocument(acroForm);
fields = await pdfDocument.fieldObjects;
fields = (await pdfDocument.fieldObjects) || null;
expect(fields).toEqual(null);

const kid1Ref = Ref.get(314, 0);
Expand Down 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 84bf34f

Please sign in to comment.