Merge pull request #16920 from Snuffleupagus/annotationGlobals

Slightly reduce asynchronicity when parsing Annotations
This commit is contained in:
Jonas Jenwald 2023-09-09 09:55:49 +02:00 committed by GitHub
commit 18a661b6a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 420 additions and 322 deletions

View file

@ -426,9 +426,12 @@ class Page {
let newAnnotationsPromise = Promise.resolve(null);
if (newAnnotationsByPage) {
let imagePromises;
const newAnnotations = newAnnotationsByPage.get(this.pageIndex);
if (newAnnotations) {
const annotationGlobalsPromise =
this.pdfManager.ensureDoc("annotationGlobals");
let imagePromises;
// An annotation can contain a reference to a bitmap, but this bitmap
// is defined in another annotation. So we need to find this annotation
// and generate the bitmap.
@ -467,11 +470,21 @@ class Page {
deletedAnnotations = new RefSet();
this.#replaceIdByRef(newAnnotations, deletedAnnotations, null);
newAnnotationsPromise = AnnotationFactory.printNewAnnotations(
partialEvaluator,
task,
newAnnotations,
imagePromises
newAnnotationsPromise = annotationGlobalsPromise.then(
annotationGlobals => {
if (!annotationGlobals) {
return null;
}
return AnnotationFactory.printNewAnnotations(
annotationGlobals,
partialEvaluator,
task,
newAnnotations,
imagePromises
);
}
);
}
}
@ -663,7 +676,7 @@ class Page {
async getAnnotationsData(handler, task, intent) {
const annotations = await this._parsedAnnotations;
if (annotations.length === 0) {
return [];
return annotations;
}
const annotationsData = [],
@ -723,16 +736,25 @@ class Page {
}
get _parsedAnnotations() {
const parsedAnnotations = this.pdfManager
const promise = this.pdfManager
.ensure(this, "annotations")
.then(() => {
.then(async annots => {
if (annots.length === 0) {
return annots;
}
const annotationGlobals =
await this.pdfManager.ensureDoc("annotationGlobals");
if (!annotationGlobals) {
return [];
}
const annotationPromises = [];
for (const annotationRef of this.annotations) {
for (const annotationRef of annots) {
annotationPromises.push(
AnnotationFactory.create(
this.xref,
annotationRef,
this.pdfManager,
annotationGlobals,
this._localIdFactory,
/* collectFields */ false,
this.ref
@ -743,34 +765,28 @@ class Page {
);
}
return Promise.all(annotationPromises).then(function (annotations) {
if (annotations.length === 0) {
return annotations;
const sortedAnnotations = [];
let popupAnnotations;
// Ensure that PopupAnnotations are handled last, since they depend on
// their parent Annotation in the display layer; fixes issue 11362.
for (const annotation of await Promise.all(annotationPromises)) {
if (!annotation) {
continue;
}
if (annotation instanceof PopupAnnotation) {
(popupAnnotations ||= []).push(annotation);
continue;
}
sortedAnnotations.push(annotation);
}
if (popupAnnotations) {
sortedAnnotations.push(...popupAnnotations);
}
const sortedAnnotations = [];
let popupAnnotations;
// Ensure that PopupAnnotations are handled last, since they depend on
// their parent Annotation in the display layer; fixes issue 11362.
for (const annotation of annotations) {
if (!annotation) {
continue;
}
if (annotation instanceof PopupAnnotation) {
(popupAnnotations ||= []).push(annotation);
continue;
}
sortedAnnotations.push(annotation);
}
if (popupAnnotations) {
sortedAnnotations.push(...popupAnnotations);
}
return sortedAnnotations;
});
return sortedAnnotations;
});
return shadow(this, "_parsedAnnotations", parsedAnnotations);
return shadow(this, "_parsedAnnotations", promise);
}
get jsActions() {
@ -1695,10 +1711,7 @@ class PDFDocument {
: clearGlobalCaches();
}
/**
* @private
*/
_collectFieldObjects(name, fieldRef, promises) {
#collectFieldObjects(name, fieldRef, promises, annotationGlobals) {
const field = this.xref.fetchIfRef(fieldRef);
if (field.has("T")) {
const partName = stringToPDFString(field.get("T"));
@ -1712,22 +1725,21 @@ class PDFDocument {
AnnotationFactory.create(
this.xref,
fieldRef,
this.pdfManager,
annotationGlobals,
this._localIdFactory,
/* collectFields */ true,
/* pageRef */ null
)
.then(annotation => annotation?.getFieldObject())
.catch(function (reason) {
warn(`_collectFieldObjects: "${reason}".`);
warn(`#collectFieldObjects: "${reason}".`);
return null;
})
);
if (field.has("Kids")) {
const kids = field.get("Kids");
for (const kid of kids) {
this._collectFieldObjects(name, kid, promises);
for (const kid of field.get("Kids")) {
this.#collectFieldObjects(name, kid, promises, annotationGlobals);
}
}
}
@ -1737,29 +1749,41 @@ class PDFDocument {
return shadow(this, "fieldObjects", Promise.resolve(null));
}
const allFields = Object.create(null);
const fieldPromises = new Map();
for (const fieldRef of this.catalog.acroForm.get("Fields")) {
this._collectFieldObjects("", fieldRef, fieldPromises);
}
const promise = this.pdfManager
.ensureDoc("annotationGlobals")
.then(async annotationGlobals => {
if (!annotationGlobals) {
return null;
}
const allPromises = [];
for (const [name, promises] of fieldPromises) {
allPromises.push(
Promise.all(promises).then(fields => {
fields = fields.filter(field => !!field);
if (fields.length > 0) {
allFields[name] = fields;
}
})
);
}
const allFields = Object.create(null);
const fieldPromises = new Map();
for (const fieldRef of this.catalog.acroForm.get("Fields")) {
this.#collectFieldObjects(
"",
fieldRef,
fieldPromises,
annotationGlobals
);
}
return shadow(
this,
"fieldObjects",
Promise.all(allPromises).then(() => allFields)
);
const allPromises = [];
for (const [name, promises] of fieldPromises) {
allPromises.push(
Promise.all(promises).then(fields => {
fields = fields.filter(field => !!field);
if (fields.length > 0) {
allFields[name] = fields;
}
})
);
}
await Promise.all(allPromises);
return allFields;
});
return shadow(this, "fieldObjects", promise);
}
get hasJSActions() {
@ -1809,6 +1833,14 @@ class PDFDocument {
}
return shadow(this, "calculationOrderIds", ids);
}
get annotationGlobals() {
return shadow(
this,
"annotationGlobals",
AnnotationFactory.createGlobals(this.pdfManager)
);
}
}
export { Page, PDFDocument };