Remove per-draw canvas clones; title nav cap + right-page-number labels
Two changes: Eliminate cloning in the publish path. The page-texture-records event is dispatched synchronously and its handler uploads the canvas to a GPU texture synchronously (renderer.initTexture), and the stored sourceCanvas is never re-read — so the per-draw cloneCanvas of the page (and the now-static reveal base) was pure waste driving GC stalls. publishSpread now passes the live page canvas and the cached base directly; cloneCanvas is removed. Worst per-paragraph stall 1431ms -> 902ms (originally 2159ms); all stalls now <1s. Title spread and labels (as specified): - getMaxNavigableSpread caps to the spread holding the last written body page; before any content exists the book stays on the title spread (forward nav disabled), instead of letting you flip into blank leaves. - spreadPageLabel reads 0 at the title and the printed page number of the spread's right page elsewhere (was the raw right-page index, e.g. "3" before a game). Verified live: title reads 0 with forward disabled; spread 1 reads 1; suite 182. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,6 @@ class BookTextureRendererModule extends BaseModule {
|
||||
'drawSpreadSerial',
|
||||
'rasterizeSpread',
|
||||
'getDrawSignature',
|
||||
'cloneCanvas',
|
||||
'buildRevealRegions',
|
||||
'shouldFlipAfterSideReveal',
|
||||
'collectRevealRegionCandidates',
|
||||
@@ -373,15 +372,6 @@ class BookTextureRendererModule extends BaseModule {
|
||||
}).join('|');
|
||||
}
|
||||
|
||||
cloneCanvas(canvas) {
|
||||
if (!canvas) return null;
|
||||
const clone = document.createElement('canvas');
|
||||
clone.width = canvas.width;
|
||||
clone.height = canvas.height;
|
||||
const context = clone.getContext('2d');
|
||||
if (context) context.drawImage(canvas, 0, 0);
|
||||
return clone;
|
||||
}
|
||||
|
||||
getPageContent(side = 'left') {
|
||||
return this.metrics?.contentBySide?.[side] || this.metrics?.content || {
|
||||
@@ -953,19 +943,17 @@ class BookTextureRendererModule extends BaseModule {
|
||||
pageMeta: this.buildPublishPageMeta(sidesToPublish),
|
||||
phase
|
||||
};
|
||||
if (sidesToPublish.includes('left')) {
|
||||
detail.left = phase === 'prepare' ? this.cloneCanvas(this.canvases.left) : this.canvases.left;
|
||||
}
|
||||
if (sidesToPublish.includes('right')) {
|
||||
detail.right = phase === 'prepare' ? this.cloneCanvas(this.canvases.right) : this.canvases.right;
|
||||
}
|
||||
// The page-texture-records event is dispatched synchronously below, and its handler
|
||||
// uploads the canvas to a GPU texture synchronously (renderer.initTexture). So the live
|
||||
// page canvas (and the static cached base) are consumed before the next draw can touch
|
||||
// them — no per-draw clones needed (those large canvas copies drove the GC stalls).
|
||||
if (sidesToPublish.includes('left')) detail.left = this.canvases.left;
|
||||
if (sidesToPublish.includes('right')) detail.right = this.canvases.right;
|
||||
const reveal = {};
|
||||
sidesToPublish.forEach((side) => {
|
||||
const sideReveal = this.buildRevealRegions(side);
|
||||
if (!sideReveal) return;
|
||||
sideReveal.baseCanvas = phase === 'prepare'
|
||||
? this.cloneCanvas(this.revealBaseCanvases?.[side])
|
||||
: this.revealBaseCanvases?.[side] || null;
|
||||
sideReveal.baseCanvas = this.revealBaseCanvases?.[side] || null;
|
||||
regionCounts[side] = sideReveal.lineRects.length;
|
||||
reveal[side] = sideReveal;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user