diff --git a/web/page_view.js b/web/page_view.js index 7330f19e7..c6cc9e31e 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -25,6 +25,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, linkService, renderingQueue, cache, pageSource, viewer) { this.id = id; + this.renderingId = 'page' + id; this.rotation = 0; this.scale = scale || 1.0; @@ -610,7 +611,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, viewport: this.viewport, // intent: 'default', // === 'display' continueCallback: function pdfViewcContinueCallback(cont) { - if (self.renderingQueue.highestPriorityPage !== 'page' + self.id) { + if (!self.renderingQueue.isHighestPriority(self)) { self.renderingState = RenderingStates.PAUSED; self.resume = function resumeCallback() { self.renderingState = RenderingStates.RUNNING; diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js new file mode 100644 index 000000000..58424b728 --- /dev/null +++ b/web/pdf_rendering_queue.js @@ -0,0 +1,151 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* 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. + */ +/*globals CLEANUP_TIMEOUT */ + +'use strict'; + +var RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 +}; + +var PDFRenderingQueue = (function PDFRenderingQueueClosure() { + function PDFRenderingQueue() { + this.pdfViewer = null; + this.pdfThumbnailViewer = null; + this.onIdle = null; + + this.highestPriorityPage = null; + this.idleTimeout = null; + this.printing = false; + this.isThumbnailViewEnabled = false; + } + + PDFRenderingQueue.prototype = { + setViewer: function PDFRenderingQueue_setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + }, + + setThumbnailViewer: + function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) { + this.pdfThumbnailViewer = pdfThumbnailViewer; + }, + + isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) { + return this.highestPriorityPage === view.renderingId; + }, + + renderHighestPriority: function + PDFRenderingQueue_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.pdfThumbnailViewer && this.isThumbnailViewEnabled) { + if (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); + } + }, + + getHighestPriority: function + PDFRenderingQueue_getHighestPriority(visible, views, scrolledDown) { + // 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 page after the visible pages + // 2 if last scrolled up page before the visible pages + var visibleViews = visible.views; + + var numVisible = visibleViews.length; + if (numVisible === 0) { + return false; + } + for (var i = 0; i < numVisible; ++i) { + var view = visibleViews[i].view; + if (!this.isViewFinished(view)) { + return view; + } + } + + // All the visible views have rendered, try to render next/previous pages. + if (scrolledDown) { + var nextPageIndex = visible.last.id; + // ID's start at 1 so no need to add 1. + if (views[nextPageIndex] && + !this.isViewFinished(views[nextPageIndex])) { + return views[nextPageIndex]; + } + } else { + var previousPageIndex = visible.first.id - 2; + if (views[previousPageIndex] && + !this.isViewFinished(views[previousPageIndex])) { + return views[previousPageIndex]; + } + } + // Everything that needs to be rendered has been. + return null; + }, + + isViewFinished: function PDFRenderingQueue_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. + renderView: function PDFRenderingQueue_renderView(view) { + var state = view.renderingState; + switch (state) { + 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(this.renderHighestPriority.bind(this)); + break; + } + return true; + }, + }; + + return PDFRenderingQueue; +})(); diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 30f82b534..8e6105d44 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -392,7 +392,7 @@ var PDFViewer = (function pdfViewer() { this.pages, this.scroll.down); if (pageView) { - this.renderingQueue.renderView(pageView, 'page'); + this.renderingQueue.renderView(pageView); return; } }, diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index 38a653dda..efd10a9d1 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -39,6 +39,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, this.pageHeight = this.viewport.height; this.pageRatio = this.pageWidth / this.pageHeight; this.id = id; + this.renderingId = 'thumbnail' + id; this.canvasWidth = 98; this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; @@ -155,7 +156,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, canvasContext: ctx, viewport: drawViewport, continueCallback: function(cont) { - if (self.renderingQueue.highestPriorityPage !== 'thumbnail' + self.id) { + if (!self.renderingQueue.isHighestPriority(self)) { self.renderingState = RenderingStates.PAUSED; self.resume = function() { self.renderingState = RenderingStates.RUNNING; @@ -336,7 +337,7 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { this.thumbnails, this.scroll.down); if (thumbView) { - this.renderingQueue.renderView(thumbView, 'thumbnail'); + this.renderingQueue.renderView(thumbView); return true; } return false; diff --git a/web/viewer.html b/web/viewer.html index 6df149d18..96af7b46e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -68,6 +68,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/ + diff --git a/web/viewer.js b/web/viewer.js index 937a9264f..43b0fea02 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -21,7 +21,7 @@ PasswordPrompt, PresentationMode, HandTool, Promise, DocumentProperties, DocumentOutlineView, DocumentAttachmentsView, OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, - watchScroll, PDFViewer */ + watchScroll, PDFViewer, PDFRenderingQueue */ 'use strict'; @@ -46,12 +46,6 @@ var IGNORE_CURRENT_POSITION_ON_ZOOM = false; //PDFJS.useOnlyCssZoom = true; //PDFJS.disableTextLayer = true; //#endif -var RenderingStates = { - INITIAL: 0, - RUNNING: 1, - PAUSED: 2, - FINISHED: 3 -}; PDFJS.imageResourcesPath = './images/'; //#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME) @@ -106,31 +100,37 @@ var PDFView = { printing: false, pdfViewer: null, pdfThumbnailViewer: null, + pdfRenderingQueue: null, pageRotation: 0, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, lastScroll: 0, isViewerEmbedded: (window.parent !== window), - idleTimeout: null, url: '', // called once when the document is loaded initialize: function pdfViewInitialize() { + var pdfRenderingQueue = new PDFRenderingQueue(); + pdfRenderingQueue.onIdle = this.cleanup.bind(this); + this.pdfRenderingQueue = pdfRenderingQueue; + var container = document.getElementById('viewerContainer'); var viewer = document.getElementById('viewer'); this.pdfViewer = new PDFViewer({ container: container, viewer: viewer, - renderingQueue: this, + renderingQueue: pdfRenderingQueue, linkService: this }); + pdfRenderingQueue.setViewer(this.pdfViewer); var thumbnailContainer = document.getElementById('thumbnailView'); this.pdfThumbnailViewer = new PDFThumbnailViewer({ container: thumbnailContainer, - renderingQueue: this, + renderingQueue: pdfRenderingQueue, linkService: this }); + pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); Preferences.initialize(); @@ -1082,103 +1082,16 @@ var PDFView = { } }, - renderHighestPriority: - function pdfViewRenderHighestPriority(currentlyVisiblePages) { - if (PDFView.idleTimeout) { - clearTimeout(PDFView.idleTimeout); - PDFView.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.sidebarOpen) { - if (this.pdfThumbnailViewer.forceRendering()) { - return; - } - } - - if (this.printing) { - // If printing is currently ongoing do not reschedule cleanup. - return; - } - - PDFView.idleTimeout = setTimeout(function () { - PDFView.cleanup(); - }, CLEANUP_TIMEOUT); - }, - cleanup: function pdfViewCleanup() { this.pdfViewer.cleanup(); this.pdfThumbnailViewer.cleanup(); this.pdfDocument.cleanup(); }, - getHighestPriority: function pdfViewGetHighestPriority(visible, views, - scrolledDown) { - // 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 page after the visible pages - // 2 if last scrolled up page before the visible pages - var visibleViews = visible.views; - - var numVisible = visibleViews.length; - if (numVisible === 0) { - return false; - } - for (var i = 0; i < numVisible; ++i) { - var view = visibleViews[i].view; - if (!this.isViewFinished(view)) { - return view; - } - } - - // All the visible views have rendered, try to render next/previous pages. - if (scrolledDown) { - var nextPageIndex = visible.last.id; - // ID's start at 1 so no need to add 1. - if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { - return views[nextPageIndex]; - } - } else { - var previousPageIndex = visible.first.id - 2; - if (views[previousPageIndex] && - !this.isViewFinished(views[previousPageIndex])) { - return views[previousPageIndex]; - } - } - // Everything that needs to be rendered has been. - return false; - }, - - isViewFinished: function pdfViewIsViewFinished(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. - renderView: function pdfViewRender(view, type) { - var state = view.renderingState; - switch (state) { - case RenderingStates.FINISHED: - return false; - case RenderingStates.PAUSED: - PDFView.highestPriorityPage = type + view.id; - view.resume(); - break; - case RenderingStates.RUNNING: - PDFView.highestPriorityPage = type + view.id; - break; - case RenderingStates.INITIAL: - PDFView.highestPriorityPage = type + view.id; - view.draw(this.renderHighestPriority.bind(this)); - break; - } - return true; + forceRendering: function pdfViewForceRendering() { + this.pdfRenderingQueue.printing = this.printing; + this.pdfRenderingQueue.isThumbnailViewEnabled = this.sidebarOpen; + this.pdfRenderingQueue.renderHighestPriority(); }, setHash: function pdfViewSetHash(hash) { @@ -1266,7 +1179,7 @@ var PDFView = { outlineView.classList.add('hidden'); attachmentsView.classList.add('hidden'); - PDFView.renderHighestPriority(); + PDFView.forceRendering(); if (wasAnotherViewVisible) { this.pdfThumbnailViewer.ensureThumbnailVisible(this.page); @@ -1342,7 +1255,7 @@ var PDFView = { } this.printing = true; - this.renderHighestPriority(); + this.forceRendering(); var body = document.querySelector('body'); body.setAttribute('data-mozPrintCallback', true); @@ -1364,7 +1277,7 @@ var PDFView = { } this.printing = false; - this.renderHighestPriority(); + this.forceRendering(); }, setScale: function (value, resetAutoSettings, noScroll) { @@ -1378,7 +1291,7 @@ var PDFView = { this.pdfViewer.updateRotation(this.pageRotation); this.pdfThumbnailViewer.updateRotation(this.pageRotation); - this.renderHighestPriority(); + this.forceRendering(); if (currentPage) { currentPage.scrollIntoView(); @@ -1454,6 +1367,7 @@ var PDFView = { } }; +//#include pdf_rendering_queue.js //#include page_view.js //#include pdf_viewer.js //#include thumbnail_view.js @@ -1635,7 +1549,7 @@ function webViewerInitialized() { outerContainer.classList.add('sidebarMoving'); outerContainer.classList.toggle('sidebarOpen'); PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen'); - PDFView.renderHighestPriority(); + PDFView.forceRendering(); }); document.getElementById('viewThumbnail').addEventListener('click',