Skip to content

Commit 13a231c

Browse files
authored
Merge pull request #19026 from calixteman/refactor_newrefs_saving
Simplify saving added/modified annotations.
2 parents 7a96203 + 4bf7787 commit 13a231c

File tree

8 files changed

+301
-331
lines changed

8 files changed

+301
-331
lines changed

src/core/annotation.js

+81-101
Large diffs are not rendered by default.

src/core/document.js

+16-25
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ import { OperatorList } from "./operator_list.js";
7070
import { PartialEvaluator } from "./evaluator.js";
7171
import { StreamsSequenceStream } from "./decode_stream.js";
7272
import { StructTreePage } from "./struct_tree.js";
73-
import { writeObject } from "./writer.js";
7473
import { XFAFactory } from "./xfa/factory.js";
7574
import { XRef } from "./xref.js";
7675

@@ -314,7 +313,7 @@ class Page {
314313
await Promise.all(promises);
315314
}
316315

317-
async saveNewAnnotations(handler, task, annotations, imagePromises) {
316+
async saveNewAnnotations(handler, task, annotations, imagePromises, changes) {
318317
if (this.xfaFactory) {
319318
throw new Error("XFA: Cannot save new annotations.");
320319
}
@@ -348,7 +347,8 @@ class Page {
348347
partialEvaluator,
349348
task,
350349
annotations,
351-
imagePromises
350+
imagePromises,
351+
changes
352352
);
353353

354354
for (const { ref } of newData.annotations) {
@@ -358,27 +358,20 @@ class Page {
358358
}
359359
}
360360

361-
const savedDict = pageDict.get("Annots");
362-
pageDict.set("Annots", annotationsArray);
363-
const buffer = [];
364-
await writeObject(this.ref, pageDict, buffer, this.xref);
365-
if (savedDict) {
366-
pageDict.set("Annots", savedDict);
367-
}
361+
const dict = pageDict.clone();
362+
dict.set("Annots", annotationsArray);
363+
changes.put(this.ref, {
364+
data: dict,
365+
});
368366

369-
const objects = newData.dependencies;
370-
objects.push(
371-
{ ref: this.ref, data: buffer.join("") },
372-
...newData.annotations
373-
);
374367
for (const deletedRef of deletedAnnotations) {
375-
objects.push({ ref: deletedRef, data: null });
368+
changes.put(deletedRef, {
369+
data: null,
370+
});
376371
}
377-
378-
return objects;
379372
}
380373

381-
save(handler, task, annotationStorage) {
374+
save(handler, task, annotationStorage, changes) {
382375
const partialEvaluator = new PartialEvaluator({
383376
xref: this.xref,
384377
handler,
@@ -395,11 +388,11 @@ class Page {
395388
// Fetch the page's annotations and save the content
396389
// in case of interactive form fields.
397390
return this._parsedAnnotations.then(function (annotations) {
398-
const newRefsPromises = [];
391+
const promises = [];
399392
for (const annotation of annotations) {
400-
newRefsPromises.push(
393+
promises.push(
401394
annotation
402-
.save(partialEvaluator, task, annotationStorage)
395+
.save(partialEvaluator, task, annotationStorage, changes)
403396
.catch(function (reason) {
404397
warn(
405398
"save - ignoring annotation data during " +
@@ -410,9 +403,7 @@ class Page {
410403
);
411404
}
412405

413-
return Promise.all(newRefsPromises).then(function (newRefs) {
414-
return newRefs.filter(newRef => !!newRef);
415-
});
406+
return Promise.all(promises);
416407
});
417408
}
418409

src/core/primitives.js

+4
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ class RefSetCache {
383383
this._map.clear();
384384
}
385385

386+
*values() {
387+
yield* this._map.values();
388+
}
389+
386390
*items() {
387391
for (const [ref, value] of this._map) {
388392
yield [Ref.fromString(ref), value];

src/core/struct_tree.js

+14-18
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { AnnotationPrefix, stringToPDFString, warn } from "../shared/util.js";
1717
import { Dict, isName, Name, Ref, RefSetCache } from "./primitives.js";
1818
import { lookupNormalRect, stringToAsciiOrUTF16BE } from "./core_utils.js";
1919
import { NumberTree } from "./name_number_tree.js";
20-
import { writeObject } from "./writer.js";
2120

2221
const MAX_DEPTH = 40;
2322

@@ -117,7 +116,7 @@ class StructTreeRoot {
117116
xref,
118117
catalogRef,
119118
pdfManager,
120-
newRefs,
119+
changes,
121120
}) {
122121
const root = pdfManager.catalog.cloneDict();
123122
const cache = new RefSetCache();
@@ -146,18 +145,17 @@ class StructTreeRoot {
146145
nums,
147146
xref,
148147
pdfManager,
149-
newRefs,
148+
changes,
150149
cache,
151150
});
152151
structTreeRoot.set("ParentTreeNextKey", nextKey);
153152

154153
cache.put(parentTreeRef, parentTree);
155154

156-
const buffer = [];
157155
for (const [ref, obj] of cache.items()) {
158-
buffer.length = 0;
159-
await writeObject(ref, obj, buffer, xref);
160-
newRefs.push({ ref, data: buffer.join("") });
156+
changes.put(ref, {
157+
data: obj,
158+
});
161159
}
162160
}
163161

@@ -235,7 +233,7 @@ class StructTreeRoot {
235233
return true;
236234
}
237235

238-
async updateStructureTree({ newAnnotationsByPage, pdfManager, newRefs }) {
236+
async updateStructureTree({ newAnnotationsByPage, pdfManager, changes }) {
239237
const xref = this.dict.xref;
240238
const structTreeRoot = this.dict.clone();
241239
const structTreeRootRef = this.ref;
@@ -273,7 +271,7 @@ class StructTreeRoot {
273271
nums,
274272
xref,
275273
pdfManager,
276-
newRefs,
274+
changes,
277275
cache,
278276
});
279277

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

291-
const buffer = [];
292289
for (const [ref, obj] of cache.items()) {
293-
buffer.length = 0;
294-
await writeObject(ref, obj, buffer, xref);
295-
newRefs.push({ ref, data: buffer.join("") });
290+
changes.put(ref, {
291+
data: obj,
292+
});
296293
}
297294
}
298295

@@ -304,13 +301,12 @@ class StructTreeRoot {
304301
nums,
305302
xref,
306303
pdfManager,
307-
newRefs,
304+
changes,
308305
cache,
309306
}) {
310307
const objr = Name.get("OBJR");
311308
let nextKey = -1;
312309
let structTreePageObjs;
313-
const buffer = [];
314310

315311
for (const [pageIndex, elements] of newAnnotationsByPage) {
316312
const page = await pdfManager.getPage(pageIndex);
@@ -350,9 +346,9 @@ class StructTreeRoot {
350346
// We update the existing tag.
351347
const tagDict = xref.fetch(objRef).clone();
352348
StructTreeRoot.#writeProperties(tagDict, accessibilityData);
353-
buffer.length = 0;
354-
await writeObject(objRef, tagDict, buffer, xref);
355-
newRefs.push({ ref: objRef, data: buffer.join("") });
349+
changes.put(objRef, {
350+
data: tagDict,
351+
});
356352
continue;
357353
}
358354
}

src/core/worker.js

+19-19
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
getNewAnnotationsMap,
3535
XRefParseException,
3636
} from "./core_utils.js";
37-
import { Dict, isDict, Ref } from "./primitives.js";
37+
import { Dict, isDict, Ref, RefSetCache } from "./primitives.js";
3838
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js";
3939
import { AnnotationFactory } from "./annotation.js";
4040
import { clearGlobalCaches } from "./cleanup_helper.js";
@@ -540,6 +540,7 @@ class WorkerMessageHandler {
540540
pdfManager.ensureDoc("linearization"),
541541
pdfManager.ensureCatalog("structTreeRoot"),
542542
];
543+
const changes = new RefSetCache();
543544
const promises = [];
544545

545546
const newAnnotationsByPage = !isPureXfa
@@ -590,7 +591,13 @@ class WorkerMessageHandler {
590591
pdfManager.getPage(pageIndex).then(page => {
591592
const task = new WorkerTask(`Save (editor): page ${pageIndex}`);
592593
return page
593-
.saveNewAnnotations(handler, task, annotations, imagePromises)
594+
.saveNewAnnotations(
595+
handler,
596+
task,
597+
annotations,
598+
imagePromises,
599+
changes
600+
)
594601
.finally(function () {
595602
finishWorkerTask(task);
596603
});
@@ -600,26 +607,24 @@ class WorkerMessageHandler {
600607
if (structTreeRoot === null) {
601608
// No structTreeRoot exists, so we need to create one.
602609
promises.push(
603-
Promise.all(newAnnotationPromises).then(async newRefs => {
610+
Promise.all(newAnnotationPromises).then(async () => {
604611
await StructTreeRoot.createStructureTree({
605612
newAnnotationsByPage,
606613
xref,
607614
catalogRef,
608615
pdfManager,
609-
newRefs,
616+
changes,
610617
});
611-
return newRefs;
612618
})
613619
);
614620
} else if (structTreeRoot) {
615621
promises.push(
616-
Promise.all(newAnnotationPromises).then(async newRefs => {
622+
Promise.all(newAnnotationPromises).then(async () => {
617623
await structTreeRoot.updateStructureTree({
618624
newAnnotationsByPage,
619625
pdfManager,
620-
newRefs,
626+
changes,
621627
});
622-
return newRefs;
623628
})
624629
);
625630
}
@@ -633,7 +638,7 @@ class WorkerMessageHandler {
633638
pdfManager.getPage(pageIndex).then(function (page) {
634639
const task = new WorkerTask(`Save: page ${pageIndex}`);
635640
return page
636-
.save(handler, task, annotationStorage)
641+
.save(handler, task, annotationStorage, changes)
637642
.finally(function () {
638643
finishWorkerTask(task);
639644
});
@@ -643,26 +648,21 @@ class WorkerMessageHandler {
643648
}
644649
const refs = await Promise.all(promises);
645650

646-
let newRefs = [];
647651
let xfaData = null;
648652
if (isPureXfa) {
649653
xfaData = refs[0];
650654
if (!xfaData) {
651655
return stream.bytes;
652656
}
653-
} else {
654-
newRefs = refs.flat(2);
655-
656-
if (newRefs.length === 0) {
657-
// No new refs so just return the initial bytes
658-
return stream.bytes;
659-
}
657+
} else if (changes.size === 0) {
658+
// No new refs so just return the initial bytes
659+
return stream.bytes;
660660
}
661661

662662
const needAppearances =
663663
acroFormRef &&
664664
acroForm instanceof Dict &&
665-
newRefs.some(ref => ref.needAppearances);
665+
changes.values().some(ref => ref.needAppearances);
666666

667667
const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || null;
668668
let xfaDatasetsRef = null;
@@ -712,7 +712,7 @@ class WorkerMessageHandler {
712712
return incrementalUpdate({
713713
originalData: stream.bytes,
714714
xrefInfo: newXrefInfo,
715-
newRefs,
715+
changes,
716716
xref,
717717
hasXfa: !!xfa,
718718
xfaDatasetsRef,

0 commit comments

Comments
 (0)