Fix missing annotation parent in using the one from the Fields entry
Fixes #15096.
This commit is contained in:
parent
7c1883a839
commit
3103deaa44
@ -112,6 +112,7 @@ class AnnotationFactory {
|
|||||||
* @params {Object} annotationGlobals
|
* @params {Object} annotationGlobals
|
||||||
* @param {Object} idFactory
|
* @param {Object} idFactory
|
||||||
* @param {boolean} [collectFields]
|
* @param {boolean} [collectFields]
|
||||||
|
* @param {Object} [orphanFields]
|
||||||
* @param {Object} [pageRef]
|
* @param {Object} [pageRef]
|
||||||
* @returns {Promise} A promise that is resolved with an {Annotation}
|
* @returns {Promise} A promise that is resolved with an {Annotation}
|
||||||
* instance.
|
* instance.
|
||||||
@ -122,6 +123,7 @@ class AnnotationFactory {
|
|||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
idFactory,
|
idFactory,
|
||||||
collectFields,
|
collectFields,
|
||||||
|
orphanFields,
|
||||||
pageRef
|
pageRef
|
||||||
) {
|
) {
|
||||||
const pageIndex = collectFields
|
const pageIndex = collectFields
|
||||||
@ -134,6 +136,7 @@ class AnnotationFactory {
|
|||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
idFactory,
|
idFactory,
|
||||||
collectFields,
|
collectFields,
|
||||||
|
orphanFields,
|
||||||
pageIndex,
|
pageIndex,
|
||||||
pageRef,
|
pageRef,
|
||||||
]);
|
]);
|
||||||
@ -148,6 +151,7 @@ class AnnotationFactory {
|
|||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
idFactory,
|
idFactory,
|
||||||
collectFields = false,
|
collectFields = false,
|
||||||
|
orphanFields = null,
|
||||||
pageIndex = null,
|
pageIndex = null,
|
||||||
pageRef = null
|
pageRef = null
|
||||||
) {
|
) {
|
||||||
@ -173,6 +177,7 @@ class AnnotationFactory {
|
|||||||
id,
|
id,
|
||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
collectFields,
|
collectFields,
|
||||||
|
orphanFields,
|
||||||
needAppearances:
|
needAppearances:
|
||||||
!collectFields && acroForm.get("NeedAppearances") === true,
|
!collectFields && acroForm.get("NeedAppearances") === true,
|
||||||
pageIndex,
|
pageIndex,
|
||||||
@ -623,7 +628,11 @@ function getTransformMatrix(rect, bbox, matrix) {
|
|||||||
|
|
||||||
class Annotation {
|
class Annotation {
|
||||||
constructor(params) {
|
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.setTitle(dict.get("T"));
|
||||||
this.setContents(dict.get("Contents"));
|
this.setContents(dict.get("Contents"));
|
||||||
@ -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("AS", name);
|
||||||
dict.set("M", `D:${getModificationDate()}`);
|
dict.set("M", `D:${getModificationDate()}`);
|
||||||
if (flags !== undefined) {
|
if (flags !== undefined) {
|
||||||
|
|||||||
@ -787,12 +787,16 @@ class Page {
|
|||||||
if (annots.length === 0) {
|
if (annots.length === 0) {
|
||||||
return annots;
|
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) {
|
if (!annotationGlobals) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const orphanFields = fieldObjects?.orphanFields;
|
||||||
const annotationPromises = [];
|
const annotationPromises = [];
|
||||||
for (const annotationRef of annots) {
|
for (const annotationRef of annots) {
|
||||||
annotationPromises.push(
|
annotationPromises.push(
|
||||||
@ -802,6 +806,7 @@ class Page {
|
|||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
this._localIdFactory,
|
this._localIdFactory,
|
||||||
/* collectFields */ false,
|
/* collectFields */ false,
|
||||||
|
orphanFields,
|
||||||
this.ref
|
this.ref
|
||||||
).catch(function (reason) {
|
).catch(function (reason) {
|
||||||
warn(`_parsedAnnotations: "${reason}".`);
|
warn(`_parsedAnnotations: "${reason}".`);
|
||||||
@ -1776,10 +1781,12 @@ class PDFDocument {
|
|||||||
|
|
||||||
async #collectFieldObjects(
|
async #collectFieldObjects(
|
||||||
name,
|
name,
|
||||||
|
parentRef,
|
||||||
fieldRef,
|
fieldRef,
|
||||||
promises,
|
promises,
|
||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
visitedRefs
|
visitedRefs,
|
||||||
|
orphanFields
|
||||||
) {
|
) {
|
||||||
const { xref } = this;
|
const { xref } = this;
|
||||||
|
|
||||||
@ -1797,7 +1804,7 @@ class PDFDocument {
|
|||||||
} else {
|
} else {
|
||||||
let obj = field;
|
let obj = field;
|
||||||
while (true) {
|
while (true) {
|
||||||
obj = obj.getRaw("Parent");
|
obj = obj.getRaw("Parent") || parentRef;
|
||||||
if (obj instanceof Ref) {
|
if (obj instanceof Ref) {
|
||||||
if (visitedRefs.has(obj)) {
|
if (visitedRefs.has(obj)) {
|
||||||
break;
|
break;
|
||||||
@ -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)) {
|
if (!promises.has(name)) {
|
||||||
promises.set(name, []);
|
promises.set(name, []);
|
||||||
}
|
}
|
||||||
@ -1825,6 +1841,7 @@ class PDFDocument {
|
|||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
/* idFactory = */ null,
|
/* idFactory = */ null,
|
||||||
/* collectFields */ true,
|
/* collectFields */ true,
|
||||||
|
orphanFields,
|
||||||
/* pageRef */ null
|
/* pageRef */ null
|
||||||
)
|
)
|
||||||
.then(annotation => annotation?.getFieldObject())
|
.then(annotation => annotation?.getFieldObject())
|
||||||
@ -1842,10 +1859,12 @@ class PDFDocument {
|
|||||||
for (const kid of kids) {
|
for (const kid of kids) {
|
||||||
await this.#collectFieldObjects(
|
await this.#collectFieldObjects(
|
||||||
name,
|
name,
|
||||||
|
fieldRef,
|
||||||
kid,
|
kid,
|
||||||
promises,
|
promises,
|
||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
visitedRefs
|
visitedRefs,
|
||||||
|
orphanFields
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1867,13 +1886,16 @@ class PDFDocument {
|
|||||||
const visitedRefs = new RefSet();
|
const visitedRefs = new RefSet();
|
||||||
const allFields = Object.create(null);
|
const allFields = Object.create(null);
|
||||||
const fieldPromises = new Map();
|
const fieldPromises = new Map();
|
||||||
|
const orphanFields = new RefSetCache();
|
||||||
for (const fieldRef of await acroForm.getAsync("Fields")) {
|
for (const fieldRef of await acroForm.getAsync("Fields")) {
|
||||||
await this.#collectFieldObjects(
|
await this.#collectFieldObjects(
|
||||||
"",
|
"",
|
||||||
|
null,
|
||||||
fieldRef,
|
fieldRef,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
annotationGlobals,
|
annotationGlobals,
|
||||||
visitedRefs
|
visitedRefs,
|
||||||
|
orphanFields
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1890,7 +1912,7 @@ class PDFDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(allPromises);
|
await Promise.all(allPromises);
|
||||||
return allFields;
|
return { allFields, orphanFields };
|
||||||
});
|
});
|
||||||
|
|
||||||
return shadow(this, "fieldObjects", promise);
|
return shadow(this, "fieldObjects", promise);
|
||||||
@ -1914,7 +1936,7 @@ class PDFDocument {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (fieldObjects) {
|
if (fieldObjects) {
|
||||||
return Object.values(fieldObjects).some(fieldObject =>
|
return Object.values(fieldObjects.allFields).some(fieldObject =>
|
||||||
fieldObject.some(object => object.actions !== null)
|
fieldObject.some(object => object.actions !== null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -522,7 +522,9 @@ class WorkerMessageHandler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
handler.on("GetFieldObjects", function (data) {
|
handler.on("GetFieldObjects", function (data) {
|
||||||
return pdfManager.ensureDoc("fieldObjects");
|
return pdfManager
|
||||||
|
.ensureDoc("fieldObjects")
|
||||||
|
.then(fieldObjects => fieldObjects?.allFields || null);
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.on("HasJSActions", function (data) {
|
handler.on("HasJSActions", function (data) {
|
||||||
|
|||||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -673,3 +673,4 @@
|
|||||||
!highlight_popup.pdf
|
!highlight_popup.pdf
|
||||||
!issue18072.pdf
|
!issue18072.pdf
|
||||||
!stamps.pdf
|
!stamps.pdf
|
||||||
|
!issue15096.pdf
|
||||||
|
|||||||
BIN
test/pdfs/issue15096.pdf
Executable file
BIN
test/pdfs/issue15096.pdf
Executable file
Binary file not shown.
@ -10667,5 +10667,22 @@
|
|||||||
"popupRef": "44R"
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -250,7 +250,7 @@ describe("document", function () {
|
|||||||
|
|
||||||
acroForm.set("Fields", [parentRef]);
|
acroForm.set("Fields", [parentRef]);
|
||||||
pdfDocument = getDocument(acroForm, xref);
|
pdfDocument = getDocument(acroForm, xref);
|
||||||
fields = await pdfDocument.fieldObjects;
|
fields = (await pdfDocument.fieldObjects).allFields;
|
||||||
|
|
||||||
for (const [name, objs] of Object.entries(fields)) {
|
for (const [name, objs] of Object.entries(fields)) {
|
||||||
fields[name] = objs.map(obj => obj.id);
|
fields[name] = objs.map(obj => obj.id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user