vomebook commited on
Commit ·
44759b1
1
Parent(s): 61e3a76
perf(reader): create PDF page canvases on first render
Browse filesEvery PDF page shell created a default 300x150 canvas at mount. A 234-page
original PDF therefore held 234 blank backing stores (~16.7M pixels, ~67 MB)
before any page was visible, and the count scaled with the document.
Create the canvas in the renderer instead, matching the v3 path. Measured on a
production 234-page PDF: 234 canvases / 16.7M px at open -> 0 / 0, with the same
pages rendered as they scroll into view.
static/reader/pdf/reader-pdf-page-window.mjs
CHANGED
|
@@ -632,13 +632,14 @@ export function createReaderPdfPageWindow(readerContext) {
|
|
| 632 |
shell.tabIndex = 0;
|
| 633 |
shell.setAttribute("role", "region");
|
| 634 |
shell.setAttribute("aria-label", `第 ${page} 页`);
|
| 635 |
-
|
| 636 |
-
canvas
|
|
|
|
| 637 |
const textLayer = document.createElement("div");
|
| 638 |
textLayer.className = "reader-pdf-text";
|
| 639 |
textLayer.setAttribute("role", "document");
|
| 640 |
textLayer.setAttribute("aria-label", `第 ${page} 页正文`);
|
| 641 |
-
shell.append(
|
| 642 |
const pageState = document.createElement("div");
|
| 643 |
pageState.className = "reader-page-state";
|
| 644 |
readerContext.setPdfPageLoadingState(pageState, page);
|
|
|
|
| 632 |
shell.tabIndex = 0;
|
| 633 |
shell.setAttribute("role", "region");
|
| 634 |
shell.setAttribute("aria-label", `第 ${page} 页`);
|
| 635 |
+
// The canvas is created by the renderer on first use: a 300x150 default
|
| 636 |
+
// canvas per shell costs ~180 KB, so a 250-page PDF held ~45 MB of blank
|
| 637 |
+
// backing stores before any page was visible.
|
| 638 |
const textLayer = document.createElement("div");
|
| 639 |
textLayer.className = "reader-pdf-text";
|
| 640 |
textLayer.setAttribute("role", "document");
|
| 641 |
textLayer.setAttribute("aria-label", `第 ${page} 页正文`);
|
| 642 |
+
shell.append(textLayer);
|
| 643 |
const pageState = document.createElement("div");
|
| 644 |
pageState.className = "reader-page-state";
|
| 645 |
readerContext.setPdfPageLoadingState(pageState, page);
|
static/reader/pdf/reader-pdf-renderer.mjs
CHANGED
|
@@ -546,6 +546,7 @@ export function createReaderPdfRenderer(readerContext) {
|
|
| 546 |
if (renderController.signal.aborted) throw readerContext.readerAbortError();
|
| 547 |
const pdf = readerContext.pdfDocument;
|
| 548 |
if (!pdf) throw readerContext.readerAbortError();
|
|
|
|
| 549 |
do {
|
| 550 |
delete shell.dataset.pendingRerender;
|
| 551 |
const generation = readerContext.readerRuntime.currentGeneration("pdf"),
|
|
@@ -557,7 +558,12 @@ export function createReaderPdfRenderer(readerContext) {
|
|
| 557 |
scale = Math.min(3, shell.clientWidth / base.width),
|
| 558 |
viewport = page.getViewport({ scale }),
|
| 559 |
outputScale = Math.min(2, Math.max(1, Number(window.devicePixelRatio) || 1));
|
| 560 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 561 |
canvas.width = Math.ceil(viewport.width * outputScale);
|
| 562 |
canvas.height = Math.ceil(viewport.height * outputScale);
|
| 563 |
canvas.style.width = "100%";
|
|
@@ -584,7 +590,7 @@ export function createReaderPdfRenderer(readerContext) {
|
|
| 584 |
if (renderController.signal.aborted) throw readerContext.readerAbortError();
|
| 585 |
if (!readerContext.isReaderGenerationCurrent("pdf", generation)) shell.dataset.pendingRerender = "1";
|
| 586 |
} while (shell.dataset.pendingRerender);
|
| 587 |
-
|
| 588 |
const pageState = shell.querySelector(".reader-page-state");
|
| 589 |
if (pageState) pageState.hidden = true;
|
| 590 |
shell.dataset.renderState = "rendered";
|
|
|
|
| 546 |
if (renderController.signal.aborted) throw readerContext.readerAbortError();
|
| 547 |
const pdf = readerContext.pdfDocument;
|
| 548 |
if (!pdf) throw readerContext.readerAbortError();
|
| 549 |
+
let canvas = null;
|
| 550 |
do {
|
| 551 |
delete shell.dataset.pendingRerender;
|
| 552 |
const generation = readerContext.readerRuntime.currentGeneration("pdf"),
|
|
|
|
| 558 |
scale = Math.min(3, shell.clientWidth / base.width),
|
| 559 |
viewport = page.getViewport({ scale }),
|
| 560 |
outputScale = Math.min(2, Math.max(1, Number(window.devicePixelRatio) || 1));
|
| 561 |
+
canvas = shell.querySelector("canvas");
|
| 562 |
+
if (!canvas) {
|
| 563 |
+
canvas = document.createElement("canvas");
|
| 564 |
+
canvas.setAttribute("aria-hidden", "true");
|
| 565 |
+
shell.prepend(canvas);
|
| 566 |
+
}
|
| 567 |
canvas.width = Math.ceil(viewport.width * outputScale);
|
| 568 |
canvas.height = Math.ceil(viewport.height * outputScale);
|
| 569 |
canvas.style.width = "100%";
|
|
|
|
| 590 |
if (renderController.signal.aborted) throw readerContext.readerAbortError();
|
| 591 |
if (!readerContext.isReaderGenerationCurrent("pdf", generation)) shell.dataset.pendingRerender = "1";
|
| 592 |
} while (shell.dataset.pendingRerender);
|
| 593 |
+
canvas.classList.add("ready");
|
| 594 |
const pageState = shell.querySelector(".reader-page-state");
|
| 595 |
if (pageState) pageState.hidden = true;
|
| 596 |
shell.dataset.renderState = "rendered";
|