Skip to content

Commit b8de9a3

Browse files
authored
Merge pull request #19856 from calixteman/bug1936605
Don't update the visible canvas at 60 fps (bug 1936605)
2 parents 0922aa9 + ecc56a6 commit b8de9a3

4 files changed

Lines changed: 70 additions & 3 deletions

File tree

web/app.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,19 @@ const PDFViewerApplication = {
326326
}
327327
}
328328
if (params.has("pdfbug")) {
329-
AppOptions.setAll({ pdfBug: true, fontExtraProperties: true });
330-
331329
const enabled = params.get("pdfbug").split(",");
332330
try {
333331
await loadPDFBug();
334332
this._PDFBug.init(mainContainer, enabled);
335333
} catch (ex) {
336334
console.error("_parseHashParams:", ex);
337335
}
336+
337+
const debugOpts = { pdfBug: true, fontExtraProperties: true };
338+
if (globalThis.StepperManager?.enabled) {
339+
debugOpts.minDurationToUpdateCanvas = 0;
340+
}
341+
AppOptions.setAll(debugOpts);
338342
}
339343
// It is not possible to change locale for the (various) extension builds.
340344
if (
@@ -519,6 +523,7 @@ const PDFViewerApplication = {
519523
enableHWA,
520524
supportsPinchToZoom: this.supportsPinchToZoom,
521525
enableAutoLinking: AppOptions.get("enableAutoLinking"),
526+
minDurationToUpdateCanvas: AppOptions.get("minDurationToUpdateCanvas"),
522527
}));
523528

524529
renderingQueue.setViewer(pdfViewer);

web/app_options.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ const defaultOptions = {
302302
value: 2 ** 25,
303303
kind: OptionKind.VIEWER,
304304
},
305+
minDurationToUpdateCanvas: {
306+
/** @type {number} */
307+
value: 500, // ms
308+
kind: OptionKind.VIEWER,
309+
},
305310
forcePageColors: {
306311
/** @type {boolean} */
307312
value: false,

web/base_pdf_page_view.js

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@ class BasePDFPageView {
2121

2222
#loadingId = null;
2323

24+
#minDurationToUpdateCanvas = 0;
25+
2426
#renderError = null;
2527

2628
#renderingState = RenderingStates.INITIAL;
2729

2830
#showCanvas = null;
2931

32+
#startTime = 0;
33+
34+
#tempCanvas = null;
35+
3036
canvas = null;
3137

3238
/** @type {null | HTMLDivElement} */
@@ -51,6 +57,7 @@ class BasePDFPageView {
5157
this.id = options.id;
5258
this.pageColors = options.pageColors || null;
5359
this.renderingQueue = options.renderingQueue;
60+
this.#minDurationToUpdateCanvas = options.minDurationToUpdateCanvas ?? 500;
5461
}
5562

5663
get renderingState() {
@@ -71,6 +78,9 @@ class BasePDFPageView {
7178
switch (state) {
7279
case RenderingStates.PAUSED:
7380
this.div.classList.remove("loading");
81+
// Display the canvas as it has been drawn.
82+
this.#startTime = 0;
83+
this.#showCanvas?.(false);
7484
break;
7585
case RenderingStates.RUNNING:
7686
this.div.classList.add("loadingIcon");
@@ -82,10 +92,12 @@ class BasePDFPageView {
8292
this.div.classList.add("loading");
8393
this.#loadingId = null;
8494
}, 0);
95+
this.#startTime = Date.now();
8596
break;
8697
case RenderingStates.INITIAL:
8798
case RenderingStates.FINISHED:
8899
this.div.classList.remove("loadingIcon", "loading");
100+
this.#startTime = 0;
89101
break;
90102
}
91103
}
@@ -100,10 +112,41 @@ class BasePDFPageView {
100112
// have a final flash we just display it once all the drawing is done.
101113
const updateOnFirstShow = !prevCanvas && !hasHCM && !hideUntilComplete;
102114

103-
const canvas = (this.canvas = document.createElement("canvas"));
115+
let canvas = (this.canvas = document.createElement("canvas"));
104116

105117
this.#showCanvas = isLastShow => {
106118
if (updateOnFirstShow) {
119+
let tempCanvas = this.#tempCanvas;
120+
if (!isLastShow && this.#minDurationToUpdateCanvas > 0) {
121+
// We draw on the canvas at 60fps (in using `requestAnimationFrame`),
122+
// so if the canvas is large, updating it at 60fps can be a way too
123+
// much and can cause some serious performance issues.
124+
// To avoid that we only update the canvas every
125+
// `this.#minDurationToUpdateCanvas` ms.
126+
127+
if (Date.now() - this.#startTime < this.#minDurationToUpdateCanvas) {
128+
return;
129+
}
130+
if (!tempCanvas) {
131+
tempCanvas = this.#tempCanvas = canvas;
132+
canvas = this.canvas = canvas.cloneNode(false);
133+
onShow(canvas);
134+
}
135+
}
136+
137+
if (tempCanvas) {
138+
const ctx = canvas.getContext("2d", {
139+
alpha: false,
140+
});
141+
ctx.drawImage(tempCanvas, 0, 0);
142+
if (isLastShow) {
143+
this.#resetTempCanvas();
144+
} else {
145+
this.#startTime = Date.now();
146+
}
147+
return;
148+
}
149+
107150
// Don't add the canvas until the first draw callback, or until
108151
// drawing is complete when `!this.renderingQueue`, to prevent black
109152
// flickering.
@@ -152,6 +195,14 @@ class BasePDFPageView {
152195
canvas.remove();
153196
canvas.width = canvas.height = 0;
154197
this.canvas = null;
198+
this.#resetTempCanvas();
199+
}
200+
201+
#resetTempCanvas() {
202+
if (this.#tempCanvas) {
203+
this.#tempCanvas.width = this.#tempCanvas.height = 0;
204+
this.#tempCanvas = null;
205+
}
155206
}
156207

157208
async _drawCanvas(options, onCancel, onFinish) {

web/pdf_viewer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ function isValidAnnotationEditorMode(mode) {
139139
* The default value is `true`.
140140
* @property {boolean} [enableAutoLinking] - Enable creation of hyperlinks from
141141
* text that look like URLs. The default value is `true`.
142+
* @property {number} [minDurationToUpdateCanvas] - Minimum duration to wait
143+
* before updating the canvas. The default value is `500`.
142144
*/
143145

144146
class PDFPageViewBuffer {
@@ -243,6 +245,8 @@ class PDFViewer {
243245

244246
#eventAbortController = null;
245247

248+
#minDurationToUpdateCanvas = 0;
249+
246250
#mlManager = null;
247251

248252
#scrollTimeoutId = null;
@@ -342,6 +346,7 @@ class PDFViewer {
342346
this.#enableHWA = options.enableHWA || false;
343347
this.#supportsPinchToZoom = options.supportsPinchToZoom !== false;
344348
this.#enableAutoLinking = options.enableAutoLinking !== false;
349+
this.#minDurationToUpdateCanvas = options.minDurationToUpdateCanvas ?? 500;
345350

346351
this.defaultRenderingQueue = !options.renderingQueue;
347352
if (
@@ -1003,6 +1008,7 @@ class PDFViewer {
10031008
layerProperties: this._layerProperties,
10041009
enableHWA: this.#enableHWA,
10051010
enableAutoLinking: this.#enableAutoLinking,
1011+
minDurationToUpdateCanvas: this.#minDurationToUpdateCanvas,
10061012
});
10071013
this._pages.push(pageView);
10081014
}

0 commit comments

Comments
 (0)