Skip to content

Commit 5af7d2e

Browse files
committed
Retain the thumbnail cache across page ops by reordering it instead of dropping it
1 parent 3b7ff52 commit 5af7d2e

1 file changed

Lines changed: 27 additions & 4 deletions

File tree

js/containers/scribeDoc.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ function uniqueLayers(layers) {
3838
}
3939

4040
/**
41-
* Every dense per-page array that must stay index-aligned with `pageMetrics`.
42-
* Delete/move apply the same splice to each. (Derived image caches are handled separately by `clearImageCaches`.)
41+
* Every dense per-page array that must stay index-aligned with `pageMetrics` under page delete/move.
4342
* @param {ScribeDoc} doc
4443
* @returns {Array<Array<any>>}
4544
*/
@@ -58,7 +57,8 @@ function densePageArrays(doc) {
5857
}
5958

6059
/**
61-
* Drop the derived image caches so they re-render against the edited order (via `sourcePageN`).
60+
* Drop the full-resolution render caches so they re-render against the edited page order.
61+
* Thumbnails are deliberately not among these; page ops reorder that cache in place via `remapThumbnails` instead of re-rendering it.
6262
* @param {ScribeDoc} doc
6363
*/
6464
function clearImageCaches(doc) {
@@ -67,7 +67,6 @@ function clearImageCaches(doc) {
6767
images.binary.length = 0;
6868
images.nativeProps.length = 0;
6969
images.binaryProps.length = 0;
70-
images.thumbnails.length = 0;
7170
}
7271

7372
/**
@@ -192,6 +191,19 @@ function remapOutlineByTags(doc, tags) {
192191
setDocOutline(doc, remapOutline(doc.outline, (old) => (newByOld.has(old) ? newByOld.get(old) : null)));
193192
}
194193

194+
/**
195+
* Reorder the retained thumbnail cache to match a page-order edit instead of dropping it:
196+
* a reorder leaves each thumbnail's pixels unchanged, so re-rendering would be waste.
197+
* @param {ScribeDoc} doc
198+
* @param {Array<?number>} tags - tags[newPos] is the pre-edit index of the page now at newPos, or null for a freshly inserted page.
199+
*/
200+
function remapThumbnails(doc, tags) {
201+
const { thumbnails } = doc.images;
202+
const remapped = tags.map((old) => (old == null ? undefined : thumbnails[old]));
203+
thumbnails.length = 0;
204+
for (const t of remapped) thumbnails.push(t);
205+
}
206+
195207
/**
196208
* Re-align the document's FOREIGN render sources (the pools of pages copied in from other documents) with a restored page state,
197209
* so undo/redo of a cross-document paste tracks its source rather than leaking it.
@@ -228,6 +240,8 @@ function capturePageState(doc) {
228240
// Foreign (cross-document) render sources this state references, captured so undo/redo can re-register or release them.
229241
// The primary source is excluded because page ops never add or remove it.
230242
foreignSources: new Map([...doc.images.sources].filter(([id]) => id !== primaryId)),
243+
// The retained thumbnail cache, so undo/redo restore its slot alignment too (no preview re-render on either).
244+
thumbnails: [...doc.images.thumbnails],
231245
};
232246
}
233247

@@ -244,6 +258,10 @@ function restorePageState(doc, snap) {
244258
setDocOutline(doc, cloneOutline(snap.outline));
245259
renumberPages(doc);
246260
clearImageCaches(doc);
261+
// Restore the retained thumbnail cache in lockstep with the page order (clearImageCaches no longer drops it).
262+
const { thumbnails } = doc.images;
263+
thumbnails.length = 0;
264+
for (const t of snap.thumbnails) thumbnails.push(t);
247265
doc.inputData.pageCount = snap.pageCount;
248266
doc.images.pageCount = snap.pageCount;
249267
reconcileForeignSources(doc, snap.foreignSources);
@@ -423,6 +441,7 @@ export class ScribeDoc {
423441
const tags = this.pageMetrics.map((_, k) => k);
424442
for (const arr of [...densePageArrays(this), tags]) if (i < arr.length) arr.splice(i, 1);
425443
remapOutlineByTags(this, tags);
444+
remapThumbnails(this, tags);
426445
clearImageCaches(this);
427446
renumberPages(this);
428447
this.inputData.pageCount = this.pageMetrics.length;
@@ -447,6 +466,7 @@ export class ScribeDoc {
447466
arr.splice(to, 0, item);
448467
}
449468
remapOutlineByTags(this, tags);
469+
remapThumbnails(this, tags);
450470
clearImageCaches(this);
451471
renumberPages(this);
452472
});
@@ -467,6 +487,7 @@ export class ScribeDoc {
467487
for (const i of sorted) if (i < arr.length) arr.splice(i, 1);
468488
}
469489
remapOutlineByTags(this, tags);
490+
remapThumbnails(this, tags);
470491
clearImageCaches(this);
471492
renumberPages(this);
472493
this.inputData.pageCount = this.pageMetrics.length;
@@ -494,6 +515,7 @@ export class ScribeDoc {
494515
arr.splice(Math.max(0, Math.min(to, arr.length)), 0, ...pulled);
495516
}
496517
remapOutlineByTags(this, tags);
518+
remapThumbnails(this, tags);
497519
clearImageCaches(this);
498520
renumberPages(this);
499521
});
@@ -560,6 +582,7 @@ export class ScribeDoc {
560582
spliceFull(this.inputData.ocrApplied, bundles.map((b) => b.ocrApplied));
561583
spliceFull(tags, bundles.map(() => null));
562584
remapOutlineByTags(this, tags);
585+
remapThumbnails(this, tags);
563586

564587
// Register a copied page's foreign render source so it keeps rendering and subsetting from its origin.
565588
for (const b of bundles) {

0 commit comments

Comments
 (0)