Skip to content

Commit

Permalink
Avoid degrading scroll performance due to the detail view
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nicolo-ribaudo committed Jan 23, 2025
1 parent 7629b24 commit 08f526f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
22 changes: 22 additions & 0 deletions web/pdf_page_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,14 @@ class PDFPageView extends PDFPageViewBase {
class PDFPageDetailView extends PDFPageViewBase {
#detailArea = null;

/**
* @type {boolean} True when the last rendering attempt of the view was
* cancelled due to a `.reset()` call. This will happen when
* the visible area changes so much during the rendering that
* we need to cancel the rendering and start over.
*/
renderingCancelled = false;

constructor({ pageView }) {
super(pageView);

Expand All @@ -1320,9 +1328,23 @@ class PDFPageDetailView extends PDFPageViewBase {
return this.pageView.pdfPage;
}

get renderingState() {
return super.renderingState;
}

set renderingState(value) {
this.renderingCancelled = false;
super.renderingState = value;
}

reset({ keepCanvas = false } = {}) {
const renderingCancelled =
this.renderingCancelled ||
this.renderingState === RenderingStates.RUNNING ||
this.renderingState === RenderingStates.PAUSED;
this.cancelRendering();
this.renderingState = RenderingStates.INITIAL;
this.renderingCancelled = renderingCancelled;

if (!keepCanvas) {
this._resetCanvas();
Expand Down
29 changes: 28 additions & 1 deletion web/pdf_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ import {
VERTICAL_PADDING,
watchScroll,
} from "./ui_utils.js";
import { PDFPageDetailView, PDFPageView } from "./pdf_page_view.js";
import { GenericL10n } from "web-null_l10n";
import { PDFPageView } from "./pdf_page_view.js";
import { PDFRenderingQueue } from "./pdf_rendering_queue.js";
import { SimpleLinkService } from "./pdf_link_service.js";

Expand Down Expand Up @@ -237,6 +237,8 @@ class PDFViewer {

#mlManager = null;

#scrollTimeoutId = null;

#switchAnnotationEditorModeAC = null;

#switchAnnotationEditorModeTimeoutId = null;
Expand Down Expand Up @@ -1233,6 +1235,15 @@ class PDFViewer {
if (this.pagesCount === 0) {
return;
}

if (this.#scrollTimeoutId) {
clearTimeout(this.#scrollTimeoutId);
}
this.#scrollTimeoutId = setTimeout(() => {
this.#scrollTimeoutId = null;
this.update();
}, 100);

this.update();
}

Expand Down Expand Up @@ -1851,6 +1862,18 @@ class PDFViewer {
);

if (pageView) {
if (
this.#scrollTimeoutId !== null &&
pageView instanceof PDFPageDetailView &&
pageView.renderingCancelled
) {
// If we are scrolling and the rendering of the detail view was just
// cancelled, it's because the user is scrolling too quickly and so
// we constantly need to re-render a different area.
// Don't attempt to re-rendering it: this will be done once the user
// stops scrolling.
return true;
}
this.#ensurePdfPageLoaded(pageView).then(() => {
this.renderingQueue.renderView(pageView);
});
Expand Down Expand Up @@ -2420,6 +2443,10 @@ class PDFViewer {
clearTimeout(this.#scaleTimeoutId);
this.#scaleTimeoutId = null;
}
if (this.#scrollTimeoutId !== null) {
clearTimeout(this.#scrollTimeoutId);
this.#scrollTimeoutId = null;
}
if (!noUpdate) {
this.update();
}
Expand Down

0 comments on commit 08f526f

Please sign in to comment.