123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /* Copyright 2012 Mozilla Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /** @typedef {import("./interfaces").IRenderableView} IRenderableView */
- /** @typedef {import("./pdf_viewer").PDFViewer} PDFViewer */
- // eslint-disable-next-line max-len
- /** @typedef {import("./pdf_thumbnail_viewer").PDFThumbnailViewer} PDFThumbnailViewer */
- import { RenderingCancelledException } from "pdfjs-lib";
- import { RenderingStates } from "./ui_utils.js";
- const CLEANUP_TIMEOUT = 30000;
- /**
- * Controls rendering of the views for pages and thumbnails.
- */
- class PDFRenderingQueue {
- constructor() {
- this.pdfViewer = null;
- this.pdfThumbnailViewer = null;
- this.onIdle = null;
- this.highestPriorityPage = null;
- /** @type {number} */
- this.idleTimeout = null;
- this.printing = false;
- this.isThumbnailViewEnabled = false;
- }
- /**
- * @param {PDFViewer} pdfViewer
- */
- setViewer(pdfViewer) {
- this.pdfViewer = pdfViewer;
- }
- /**
- * @param {PDFThumbnailViewer} pdfThumbnailViewer
- */
- setThumbnailViewer(pdfThumbnailViewer) {
- this.pdfThumbnailViewer = pdfThumbnailViewer;
- }
- /**
- * @param {IRenderableView} view
- * @returns {boolean}
- */
- isHighestPriority(view) {
- return this.highestPriorityPage === view.renderingId;
- }
- /**
- * @returns {boolean}
- */
- hasViewer() {
- return !!this.pdfViewer;
- }
- /**
- * @param {Object} currentlyVisiblePages
- */
- renderHighestPriority(currentlyVisiblePages) {
- if (this.idleTimeout) {
- clearTimeout(this.idleTimeout);
- this.idleTimeout = null;
- }
- // Pages have a higher priority than thumbnails, so check them first.
- if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
- return;
- }
- // No pages needed rendering, so check thumbnails.
- if (
- this.isThumbnailViewEnabled &&
- this.pdfThumbnailViewer?.forceRendering()
- ) {
- return;
- }
- if (this.printing) {
- // If printing is currently ongoing do not reschedule cleanup.
- return;
- }
- if (this.onIdle) {
- this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
- }
- }
- /**
- * @param {Object} visible
- * @param {Array} views
- * @param {boolean} scrolledDown
- * @param {boolean} [preRenderExtra]
- */
- getHighestPriority(visible, views, scrolledDown, preRenderExtra = false) {
- /**
- * The state has changed. Figure out which page has the highest priority to
- * render next (if any).
- *
- * Priority:
- * 1. visible pages
- * 2. if last scrolled down, the page after the visible pages, or
- * if last scrolled up, the page before the visible pages
- */
- const visibleViews = visible.views,
- numVisible = visibleViews.length;
- if (numVisible === 0) {
- return null;
- }
- for (let i = 0; i < numVisible; i++) {
- const view = visibleViews[i].view;
- if (!this.isViewFinished(view)) {
- return view;
- }
- }
- const firstId = visible.first.id,
- lastId = visible.last.id;
- // All the visible views have rendered; try to handle any "holes" in the
- // page layout (can happen e.g. with spreadModes at higher zoom levels).
- if (lastId - firstId + 1 > numVisible) {
- const visibleIds = visible.ids;
- for (let i = 1, ii = lastId - firstId; i < ii; i++) {
- const holeId = scrolledDown ? firstId + i : lastId - i;
- if (visibleIds.has(holeId)) {
- continue;
- }
- const holeView = views[holeId - 1];
- if (!this.isViewFinished(holeView)) {
- return holeView;
- }
- }
- }
- // 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`.)
- let preRenderIndex = scrolledDown ? lastId : firstId - 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;
- }
- /**
- * @param {IRenderableView} view
- * @returns {boolean}
- */
- isViewFinished(view) {
- return view.renderingState === RenderingStates.FINISHED;
- }
- /**
- * Render a page or thumbnail view. This calls the appropriate function
- * based on the views state. If the view is already rendered it will return
- * `false`.
- *
- * @param {IRenderableView} view
- */
- renderView(view) {
- switch (view.renderingState) {
- case RenderingStates.FINISHED:
- return false;
- case RenderingStates.PAUSED:
- this.highestPriorityPage = view.renderingId;
- view.resume();
- break;
- case RenderingStates.RUNNING:
- this.highestPriorityPage = view.renderingId;
- break;
- case RenderingStates.INITIAL:
- this.highestPriorityPage = view.renderingId;
- view
- .draw()
- .finally(() => {
- this.renderHighestPriority();
- })
- .catch(reason => {
- if (reason instanceof RenderingCancelledException) {
- return;
- }
- console.error(`renderView: "${reason}"`);
- });
- break;
- }
- return true;
- }
- }
- export { PDFRenderingQueue };
|