Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 18 additions & 23 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import { FileSpec } from "./file_spec.js";
import { JpegStream } from "./jpeg_stream.js";
import { ObjectLoader } from "./object_loader.js";
import { OperatorList } from "./operator_list.js";
import { parseMarkedContentProps } from "./evaluator_utils.js";
import { XFAFactory } from "./xfa/factory.js";

class AnnotationFactory {
Expand Down Expand Up @@ -663,6 +664,8 @@ function getTransformMatrix(rect, bbox, matrix) {
}

class Annotation {
_oc = undefined;

constructor(params) {
const { annotationGlobals, dict, orphanFields, ref, subtype, xref } =
params;
Expand All @@ -679,7 +682,7 @@ class Annotation {
this.setColor(dict.getArray("C"));
this.setBorderStyle(dict);
this.setAppearance(dict);
this.setOptionalContent(dict);
this.#setOptionalContent(xref, dict);

const MK = dict.get("MK");
this.setBorderAndBackgroundColors(MK);
Expand Down Expand Up @@ -710,6 +713,7 @@ class Annotation {
hasAppearance: !!this.appearance,
id: params.id,
modificationDate: this.modificationDate,
oc: this._oc,
rect: this.rectangle,
subtype,
hasOwnCanvas: false,
Expand Down Expand Up @@ -1169,14 +1173,17 @@ class Annotation {
}
}

setOptionalContent(dict) {
this.oc = null;

const oc = dict.get("OC");
if (oc instanceof Name) {
warn("setOptionalContent: Support for /Name-entry is not implemented.");
} else if (oc instanceof Dict) {
this.oc = oc;
#setOptionalContent(xref, dict) {
if (dict.has("OC")) {
try {
this._oc = parseMarkedContentProps(
xref,
dict.get("OC"),
/* resources = */ null
);
} catch (ex) {
warn(`#setOptionalContent: ${ex}`);
}
}
}

Expand Down Expand Up @@ -1229,13 +1236,7 @@ class Annotation {

const opList = new OperatorList();

let optionalContent;
if (this.oc) {
optionalContent = await evaluator.parseMarkedContentProps(
this.oc,
/* resources = */ null
);
}
const optionalContent = this._oc;
if (optionalContent !== undefined) {
opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
}
Expand Down Expand Up @@ -2110,13 +2111,7 @@ class WidgetAnnotation extends Annotation {
const bbox = [0, 0, this.width, this.height];
const transform = getTransformMatrix(this.data.rect, bbox, matrix);

let optionalContent;
if (this.oc) {
optionalContent = await evaluator.parseMarkedContentProps(
this.oc,
/* resources = */ null
);
}
const optionalContent = this._oc;
if (optionalContent !== undefined) {
opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
}
Expand Down
30 changes: 16 additions & 14 deletions src/core/editor/pdf_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,27 @@ class XRefWrapper {
this._getNewRef = getNewRef;
}

fetch(ref) {
return ref instanceof Ref ? this.entries[ref.num] : ref;
getNewTemporaryRef() {
return this._getNewRef();
}

fetchIfRefAsync(ref) {
return Promise.resolve(this.fetch(ref));
fetchIfRef(obj) {
return obj instanceof Ref ? this.fetch(obj) : obj;
}

fetchIfRef(ref) {
return this.fetch(ref);
fetch(ref) {
if (!(ref instanceof Ref)) {
throw new Error("ref object is not a reference");
}
return this.entries[ref.num];
}

fetchAsync(ref) {
return Promise.resolve(this.fetch(ref));
async fetchIfRefAsync(obj) {
return obj instanceof Ref ? this.fetchAsync(obj) : obj;
}

getNewTemporaryRef() {
return this._getNewRef();
async fetchAsync(ref) {
return this.fetch(ref);
}
}

Expand Down Expand Up @@ -193,8 +196,7 @@ class PDFEditor {
* @returns {Ref}
*/
get newRef() {
const ref = Ref.get(this.newRefCount++, 0);
return ref;
return Ref.get(this.newRefCount++, 0);
}

/**
Expand Down Expand Up @@ -518,9 +520,9 @@ class PDFEditor {
attributes = [attributes];
}
for (let attr of attributes) {
attr = this.xrefWrapper.fetch(attr);
attr = this.xrefWrapper.fetchIfRef(attr);
if (isName(attr.get("O"), "Table") && attr.has("Headers")) {
const headers = this.xrefWrapper.fetch(attr.getRaw("Headers"));
const headers = this.xrefWrapper.fetchIfRef(attr.getRaw("Headers"));
if (Array.isArray(headers)) {
for (let i = 0, ii = headers.length; i < ii; i++) {
const newId = dedupIDs.get(
Expand Down
115 changes: 6 additions & 109 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js";
import { getUnicodeForGlyph } from "./unicode.js";
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
import { parseMarkedContentProps } from "./evaluator_utils.js";
import { PDFImage } from "./image.js";
import { Stream } from "./stream.js";
import { stringToPDFString } from "./string_utils.js";
Expand Down Expand Up @@ -1651,105 +1652,8 @@ class PartialEvaluator {
throw new FormatError(`Unknown PatternName: ${patternName}`);
}

_parseVisibilityExpression(array, nestingCounter, currentResult) {
const MAX_NESTING = 10;
if (++nestingCounter > MAX_NESTING) {
warn("Visibility expression is too deeply nested");
return;
}
const length = array.length;
const operator = this.xref.fetchIfRef(array[0]);
if (length < 2 || !(operator instanceof Name)) {
warn("Invalid visibility expression");
return;
}
switch (operator.name) {
case "And":
case "Or":
case "Not":
currentResult.push(operator.name);
break;
default:
warn(`Invalid operator ${operator.name} in visibility expression`);
return;
}
for (let i = 1; i < length; i++) {
const raw = array[i];
const object = this.xref.fetchIfRef(raw);
if (Array.isArray(object)) {
const nestedResult = [];
currentResult.push(nestedResult);
// Recursively parse a subarray.
this._parseVisibilityExpression(object, nestingCounter, nestedResult);
} else if (raw instanceof Ref) {
// Reference to an OCG dictionary.
currentResult.push(raw.toString());
}
}
}

async parseMarkedContentProps(contentProperties, resources) {
let optionalContent;
if (contentProperties instanceof Name) {
const properties = resources.get("Properties");
optionalContent = properties.get(contentProperties.name);
} else if (contentProperties instanceof Dict) {
optionalContent = contentProperties;
} else {
throw new FormatError("Optional content properties malformed.");
}

const optionalContentType = optionalContent.get("Type")?.name;
if (optionalContentType === "OCG") {
return {
type: optionalContentType,
id: optionalContent.objId,
};
} else if (optionalContentType === "OCMD") {
const expression = optionalContent.get("VE");
if (Array.isArray(expression)) {
const result = [];
this._parseVisibilityExpression(expression, 0, result);
if (result.length > 0) {
return {
type: "OCMD",
expression: result,
};
}
}

const optionalContentGroups = optionalContent.get("OCGs");
if (
Array.isArray(optionalContentGroups) ||
optionalContentGroups instanceof Dict
) {
const groupIds = [];
if (Array.isArray(optionalContentGroups)) {
for (const ocg of optionalContentGroups) {
groupIds.push(ocg.toString());
}
} else {
// Dictionary, just use the obj id.
groupIds.push(optionalContentGroups.objId);
}

return {
type: optionalContentType,
ids: groupIds,
policy:
optionalContent.get("P") instanceof Name
? optionalContent.get("P").name
: null,
expression: null,
};
} else if (optionalContentGroups instanceof Ref) {
return {
type: optionalContentType,
id: optionalContentGroups.toString(),
};
}
}
return null;
return parseMarkedContentProps(this.xref, contentProperties, resources);
}

async getOperatorList({
Expand Down Expand Up @@ -4666,18 +4570,11 @@ class PartialEvaluator {

let fontFile, fontFileN, subtype, length1, length2, length3;
try {
fontFile = descriptor.get("FontFile");
if (fontFile) {
fontFileN = 1;
} else {
fontFile = descriptor.get("FontFile2");
for (const n of ["FontFile", "FontFile2", "FontFile3"]) {
fontFile = descriptor.get(n);
if (fontFile) {
fontFileN = 2;
} else {
fontFile = descriptor.get("FontFile3");
if (fontFile) {
fontFileN = 3;
}
fontFileN = n;
break;
}
}

Expand Down
Loading
Loading