Skip to content

Commit

Permalink
Simplify saving added/modified annotations.
Browse files Browse the repository at this point in the history
Having this map to collect the different changes will allow to know if some objects have already been modified.
  • Loading branch information
calixteman committed Nov 12, 2024
1 parent 7a96203 commit d550867
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 331 deletions.
182 changes: 81 additions & 101 deletions src/core/annotation.js

Large diffs are not rendered by default.

41 changes: 16 additions & 25 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ import { OperatorList } from "./operator_list.js";
import { PartialEvaluator } from "./evaluator.js";
import { StreamsSequenceStream } from "./decode_stream.js";
import { StructTreePage } from "./struct_tree.js";
import { writeObject } from "./writer.js";
import { XFAFactory } from "./xfa/factory.js";
import { XRef } from "./xref.js";

Expand Down Expand Up @@ -314,7 +313,7 @@ class Page {
await Promise.all(promises);
}

async saveNewAnnotations(handler, task, annotations, imagePromises) {
async saveNewAnnotations(handler, task, annotations, imagePromises, changes) {
if (this.xfaFactory) {
throw new Error("XFA: Cannot save new annotations.");
}
Expand Down Expand Up @@ -348,7 +347,8 @@ class Page {
partialEvaluator,
task,
annotations,
imagePromises
imagePromises,
changes
);

for (const { ref } of newData.annotations) {
Expand All @@ -358,27 +358,20 @@ class Page {
}
}

const savedDict = pageDict.get("Annots");
pageDict.set("Annots", annotationsArray);
const buffer = [];
await writeObject(this.ref, pageDict, buffer, this.xref);
if (savedDict) {
pageDict.set("Annots", savedDict);
}
const dict = pageDict.clone();
dict.set("Annots", annotationsArray);
changes.put(this.ref, {
data: dict,
});

const objects = newData.dependencies;
objects.push(
{ ref: this.ref, data: buffer.join("") },
...newData.annotations
);
for (const deletedRef of deletedAnnotations) {
objects.push({ ref: deletedRef, data: null });
changes.put(deletedRef, {
data: null,
});
}

return objects;
}

save(handler, task, annotationStorage) {
save(handler, task, annotationStorage, changes) {
const partialEvaluator = new PartialEvaluator({
xref: this.xref,
handler,
Expand All @@ -395,11 +388,11 @@ class Page {
// Fetch the page's annotations and save the content
// in case of interactive form fields.
return this._parsedAnnotations.then(function (annotations) {
const newRefsPromises = [];
const promises = [];
for (const annotation of annotations) {
newRefsPromises.push(
promises.push(
annotation
.save(partialEvaluator, task, annotationStorage)
.save(partialEvaluator, task, annotationStorage, changes)
.catch(function (reason) {
warn(
"save - ignoring annotation data during " +
Expand All @@ -410,9 +403,7 @@ class Page {
);
}

return Promise.all(newRefsPromises).then(function (newRefs) {
return newRefs.filter(newRef => !!newRef);
});
return Promise.all(promises);
});
}

Expand Down
8 changes: 8 additions & 0 deletions src/core/primitives.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,14 @@ class RefSetCache {
this._map.clear();
}

isEmpty() {
return this._map.size === 0;
}

*values() {
yield* this._map.values();
}

*items() {
for (const [ref, value] of this._map) {
yield [Ref.fromString(ref), value];
Expand Down
32 changes: 14 additions & 18 deletions src/core/struct_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { AnnotationPrefix, stringToPDFString, warn } from "../shared/util.js";
import { Dict, isName, Name, Ref, RefSetCache } from "./primitives.js";
import { lookupNormalRect, stringToAsciiOrUTF16BE } from "./core_utils.js";
import { NumberTree } from "./name_number_tree.js";
import { writeObject } from "./writer.js";

const MAX_DEPTH = 40;

Expand Down Expand Up @@ -117,7 +116,7 @@ class StructTreeRoot {
xref,
catalogRef,
pdfManager,
newRefs,
changes,
}) {
const root = pdfManager.catalog.cloneDict();
const cache = new RefSetCache();
Expand Down Expand Up @@ -146,18 +145,17 @@ class StructTreeRoot {
nums,
xref,
pdfManager,
newRefs,
changes,
cache,
});
structTreeRoot.set("ParentTreeNextKey", nextKey);

cache.put(parentTreeRef, parentTree);

const buffer = [];
for (const [ref, obj] of cache.items()) {
buffer.length = 0;
await writeObject(ref, obj, buffer, xref);
newRefs.push({ ref, data: buffer.join("") });
changes.put(ref, {
data: obj,
});
}
}

Expand Down Expand Up @@ -235,7 +233,7 @@ class StructTreeRoot {
return true;
}

async updateStructureTree({ newAnnotationsByPage, pdfManager, newRefs }) {
async updateStructureTree({ newAnnotationsByPage, pdfManager, changes }) {
const xref = this.dict.xref;
const structTreeRoot = this.dict.clone();
const structTreeRootRef = this.ref;
Expand Down Expand Up @@ -273,7 +271,7 @@ class StructTreeRoot {
nums,
xref,
pdfManager,
newRefs,
changes,
cache,
});

Expand All @@ -288,11 +286,10 @@ class StructTreeRoot {
cache.put(numsRef, nums);
}

const buffer = [];
for (const [ref, obj] of cache.items()) {
buffer.length = 0;
await writeObject(ref, obj, buffer, xref);
newRefs.push({ ref, data: buffer.join("") });
changes.put(ref, {
data: obj,
});
}
}

Expand All @@ -304,13 +301,12 @@ class StructTreeRoot {
nums,
xref,
pdfManager,
newRefs,
changes,
cache,
}) {
const objr = Name.get("OBJR");
let nextKey = -1;
let structTreePageObjs;
const buffer = [];

for (const [pageIndex, elements] of newAnnotationsByPage) {
const page = await pdfManager.getPage(pageIndex);
Expand Down Expand Up @@ -350,9 +346,9 @@ class StructTreeRoot {
// We update the existing tag.
const tagDict = xref.fetch(objRef).clone();
StructTreeRoot.#writeProperties(tagDict, accessibilityData);
buffer.length = 0;
await writeObject(objRef, tagDict, buffer, xref);
newRefs.push({ ref: objRef, data: buffer.join("") });
changes.put(objRef, {
data: tagDict,
});
continue;
}
}
Expand Down
38 changes: 19 additions & 19 deletions src/core/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
getNewAnnotationsMap,
XRefParseException,
} from "./core_utils.js";
import { Dict, isDict, Ref } from "./primitives.js";
import { Dict, isDict, Ref, RefSetCache } from "./primitives.js";
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js";
import { AnnotationFactory } from "./annotation.js";
import { clearGlobalCaches } from "./cleanup_helper.js";
Expand Down Expand Up @@ -540,6 +540,7 @@ class WorkerMessageHandler {
pdfManager.ensureDoc("linearization"),
pdfManager.ensureCatalog("structTreeRoot"),
];
const changes = new RefSetCache();
const promises = [];

const newAnnotationsByPage = !isPureXfa
Expand Down Expand Up @@ -590,7 +591,13 @@ class WorkerMessageHandler {
pdfManager.getPage(pageIndex).then(page => {
const task = new WorkerTask(`Save (editor): page ${pageIndex}`);
return page
.saveNewAnnotations(handler, task, annotations, imagePromises)
.saveNewAnnotations(
handler,
task,
annotations,
imagePromises,
changes
)
.finally(function () {
finishWorkerTask(task);
});
Expand All @@ -600,26 +607,24 @@ class WorkerMessageHandler {
if (structTreeRoot === null) {
// No structTreeRoot exists, so we need to create one.
promises.push(
Promise.all(newAnnotationPromises).then(async newRefs => {
Promise.all(newAnnotationPromises).then(async () => {
await StructTreeRoot.createStructureTree({
newAnnotationsByPage,
xref,
catalogRef,
pdfManager,
newRefs,
changes,
});
return newRefs;
})
);
} else if (structTreeRoot) {
promises.push(
Promise.all(newAnnotationPromises).then(async newRefs => {
Promise.all(newAnnotationPromises).then(async () => {
await structTreeRoot.updateStructureTree({
newAnnotationsByPage,
pdfManager,
newRefs,
changes,
});
return newRefs;
})
);
}
Expand All @@ -633,7 +638,7 @@ class WorkerMessageHandler {
pdfManager.getPage(pageIndex).then(function (page) {
const task = new WorkerTask(`Save: page ${pageIndex}`);
return page
.save(handler, task, annotationStorage)
.save(handler, task, annotationStorage, changes)
.finally(function () {
finishWorkerTask(task);
});
Expand All @@ -643,26 +648,21 @@ class WorkerMessageHandler {
}
const refs = await Promise.all(promises);

let newRefs = [];
let xfaData = null;
if (isPureXfa) {
xfaData = refs[0];
if (!xfaData) {
return stream.bytes;
}
} else {
newRefs = refs.flat(2);

if (newRefs.length === 0) {
// No new refs so just return the initial bytes
return stream.bytes;
}
} else if (changes.isEmpty()) {
// No new refs so just return the initial bytes
return stream.bytes;
}

const needAppearances =
acroFormRef &&
acroForm instanceof Dict &&
newRefs.some(ref => ref.needAppearances);
changes.values().some(ref => ref.needAppearances);

const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || null;
let xfaDatasetsRef = null;
Expand Down Expand Up @@ -712,7 +712,7 @@ class WorkerMessageHandler {
return incrementalUpdate({
originalData: stream.bytes,
xrefInfo: newXrefInfo,
newRefs,
changes,
xref,
hasXfa: !!xfa,
xfaDatasetsRef,
Expand Down
Loading

0 comments on commit d550867

Please sign in to comment.