Skip to content

Commit dc5d6aa

Browse files
Avoid degrading scroll performance due to the detail view
When scrolling quickly, the constant re-rendering of the detail view significantly affects rendering performance, causing Firefox to not render even the _background canvas_, which is just a static canvas not being re-drawn by JavaScript. This commit changes the viewer to only render the detail view while scrolling if its rendering hasn't just been cancelled. This means that: - when the user is scrolling slowly, we have enough time to render the detail view before that we need to change its area, so the user always sees the full screen as high resolution. - when the user is scrolling quickly, as soon as we have to cancel a rendering we just give up, and the user will see the lower resolution canvas. When then the user stops scrolling, we render the detail view for the new visible area.
1 parent 458b2ee commit dc5d6aa

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

web/pdf_page_detail_view.js

+22
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ import { RenderingStates } from "./ui_utils.js";
2424
class PDFPageDetailView extends BasePDFPageView {
2525
#detailArea = null;
2626

27+
/**
28+
* @type {boolean} True when the last rendering attempt of the view was
29+
* cancelled due to a `.reset()` call. This will happen when
30+
* the visible area changes so much during the rendering that
31+
* we need to cancel the rendering and start over.
32+
*/
33+
renderingCancelled = false;
34+
2735
constructor({ pageView }) {
2836
super(pageView);
2937

@@ -41,9 +49,23 @@ class PDFPageDetailView extends BasePDFPageView {
4149
return this.pageView.pdfPage;
4250
}
4351

52+
get renderingState() {
53+
return super.renderingState;
54+
}
55+
56+
set renderingState(value) {
57+
this.renderingCancelled = false;
58+
super.renderingState = value;
59+
}
60+
4461
reset({ keepCanvas = false } = {}) {
62+
const renderingCancelled =
63+
this.renderingCancelled ||
64+
this.renderingState === RenderingStates.RUNNING ||
65+
this.renderingState === RenderingStates.PAUSED;
4566
this.cancelRendering();
4667
this.renderingState = RenderingStates.INITIAL;
68+
this.renderingCancelled = renderingCancelled;
4769

4870
if (!keepCanvas) {
4971
this._resetCanvas();

web/pdf_rendering_queue.js

+15-6
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,22 @@ class PDFRenderingQueue {
102102
* @param {Array} views
103103
* @param {boolean} scrolledDown
104104
* @param {boolean} [preRenderExtra]
105+
* @param {boolean} [ignoreDetailViews]
105106
*/
106-
getHighestPriority(visible, views, scrolledDown, preRenderExtra = false) {
107+
getHighestPriority(
108+
visible,
109+
views,
110+
scrolledDown,
111+
preRenderExtra = false,
112+
ignoreDetailViews = false
113+
) {
107114
/**
108115
* The state has changed. Figure out which page has the highest priority to
109116
* render next (if any).
110117
*
111118
* Priority:
112119
* 1. visible pages
113-
* 2. zoomed-in partial views of visible pages
120+
* 2. zoomed-in partial views of visible pages, unless `ignoreDetailViews`
114121
* 3. if last scrolled down, the page after the visible pages, or
115122
* if last scrolled up, the page before the visible pages
116123
*/
@@ -127,10 +134,12 @@ class PDFRenderingQueue {
127134
}
128135
}
129136

130-
for (let i = 0; i < numVisible; i++) {
131-
const { detailView } = visibleViews[i].view;
132-
if (detailView && !this.isViewFinished(detailView)) {
133-
return detailView;
137+
if (!ignoreDetailViews) {
138+
for (let i = 0; i < numVisible; i++) {
139+
const { detailView } = visibleViews[i].view;
140+
if (detailView && !this.isViewFinished(detailView)) {
141+
return detailView;
142+
}
134143
}
135144
}
136145

web/pdf_thumbnail_viewer.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ class PDFThumbnailViewer {
292292
const thumbView = this.renderingQueue.getHighestPriority(
293293
visibleThumbs,
294294
this._thumbnails,
295-
scrollAhead
295+
scrollAhead,
296+
/* preRenderExtra */ false,
297+
/* ignoreDetailViews */ true
296298
);
297299
if (thumbView) {
298300
this.#ensurePdfPageLoaded(thumbView).then(() => {

web/pdf_viewer.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ class PDFViewer {
241241

242242
#mlManager = null;
243243

244+
#scrollTimeoutId = null;
245+
244246
#switchAnnotationEditorModeAC = null;
245247

246248
#switchAnnotationEditorModeTimeoutId = null;
@@ -1241,6 +1243,15 @@ class PDFViewer {
12411243
if (this.pagesCount === 0) {
12421244
return;
12431245
}
1246+
1247+
if (this.#scrollTimeoutId) {
1248+
clearTimeout(this.#scrollTimeoutId);
1249+
}
1250+
this.#scrollTimeoutId = setTimeout(() => {
1251+
this.#scrollTimeoutId = null;
1252+
this.update();
1253+
}, 100);
1254+
12441255
this.update();
12451256
}
12461257

@@ -1851,11 +1862,21 @@ class PDFViewer {
18511862
this._spreadMode !== SpreadMode.NONE &&
18521863
this._scrollMode !== ScrollMode.HORIZONTAL;
18531864

1865+
// If we are scrolling and the rendering of a detail view was just
1866+
// cancelled, it's because the user is scrolling too quickly and so
1867+
// we constantly need to re-render a different area.
1868+
// Don't attempt to re-render it: this will be done once the user
1869+
// stops scrolling.
1870+
const ignoreDetailViews =
1871+
this.#scrollTimeoutId !== null &&
1872+
visiblePages.views.some(page => page.detailView?.renderingCancelled);
1873+
18541874
const pageView = this.renderingQueue.getHighestPriority(
18551875
visiblePages,
18561876
this._pages,
18571877
scrollAhead,
1858-
preRenderExtra
1878+
preRenderExtra,
1879+
ignoreDetailViews
18591880
);
18601881

18611882
if (pageView) {
@@ -2449,6 +2470,10 @@ class PDFViewer {
24492470
clearTimeout(this.#scaleTimeoutId);
24502471
this.#scaleTimeoutId = null;
24512472
}
2473+
if (this.#scrollTimeoutId !== null) {
2474+
clearTimeout(this.#scrollTimeoutId);
2475+
this.#scrollTimeoutId = null;
2476+
}
24522477
if (!noUpdate) {
24532478
this.update();
24542479
}

0 commit comments

Comments
 (0)