From fb6c807ba2d5718fb2ca100a738d3df9ca95e402 Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Sat, 2 Oct 2021 11:24:29 +0200
Subject: [PATCH 1/2] Reduce unnecessary duplication in
 `PDFRenderingQueue.getHighestPriority`

---
 web/pdf_rendering_queue.js | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js
index 7e96c9d2c..1057f3e70 100644
--- a/web/pdf_rendering_queue.js
+++ b/web/pdf_rendering_queue.js
@@ -126,21 +126,15 @@ class PDFRenderingQueue {
       }
     }
 
-    // All the visible views have rendered; try to render next/previous pages.
-    if (scrolledDown) {
-      const nextPageIndex = visible.last.id;
-      // IDs start at 1, so no need to add 1.
-      if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {
-        return views[nextPageIndex];
-      }
-    } else {
-      const previousPageIndex = visible.first.id - 2;
-      if (
-        views[previousPageIndex] &&
-        !this.isViewFinished(views[previousPageIndex])
-      ) {
-        return views[previousPageIndex];
-      }
+    // All the visible views have rendered; try to render next/previous page.
+    // (IDs start at 1, so no need to add 1 when `scrolledDown === true`.)
+    const preRenderIndex = scrolledDown
+      ? visible.last.id
+      : visible.first.id - 2;
+    const preRenderView = views[preRenderIndex];
+
+    if (preRenderView && !this.isViewFinished(preRenderView)) {
+      return preRenderView;
     }
     // Everything that needs to be rendered has been.
     return null;

From e4794a678ac27a0fed2296e95f3043356c78ec10 Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Sat, 2 Oct 2021 11:43:58 +0200
Subject: [PATCH 2/2] Pre-render *one* additional page when spreadModes are
 enabled

Please note that we (obviously) don't want to unconditionally pre-render more than one page all the time, since that could very easily lead to overall worse performance in some documents.[1]
However, when spreadModes are enabled it does make sense to attempt to pre-render both of the pages of the next/previous spread.

---
[1] Since it may cause pre-rendering to unnecessarily compete for parsing resources, on the worker-thread, with "regular" rendering.
---
 web/base_viewer.js         |  8 +++++++-
 web/pdf_rendering_queue.js | 17 ++++++++++++-----
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/web/base_viewer.js b/web/base_viewer.js
index b1b1086da..54ed21e6e 100644
--- a/web/base_viewer.js
+++ b/web/base_viewer.js
@@ -1250,10 +1250,16 @@ class BaseViewer {
     const scrollAhead = this._isScrollModeHorizontal
       ? this.scroll.right
       : this.scroll.down;
+    const preRenderExtra =
+      this._scrollMode === ScrollMode.VERTICAL &&
+      this._spreadMode !== SpreadMode.NONE &&
+      !this.isInPresentationMode;
+
     const pageView = this.renderingQueue.getHighestPriority(
       visiblePages,
       this._pages,
-      scrollAhead
+      scrollAhead,
+      preRenderExtra
     );
     if (pageView) {
       this._ensurePdfPageLoaded(pageView).then(() => {
diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js
index 1057f3e70..d43d1dd30 100644
--- a/web/pdf_rendering_queue.js
+++ b/web/pdf_rendering_queue.js
@@ -102,8 +102,9 @@ class PDFRenderingQueue {
    * @param {Object} visible
    * @param {Array} views
    * @param {boolean} scrolledDown
+   * @param {boolean} [preRenderExtra]
    */
-  getHighestPriority(visible, views, scrolledDown) {
+  getHighestPriority(visible, views, scrolledDown, preRenderExtra = false) {
     /**
      * The state has changed. Figure out which page has the highest priority to
      * render next (if any).
@@ -128,14 +129,20 @@ class PDFRenderingQueue {
 
     // All the visible views have rendered; try to render next/previous page.
     // (IDs start at 1, so no need to add 1 when `scrolledDown === true`.)
-    const preRenderIndex = scrolledDown
-      ? visible.last.id
-      : visible.first.id - 2;
-    const preRenderView = views[preRenderIndex];
+    let preRenderIndex = scrolledDown ? visible.last.id : visible.first.id - 2;
+    let preRenderView = views[preRenderIndex];
 
     if (preRenderView && !this.isViewFinished(preRenderView)) {
       return preRenderView;
     }
+    if (preRenderExtra) {
+      preRenderIndex += scrolledDown ? 1 : -1;
+      preRenderView = views[preRenderIndex];
+
+      if (preRenderView && !this.isViewFinished(preRenderView)) {
+        return preRenderView;
+      }
+    }
     // Everything that needs to be rendered has been.
     return null;
   }