diff --git a/web/base_viewer.js b/web/base_viewer.js index cd78a11a2..3ea105873 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -54,6 +54,11 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js"; const DEFAULT_CACHE_SIZE = 10; +const PagesCountLimit = { + FORCE_SCROLL_MODE_PAGE: 15000, + FORCE_LAZY_PAGE_INIT: 7500, +}; + /** * @typedef {Object} PDFViewerOptions * @property {HTMLDivElement} container - The container for the viewer element. @@ -515,6 +520,16 @@ class BaseViewer { // Rendering (potentially) depends on this, hence fetching it immediately. const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + // Given that browsers don't handle huge amounts of DOM-elements very well, + // enforce usage of PAGE-scrolling when loading *very* long/large documents. + if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + console.warn( + "Forcing PAGE-scrolling for performance reasons, given the length of the document." + ); + const mode = (this._scrollMode = ScrollMode.PAGE); + this.eventBus.dispatch("scrollmodechanged", { source: this, mode }); + } + this._pagesCapability.promise.then(() => { this.eventBus.dispatch("pagesloaded", { source: this, @@ -618,7 +633,10 @@ class BaseViewer { // In addition to 'disableAutoFetch' being set, also attempt to reduce // resource usage when loading *very* long/large documents. - if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > 7500) { + if ( + pdfDocument.loadingParams.disableAutoFetch || + pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT + ) { // XXX: Printing is semi-broken with auto fetch disabled. this._pagesCapability.resolve(); return; @@ -1685,6 +1703,9 @@ class BaseViewer { if (!isValidScrollMode(mode)) { throw new Error(`Invalid scroll mode: ${mode}`); } + if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + return; // Disabled for performance reasons. + } this._previousScrollMode = this._scrollMode; this._scrollMode = mode; @@ -1957,4 +1978,4 @@ class BaseViewer { } } -export { BaseViewer, PDFPageViewBuffer }; +export { BaseViewer, PagesCountLimit, PDFPageViewBuffer }; diff --git a/web/secondary_toolbar.js b/web/secondary_toolbar.js index 468dd69c9..3b1f33d44 100644 --- a/web/secondary_toolbar.js +++ b/web/secondary_toolbar.js @@ -15,7 +15,7 @@ import { SCROLLBAR_PADDING, ScrollMode, SpreadMode } from "./ui_utils.js"; import { CursorTool } from "./pdf_cursor_tools.js"; -import { PDFSinglePageViewer } from "./pdf_viewer.js"; +import { PagesCountLimit } from "./base_viewer.js"; /** * @typedef {Object} SecondaryToolbarOptions @@ -166,22 +166,6 @@ class SecondaryToolbar { // Bind the event listener for adjusting the 'max-height' of the toolbar. this.eventBus._on("resize", this._setMaxHeight.bind(this)); - - // Hide the Scroll/Spread mode buttons, when they're not applicable to the - // current `BaseViewer` instance (in particular `PDFSinglePageViewer`). - this.eventBus._on("baseviewerinit", evt => { - if (evt.source instanceof PDFSinglePageViewer) { - this.toolbarButtonContainer.classList.add( - "hiddenScrollModeButtons", - "hiddenSpreadModeButtons" - ); - } else { - this.toolbarButtonContainer.classList.remove( - "hiddenScrollModeButtons", - "hiddenSpreadModeButtons" - ); - } - }); } /** @@ -252,7 +236,7 @@ class SecondaryToolbar { } _bindScrollModeListener(buttons) { - function scrollModeChanged({ mode }) { + const scrollModeChanged = ({ mode }) => { buttons.scrollPageButton.classList.toggle( "toggled", mode === ScrollMode.PAGE @@ -270,13 +254,22 @@ class SecondaryToolbar { mode === ScrollMode.WRAPPED ); + // Permanently *disable* the Scroll buttons when PAGE-scrolling is being + // enforced for *very* long/large documents; please see the `BaseViewer`. + const forceScrollModePage = + this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE; + buttons.scrollPageButton.disabled = forceScrollModePage; + buttons.scrollVerticalButton.disabled = forceScrollModePage; + buttons.scrollHorizontalButton.disabled = forceScrollModePage; + buttons.scrollWrappedButton.disabled = forceScrollModePage; + // Temporarily *disable* the Spread buttons when horizontal scrolling is // enabled, since the non-default Spread modes doesn't affect the layout. const isScrollModeHorizontal = mode === ScrollMode.HORIZONTAL; buttons.spreadNoneButton.disabled = isScrollModeHorizontal; buttons.spreadOddButton.disabled = isScrollModeHorizontal; buttons.spreadEvenButton.disabled = isScrollModeHorizontal; - } + }; this.eventBus._on("scrollmodechanged", scrollModeChanged); this.eventBus._on("secondarytoolbarreset", evt => { diff --git a/web/viewer.css b/web/viewer.css index df33a5054..a8810c528 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -625,11 +625,6 @@ html[dir="rtl"] .secondaryToolbar { margin-bottom: -4px; } -#secondaryToolbarButtonContainer.hiddenScrollModeButtons > .scrollModeButtons, -#secondaryToolbarButtonContainer.hiddenSpreadModeButtons > .spreadModeButtons { - display: none !important; -} - .doorHanger, .doorHangerRight { border-radius: 2px; diff --git a/web/viewer.html b/web/viewer.html index c49aee352..2c22f29ab 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -196,32 +196,32 @@ See https://github.com/adobe-type-tools/cmap-resources
-