mirror of
https://github.com/zen-browser/pdf.js.git
synced 2025-07-09 17:55:37 +02:00
Merge pull request #16920 from Snuffleupagus/annotationGlobals
Slightly reduce asynchronicity when parsing Annotations
This commit is contained in:
commit
18a661b6a0
5 changed files with 420 additions and 322 deletions
|
@ -67,6 +67,35 @@ import { writeObject } from "./writer.js";
|
|||
import { XFAFactory } from "./xfa/factory.js";
|
||||
|
||||
class AnnotationFactory {
|
||||
static createGlobals(pdfManager) {
|
||||
return Promise.all([
|
||||
pdfManager.ensureCatalog("acroForm"),
|
||||
pdfManager.ensureDoc("xfaDatasets"),
|
||||
pdfManager.ensureCatalog("structTreeRoot"),
|
||||
// Only necessary to prevent the `Catalog.baseUrl`-getter, used
|
||||
// with some Annotations, from throwing and thus breaking parsing:
|
||||
pdfManager.ensureCatalog("baseUrl"),
|
||||
// Only necessary to prevent the `Catalog.attachments`-getter, used
|
||||
// with "GoToE" actions, from throwing and thus breaking parsing:
|
||||
pdfManager.ensureCatalog("attachments"),
|
||||
]).then(
|
||||
([acroForm, xfaDatasets, structTreeRoot, baseUrl, attachments]) => {
|
||||
return {
|
||||
pdfManager,
|
||||
acroForm: acroForm instanceof Dict ? acroForm : Dict.empty,
|
||||
xfaDatasets,
|
||||
structTreeRoot,
|
||||
baseUrl,
|
||||
attachments,
|
||||
};
|
||||
},
|
||||
reason => {
|
||||
warn(`createGlobals: "${reason}".`);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an `Annotation` object of the correct type for the given reference
|
||||
* to an annotation dictionary. This yields a promise that is resolved when
|
||||
|
@ -74,48 +103,33 @@ class AnnotationFactory {
|
|||
*
|
||||
* @param {XRef} xref
|
||||
* @param {Object} ref
|
||||
* @param {PDFManager} pdfManager
|
||||
* @params {Object} annotationGlobals
|
||||
* @param {Object} idFactory
|
||||
* @param {boolean} collectFields
|
||||
* @param {boolean} [collectFields]
|
||||
* @param {Object} [pageRef]
|
||||
* @returns {Promise} A promise that is resolved with an {Annotation}
|
||||
* instance.
|
||||
*/
|
||||
static create(xref, ref, pdfManager, idFactory, collectFields, pageRef) {
|
||||
return Promise.all([
|
||||
pdfManager.ensureCatalog("acroForm"),
|
||||
// Only necessary to prevent the `pdfManager.docBaseUrl`-getter, used
|
||||
// with certain Annotations, from throwing and thus breaking parsing:
|
||||
pdfManager.ensureCatalog("baseUrl"),
|
||||
// Only necessary in the `Catalog.parseDestDictionary`-method,
|
||||
// when parsing "GoToE" actions:
|
||||
pdfManager.ensureCatalog("attachments"),
|
||||
pdfManager.ensureDoc("xfaDatasets"),
|
||||
collectFields ? this._getPageIndex(xref, ref, pdfManager) : -1,
|
||||
pageRef ? pdfManager.ensureCatalog("structTreeRoot") : null,
|
||||
]).then(
|
||||
([
|
||||
acroForm,
|
||||
baseUrl,
|
||||
attachments,
|
||||
xfaDatasets,
|
||||
pageIndex,
|
||||
structTreeRoot,
|
||||
]) =>
|
||||
pdfManager.ensure(this, "_create", [
|
||||
xref,
|
||||
ref,
|
||||
pdfManager,
|
||||
idFactory,
|
||||
acroForm,
|
||||
attachments,
|
||||
xfaDatasets,
|
||||
collectFields,
|
||||
pageIndex,
|
||||
structTreeRoot,
|
||||
pageRef,
|
||||
])
|
||||
);
|
||||
static async create(
|
||||
xref,
|
||||
ref,
|
||||
annotationGlobals,
|
||||
idFactory,
|
||||
collectFields,
|
||||
pageRef
|
||||
) {
|
||||
const pageIndex = collectFields
|
||||
? await this._getPageIndex(xref, ref, annotationGlobals.pdfManager)
|
||||
: null;
|
||||
|
||||
return annotationGlobals.pdfManager.ensure(this, "_create", [
|
||||
xref,
|
||||
ref,
|
||||
annotationGlobals,
|
||||
idFactory,
|
||||
pageIndex,
|
||||
pageRef,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,14 +138,9 @@ class AnnotationFactory {
|
|||
static _create(
|
||||
xref,
|
||||
ref,
|
||||
pdfManager,
|
||||
annotationGlobals,
|
||||
idFactory,
|
||||
acroForm,
|
||||
attachments = null,
|
||||
xfaDatasets,
|
||||
collectFields,
|
||||
pageIndex = -1,
|
||||
structTreeRoot = null,
|
||||
pageIndex = null,
|
||||
pageRef = null
|
||||
) {
|
||||
const dict = xref.fetchIfRef(ref);
|
||||
|
@ -139,6 +148,7 @@ class AnnotationFactory {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const { acroForm, pdfManager } = annotationGlobals;
|
||||
const id =
|
||||
ref instanceof Ref ? ref.toString() : `annot_${idFactory.createObjId()}`;
|
||||
|
||||
|
@ -146,8 +156,6 @@ class AnnotationFactory {
|
|||
let subtype = dict.get("Subtype");
|
||||
subtype = subtype instanceof Name ? subtype.name : null;
|
||||
|
||||
const acroFormDict = acroForm instanceof Dict ? acroForm : Dict.empty;
|
||||
|
||||
// Return the right annotation object based on the subtype and field type.
|
||||
const parameters = {
|
||||
xref,
|
||||
|
@ -155,16 +163,11 @@ class AnnotationFactory {
|
|||
dict,
|
||||
subtype,
|
||||
id,
|
||||
pdfManager,
|
||||
acroForm: acroFormDict,
|
||||
attachments,
|
||||
xfaDatasets,
|
||||
collectFields,
|
||||
annotationGlobals,
|
||||
needAppearances:
|
||||
!collectFields && acroFormDict.get("NeedAppearances") === true,
|
||||
pageIndex === null && acroForm.get("NeedAppearances") === true,
|
||||
pageIndex,
|
||||
evaluatorOptions: pdfManager.evaluatorOptions,
|
||||
structTreeRoot,
|
||||
pageRef,
|
||||
};
|
||||
|
||||
|
@ -241,7 +244,7 @@ class AnnotationFactory {
|
|||
return new FileAttachmentAnnotation(parameters);
|
||||
|
||||
default:
|
||||
if (!collectFields) {
|
||||
if (pageIndex === null) {
|
||||
if (!subtype) {
|
||||
warn("Annotation is missing the required /Subtype.");
|
||||
} else {
|
||||
|
@ -392,6 +395,7 @@ class AnnotationFactory {
|
|||
}
|
||||
|
||||
static async printNewAnnotations(
|
||||
annotationGlobals,
|
||||
evaluator,
|
||||
task,
|
||||
annotations,
|
||||
|
@ -410,18 +414,28 @@ class AnnotationFactory {
|
|||
switch (annotation.annotationType) {
|
||||
case AnnotationEditorType.FREETEXT:
|
||||
promises.push(
|
||||
FreeTextAnnotation.createNewPrintAnnotation(xref, annotation, {
|
||||
evaluator,
|
||||
task,
|
||||
evaluatorOptions: options,
|
||||
})
|
||||
FreeTextAnnotation.createNewPrintAnnotation(
|
||||
annotationGlobals,
|
||||
xref,
|
||||
annotation,
|
||||
{
|
||||
evaluator,
|
||||
task,
|
||||
evaluatorOptions: options,
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
case AnnotationEditorType.INK:
|
||||
promises.push(
|
||||
InkAnnotation.createNewPrintAnnotation(xref, annotation, {
|
||||
evaluatorOptions: options,
|
||||
})
|
||||
InkAnnotation.createNewPrintAnnotation(
|
||||
annotationGlobals,
|
||||
xref,
|
||||
annotation,
|
||||
{
|
||||
evaluatorOptions: options,
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
case AnnotationEditorType.STAMP:
|
||||
|
@ -438,10 +452,15 @@ class AnnotationFactory {
|
|||
image.imageStream = image.smaskStream = null;
|
||||
}
|
||||
promises.push(
|
||||
StampAnnotation.createNewPrintAnnotation(xref, annotation, {
|
||||
image,
|
||||
evaluatorOptions: options,
|
||||
})
|
||||
StampAnnotation.createNewPrintAnnotation(
|
||||
annotationGlobals,
|
||||
xref,
|
||||
annotation,
|
||||
{
|
||||
image,
|
||||
evaluatorOptions: options,
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -570,7 +589,7 @@ function getTransformMatrix(rect, bbox, matrix) {
|
|||
|
||||
class Annotation {
|
||||
constructor(params) {
|
||||
const { dict, xref } = params;
|
||||
const { dict, xref, annotationGlobals } = params;
|
||||
|
||||
this.setTitle(dict.get("T"));
|
||||
this.setContents(dict.get("Contents"));
|
||||
|
@ -598,11 +617,15 @@ class Annotation {
|
|||
const isLocked = !!(this.flags & AnnotationFlag.LOCKED);
|
||||
const isContentLocked = !!(this.flags & AnnotationFlag.LOCKEDCONTENTS);
|
||||
|
||||
if (params.structTreeRoot) {
|
||||
if (annotationGlobals.structTreeRoot) {
|
||||
let structParent = dict.get("StructParent");
|
||||
structParent =
|
||||
Number.isInteger(structParent) && structParent >= 0 ? structParent : -1;
|
||||
params.structTreeRoot.addAnnotationIdToPage(params.pageRef, structParent);
|
||||
|
||||
annotationGlobals.structTreeRoot.addAnnotationIdToPage(
|
||||
params.pageRef,
|
||||
structParent
|
||||
);
|
||||
}
|
||||
|
||||
// Expose public properties using a data object.
|
||||
|
@ -624,7 +647,7 @@ class Annotation {
|
|||
noHTML: isLocked && isContentLocked,
|
||||
};
|
||||
|
||||
if (params.collectFields) {
|
||||
if (params.pageIndex !== null) {
|
||||
// Fields can act as container for other fields and have
|
||||
// some actions even if no Annotation inherit from them.
|
||||
// Those fields can be referenced by CO (calculation order).
|
||||
|
@ -755,9 +778,11 @@ class Annotation {
|
|||
}
|
||||
|
||||
setDefaultAppearance(params) {
|
||||
const { dict, annotationGlobals } = params;
|
||||
|
||||
const defaultAppearance =
|
||||
getInheritableProperty({ dict: params.dict, key: "DA" }) ||
|
||||
params.acroForm.get("DA");
|
||||
getInheritableProperty({ dict, key: "DA" }) ||
|
||||
annotationGlobals.acroForm.get("DA");
|
||||
this._defaultAppearance =
|
||||
typeof defaultAppearance === "string" ? defaultAppearance : "";
|
||||
this.data.defaultAppearanceData = parseDefaultAppearance(
|
||||
|
@ -1634,13 +1659,19 @@ class MarkupAnnotation extends Annotation {
|
|||
return { ref: annotationRef, data: buffer.join("") };
|
||||
}
|
||||
|
||||
static async createNewPrintAnnotation(xref, annotation, params) {
|
||||
static async createNewPrintAnnotation(
|
||||
annotationGlobals,
|
||||
xref,
|
||||
annotation,
|
||||
params
|
||||
) {
|
||||
const ap = await this.createNewAppearanceStream(annotation, xref, params);
|
||||
const annotationDict = this.createNewDict(annotation, xref, { ap });
|
||||
|
||||
const newAnnotation = new this.prototype.constructor({
|
||||
dict: annotationDict,
|
||||
xref,
|
||||
annotationGlobals,
|
||||
evaluatorOptions: params.evaluatorOptions,
|
||||
});
|
||||
|
||||
|
@ -1656,7 +1687,7 @@ class WidgetAnnotation extends Annotation {
|
|||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
const { dict, xref } = params;
|
||||
const { dict, xref, annotationGlobals } = params;
|
||||
const data = this.data;
|
||||
this._needAppearances = params.needAppearances;
|
||||
|
||||
|
@ -1683,12 +1714,13 @@ class WidgetAnnotation extends Annotation {
|
|||
});
|
||||
data.defaultFieldValue = this._decodeFormValue(defaultFieldValue);
|
||||
|
||||
if (fieldValue === undefined && params.xfaDatasets) {
|
||||
if (fieldValue === undefined && annotationGlobals.xfaDatasets) {
|
||||
// Try to figure out if we have something in the xfa dataset.
|
||||
const path = this._title.str;
|
||||
if (path) {
|
||||
this._hasValueFromXFA = true;
|
||||
data.fieldValue = fieldValue = params.xfaDatasets.getValue(path);
|
||||
data.fieldValue = fieldValue =
|
||||
annotationGlobals.xfaDatasets.getValue(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1711,7 +1743,7 @@ class WidgetAnnotation extends Annotation {
|
|||
data.fieldType = fieldType instanceof Name ? fieldType.name : null;
|
||||
|
||||
const localResources = getInheritableProperty({ dict, key: "DR" });
|
||||
const acroFormResources = params.acroForm.get("DR");
|
||||
const acroFormResources = annotationGlobals.acroForm.get("DR");
|
||||
const appearanceResources = this.appearance?.dict.get("Resources");
|
||||
|
||||
this._fieldResources = {
|
||||
|
@ -3208,22 +3240,20 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
|
|||
}
|
||||
|
||||
_processPushButton(params) {
|
||||
if (
|
||||
!params.dict.has("A") &&
|
||||
!params.dict.has("AA") &&
|
||||
!this.data.alternativeText
|
||||
) {
|
||||
const { dict, annotationGlobals } = params;
|
||||
|
||||
if (!dict.has("A") && !dict.has("AA") && !this.data.alternativeText) {
|
||||
warn("Push buttons without action dictionaries are not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
this.data.isTooltipOnly = !params.dict.has("A") && !params.dict.has("AA");
|
||||
this.data.isTooltipOnly = !dict.has("A") && !dict.has("AA");
|
||||
|
||||
Catalog.parseDestDictionary({
|
||||
destDict: params.dict,
|
||||
destDict: dict,
|
||||
resultObj: this.data,
|
||||
docBaseUrl: params.pdfManager.docBaseUrl,
|
||||
docAttachments: params.attachments,
|
||||
docBaseUrl: annotationGlobals.baseUrl,
|
||||
docAttachments: annotationGlobals.attachments,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3581,9 +3611,10 @@ class LinkAnnotation extends Annotation {
|
|||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
const { dict, annotationGlobals } = params;
|
||||
this.data.annotationType = AnnotationType.LINK;
|
||||
|
||||
const quadPoints = getQuadPoints(params.dict, this.rectangle);
|
||||
const quadPoints = getQuadPoints(dict, this.rectangle);
|
||||
if (quadPoints) {
|
||||
this.data.quadPoints = quadPoints;
|
||||
}
|
||||
|
@ -3592,10 +3623,10 @@ class LinkAnnotation extends Annotation {
|
|||
this.data.borderColor ||= this.data.color;
|
||||
|
||||
Catalog.parseDestDictionary({
|
||||
destDict: params.dict,
|
||||
destDict: dict,
|
||||
resultObj: this.data,
|
||||
docBaseUrl: params.pdfManager.docBaseUrl,
|
||||
docAttachments: params.attachments,
|
||||
docBaseUrl: annotationGlobals.baseUrl,
|
||||
docAttachments: annotationGlobals.attachments,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue