Re-factor updating of thumbnails in the PDFSidebar-class

This patch does two things:
 - Moves the updating of thumbnails into `web/app.js`, via a new `PDFSidebar` callback-function, to avoid having to include otherwise unnecessary parameters when initializing a `PDFSidebar`-instance.
 - Only attempt to generate thumbnail-images from pages that are *cached* in the viewer. Note that only pages that exist in the `PDFPageViewBuffer`-instance can be rendered, hence it's not actually meaningful to check every single page when updating the thumbnails.
   For large documents, with thousands of pages, this should be a tiny bit more efficient when e.g. opening the sidebar since we no longer need to check pages that we know have not been rendered.
This commit is contained in:
Jonas Jenwald 2023-05-28 12:30:18 +02:00
parent 0e604f8f42
commit c4c8227d20
3 changed files with 22 additions and 27 deletions

View File

@ -667,12 +667,23 @@ const PDFViewerApplication = {
if (appConfig.sidebar) { if (appConfig.sidebar) {
this.pdfSidebar = new PDFSidebar({ this.pdfSidebar = new PDFSidebar({
elements: appConfig.sidebar, elements: appConfig.sidebar,
pdfViewer,
pdfThumbnailViewer: this.pdfThumbnailViewer,
eventBus, eventBus,
l10n, l10n,
}); });
this.pdfSidebar.onToggled = this.forceRendering.bind(this); this.pdfSidebar.onToggled = this.forceRendering.bind(this);
this.pdfSidebar.onUpdateThumbnails = () => {
// Use the rendered pages to set the corresponding thumbnail images.
for (const pageView of pdfViewer.getCachedPageViews()) {
if (pageView.renderingState === RenderingStates.FINISHED) {
this.pdfThumbnailViewer
.getThumbnail(pageView.id - 1)
?.setImage(pageView);
}
}
this.pdfThumbnailViewer.scrollThumbnailIntoView(
pdfViewer.currentPageNumber
);
};
} }
}, },

View File

@ -16,7 +16,6 @@
import { import {
docStyle, docStyle,
PresentationModeState, PresentationModeState,
RenderingStates,
SidebarView, SidebarView,
toggleCheckedBtn, toggleCheckedBtn,
toggleExpandedBtn, toggleExpandedBtn,
@ -30,8 +29,6 @@ const UI_NOTIFICATION_CLASS = "pdfSidebarNotification";
/** /**
* @typedef {Object} PDFSidebarOptions * @typedef {Object} PDFSidebarOptions
* @property {PDFSidebarElements} elements - The DOM elements. * @property {PDFSidebarElements} elements - The DOM elements.
* @property {PDFViewer} pdfViewer - The document viewer.
* @property {PDFThumbnailViewer} pdfThumbnailViewer - The thumbnail viewer.
* @property {EventBus} eventBus - The application event bus. * @property {EventBus} eventBus - The application event bus.
* @property {IL10n} l10n - The localization service. * @property {IL10n} l10n - The localization service.
*/ */
@ -82,7 +79,7 @@ class PDFSidebar {
/** /**
* @param {PDFSidebarOptions} options * @param {PDFSidebarOptions} options
*/ */
constructor({ elements, pdfViewer, pdfThumbnailViewer, eventBus, l10n }) { constructor({ elements, eventBus, l10n }) {
this.isOpen = false; this.isOpen = false;
this.active = SidebarView.THUMBS; this.active = SidebarView.THUMBS;
this.isInitialViewSet = false; this.isInitialViewSet = false;
@ -93,9 +90,7 @@ class PDFSidebar {
* the viewers (PDFViewer/PDFThumbnailViewer) are updated correctly. * the viewers (PDFViewer/PDFThumbnailViewer) are updated correctly.
*/ */
this.onToggled = null; this.onToggled = null;
this.onUpdateThumbnails = null;
this.pdfViewer = pdfViewer;
this.pdfThumbnailViewer = pdfThumbnailViewer;
this.outerContainer = elements.outerContainer; this.outerContainer = elements.outerContainer;
this.sidebarContainer = elements.sidebarContainer; this.sidebarContainer = elements.sidebarContainer;
@ -246,7 +241,7 @@ class PDFSidebar {
return; // Opening will trigger rendering and dispatch the event. return; // Opening will trigger rendering and dispatch the event.
} }
if (forceRendering) { if (forceRendering) {
this.#updateThumbnailViewer(); this.onUpdateThumbnails();
this.onToggled(); this.onToggled();
} }
if (isViewChanged) { if (isViewChanged) {
@ -264,7 +259,7 @@ class PDFSidebar {
this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); this.outerContainer.classList.add("sidebarMoving", "sidebarOpen");
if (this.active === SidebarView.THUMBS) { if (this.active === SidebarView.THUMBS) {
this.#updateThumbnailViewer(); this.onUpdateThumbnails();
} }
this.onToggled(); this.onToggled();
this.#dispatchEvent(); this.#dispatchEvent();
@ -305,21 +300,6 @@ class PDFSidebar {
}); });
} }
#updateThumbnailViewer() {
const { pdfViewer, pdfThumbnailViewer } = this;
// Use the rendered pages to set the corresponding thumbnail images.
const pagesCount = pdfViewer.pagesCount;
for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
const pageView = pdfViewer.getPageView(pageIndex);
if (pageView?.renderingState === RenderingStates.FINISHED) {
const thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex);
thumbnailView.setImage(pageView);
}
}
pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
}
#showUINotification() { #showUINotification() {
this.toggleButton.setAttribute( this.toggleButton.setAttribute(
"data-l10n-id", "data-l10n-id",
@ -428,7 +408,7 @@ class PDFSidebar {
evt.state === PresentationModeState.NORMAL && evt.state === PresentationModeState.NORMAL &&
this.visibleView === SidebarView.THUMBS this.visibleView === SidebarView.THUMBS
) { ) {
this.#updateThumbnailViewer(); this.onUpdateThumbnails();
} }
}); });

View File

@ -341,6 +341,10 @@ class PDFViewer {
return this._pages[index]; return this._pages[index];
} }
getCachedPageViews() {
return new Set(this.#buffer);
}
/** /**
* @type {boolean} - True if all {PDFPageView} objects are initialized. * @type {boolean} - True if all {PDFPageView} objects are initialized.
*/ */