From bfefadb87c10857a11a0e66451e77d35bcd20a31 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 12 Sep 2014 13:39:23 -0500 Subject: [PATCH 01/11] Moves watchScroll and getVisibleElements from PDFView --- web/ui_utils.js | 85 ++++++++++++++++++++++++++++++++++++++++++++ web/viewer.js | 94 +++++-------------------------------------------- 2 files changed, 94 insertions(+), 85 deletions(-) diff --git a/web/ui_utils.js b/web/ui_utils.js index b38ec4bc3..04805c053 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -138,6 +138,91 @@ function scrollIntoView(element, spot) { parent.scrollTop = offsetY; } +/** + * Helper function to start monitoring the scroll event and converting them into + * PDF.js friendly one: with scroll debounce and scroll direction. + */ +function watchScroll(viewAreaElement, callback) { + var debounceScroll = function debounceScroll(evt) { + if (rAF) { + return; + } + // schedule an invocation of scroll for next animation frame. + rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { + rAF = null; + + var currentY = viewAreaElement.scrollTop; + var lastY = state.lastY; + if (currentY > lastY) { + state.down = true; + } else if (currentY < lastY) { + state.down = false; + } + state.lastY = currentY; + // else do nothing and use previous value + callback(state); + }); + }; + + var state = { + down: true, + lastY: viewAreaElement.scrollTop, + _eventHandler: debounceScroll + }; + + var rAF = null; + viewAreaElement.addEventListener('scroll', debounceScroll, true); + return state; +} + +/** + * Generic helper to find out what elements are visible within a scroll pane. + */ +function getVisibleElements(scrollEl, views, sortByVisibility) { + var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; + var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; + + var visible = [], view; + var currentHeight, viewHeight, hiddenHeight, percentHeight; + var currentWidth, viewWidth; + for (var i = 0, ii = views.length; i < ii; ++i) { + view = views[i]; + currentHeight = view.el.offsetTop + view.el.clientTop; + viewHeight = view.el.clientHeight; + if ((currentHeight + viewHeight) < top) { + continue; + } + if (currentHeight > bottom) { + break; + } + currentWidth = view.el.offsetLeft + view.el.clientLeft; + viewWidth = view.el.clientWidth; + if ((currentWidth + viewWidth) < left || currentWidth > right) { + continue; + } + hiddenHeight = Math.max(0, top - currentHeight) + + Math.max(0, currentHeight + viewHeight - bottom); + percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; + + visible.push({ id: view.id, x: currentWidth, y: currentHeight, + view: view, percent: percentHeight }); + } + + var first = visible[0]; + var last = visible[visible.length - 1]; + + if (sortByVisibility) { + visible.sort(function(a, b) { + var pc = a.percent - b.percent; + if (Math.abs(pc) > 0.001) { + return -pc; + } + return a.id - b.id; // ensure stability + }); + } + return {first: first, last: last, views: visible}; +} + /** * Event handler to suppress context menu. */ diff --git a/web/viewer.js b/web/viewer.js index 7828db204..6cd58fb0c 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -20,7 +20,8 @@ ThumbnailView, URL, noContextMenuHandler, SecondaryToolbar, PasswordPrompt, PresentationMode, HandTool, Promise, DocumentProperties, DocumentOutlineView, DocumentAttachmentsView, - OverlayManager, PDFFindController, PDFFindBar */ + OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, + watchScroll */ 'use strict'; @@ -134,14 +135,14 @@ var PDFView = { initialize: function pdfViewInitialize() { var self = this; var container = this.container = document.getElementById('viewerContainer'); - this.pageViewScroll = {}; - this.watchScroll(container, this.pageViewScroll, updateViewarea); + this.pageViewScroll = watchScroll(container, updateViewarea); var thumbnailContainer = this.thumbnailContainer = document.getElementById('thumbnailView'); - this.thumbnailViewScroll = {}; - this.watchScroll(thumbnailContainer, this.thumbnailViewScroll, - this.renderHighestPriority.bind(this)); + this.thumbnailViewScroll = watchScroll(thumbnailContainer, function () { + this.renderHighestPriority(); + }.bind(this)); + Preferences.initialize(); @@ -272,36 +273,6 @@ var PDFView = { return this.pdfDocument.getPage(n); }, - // Helper function to keep track whether a div was scrolled up or down and - // then call a callback. - watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) { - state.down = true; - state.lastY = viewAreaElement.scrollTop; - state.rAF = null; - viewAreaElement.addEventListener('scroll', function debounceScroll(evt) { - if (state.rAF) { - return; - } - // schedule an invocation of webViewerScrolled for next animation frame. - state.rAF = window.requestAnimationFrame(function webViewerScrolled() { - state.rAF = null; - if (!PDFView.pdfDocument) { - return; - } - var currentY = viewAreaElement.scrollTop; - var lastY = state.lastY; - if (currentY > lastY) { - state.down = true; - } else if (currentY < lastY) { - state.down = false; - } - // else do nothing and use previous value - state.lastY = currentY; - callback(); - }); - }, true); - }, - _setScaleUpdatePages: function pdfView_setScaleUpdatePages( newScale, newValue, resetAutoSettings, noScroll) { this.currentScaleValue = newValue; @@ -1490,7 +1461,7 @@ var PDFView = { getVisiblePages: function pdfViewGetVisiblePages() { if (!PresentationMode.active) { - return this.getVisibleElements(this.container, this.pages, true); + return getVisibleElements(this.container, this.pages, true); } else { // The algorithm in getVisibleElements doesn't work in all browsers and // configurations when presentation mode is active. @@ -1502,54 +1473,7 @@ var PDFView = { }, getVisibleThumbs: function pdfViewGetVisibleThumbs() { - return this.getVisibleElements(this.thumbnailContainer, this.thumbnails); - }, - - // Generic helper to find out what elements are visible within a scroll pane. - getVisibleElements: function pdfViewGetVisibleElements( - scrollEl, views, sortByVisibility) { - var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; - var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; - - var visible = [], view; - var currentHeight, viewHeight, hiddenHeight, percentHeight; - var currentWidth, viewWidth; - for (var i = 0, ii = views.length; i < ii; ++i) { - view = views[i]; - currentHeight = view.el.offsetTop + view.el.clientTop; - viewHeight = view.el.clientHeight; - if ((currentHeight + viewHeight) < top) { - continue; - } - if (currentHeight > bottom) { - break; - } - currentWidth = view.el.offsetLeft + view.el.clientLeft; - viewWidth = view.el.clientWidth; - if ((currentWidth + viewWidth) < left || currentWidth > right) { - continue; - } - hiddenHeight = Math.max(0, top - currentHeight) + - Math.max(0, currentHeight + viewHeight - bottom); - percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; - - visible.push({ id: view.id, x: currentWidth, y: currentHeight, - view: view, percent: percentHeight }); - } - - var first = visible[0]; - var last = visible[visible.length - 1]; - - if (sortByVisibility) { - visible.sort(function(a, b) { - var pc = a.percent - b.percent; - if (Math.abs(pc) > 0.001) { - return -pc; - } - return a.id - b.id; // ensure stability - }); - } - return {first: first, last: last, views: visible}; + return getVisibleElements(this.thumbnailContainer, this.thumbnails); }, // Helper function to parse query string (e.g. ?param1=value&parm2=...). From 3bce14761acfd0bda8f1e0bae10f8f316df94dec Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 12 Sep 2014 14:48:44 -0500 Subject: [PATCH 02/11] Moves thumbs logic into PDFThumbnailViewer. --- web/thumbnail_view.js | 109 +++++++++++++++++++++++++++++++++++++++--- web/viewer.js | 72 +++++++--------------------- 2 files changed, 118 insertions(+), 63 deletions(-) diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index c48926698..d6721295e 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -14,16 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, mozL10n, RenderingStates */ +/* globals mozL10n, RenderingStates, THUMBNAIL_SCROLL_MARGIN, + watchScroll, getVisibleElements, scrollIntoView */ 'use strict'; -var ThumbnailView = function thumbnailView(container, id, defaultViewport) { +var ThumbnailView = function thumbnailView(container, id, defaultViewport, + linkService, renderingQueue) { var anchor = document.createElement('a'); - anchor.href = PDFView.getAnchorUrl('#page=' + id); + anchor.href = linkService.getAnchorUrl('#page=' + id); anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); anchor.onclick = function stopNavigation() { - PDFView.page = id; + linkService.page = id; return false; }; @@ -62,6 +64,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { this.hasImage = false; this.renderingState = RenderingStates.INITIAL; + this.renderingQueue = renderingQueue; this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { this.pdfPage = pdfPage; @@ -125,7 +128,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { this.draw = function thumbnailViewDraw(callback) { if (!this.pdfPage) { - var promise = PDFView.getPage(this.id); + var promise = this.renderingQueue.getPage(this.id); promise.then(function(pdfPage) { this.setPdfPage(pdfPage); this.draw(callback); @@ -150,7 +153,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { canvasContext: ctx, viewport: drawViewport, continueCallback: function(cont) { - if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { + if (self.renderingQueue.highestPriorityPage !== 'thumbnail' + self.id) { self.renderingState = RenderingStates.PAUSED; self.resume = function() { self.renderingState = RenderingStates.RUNNING; @@ -187,7 +190,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { this.setImage = function thumbnailViewSetImage(img) { if (!this.pdfPage) { - var promise = PDFView.getPage(this.id); + var promise = this.renderingQueue.getPage(this.id); promise.then(function(pdfPage) { this.setPdfPage(pdfPage); this.setImage(img); @@ -232,3 +235,95 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) { }; ThumbnailView.tempImageCache = null; + +var PDFThumbnailViewer = (function pdfThumbnailViewer() { + function PDFThumbnailViewer(options) { + this.container = options.container; + this.renderingQueue = options.renderingQueue; + this.linkService = options.linkService; + + this.scroll = watchScroll(this.container, this.scrollUpdated.bind(this)); + this.thumbnails = []; + this.currentPage = -1; + } + + PDFThumbnailViewer.prototype = { + scrollUpdated: function PDFThumbnailViewer_scrollUpdated() { + this.renderingQueue.renderHighestPriority(); + }, + + getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { + return getVisibleElements(this.container, this.thumbnails); + }, + + updatePage: function (page) { + var selected = document.querySelector('.thumbnail.selected'); + if (selected) { + selected.classList.remove('selected'); + } + var thumbnail = document.getElementById('thumbnailContainer' + page); + thumbnail.classList.add('selected'); + var visibleThumbs = this.getVisibleThumbs(); + var numVisibleThumbs = visibleThumbs.views.length; + + // If the thumbnail isn't currently visible, scroll it into view. + if (numVisibleThumbs > 0) { + var first = visibleThumbs.first.id; + // Account for only one thumbnail being visible. + var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first); + if (page <= first || page >= last) { + scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN }); + } + } + this.currentPage = page; + }, + + updateRotation: function (pageRotation) { + for (var i = 0, l = this.thumbnails.length; i < l; i++) { + var thumb = this.thumbnails[i]; + thumb.update(pageRotation); + } + }, + + cleanup: function PDFThumbnailViewer_cleanup() { + ThumbnailView.tempImageCache = null; + }, + + removeAllThumbnails: function PDFThumbnailViewer_cleanup() { + var thumbsView = this.container; + while (thumbsView.hasChildNodes()) { + thumbsView.removeChild(thumbsView.lastChild); + } + this.thumbnails = []; + }, + + addThumbnail: function PDFThumbnailViewer_addThumbnail(pageNum, viewport, + linkService) { + var thumbnail = new ThumbnailView(this.container, pageNum, viewport, + this.linkService, this.renderingQueue); + this.thumbnails.push(thumbnail); + return thumbnail; + }, + + ensureThumbnailVisible: + function PDFThumbnailViewer_ensureThumbnailVisible(page) { + // Ensure that the thumbnail of the current page is visible + // when switching from another view. + scrollIntoView(document.getElementById('thumbnailContainer' + page)); + }, + + forceRendering: function () { + var visibleThumbs = this.getVisibleThumbs(); + var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, + this.thumbnails, + this.scroll.down); + if (thumbView) { + this.renderingQueue.renderView(thumbView, 'thumbnail'); + return true; + } + return false; + } + }; + + return PDFThumbnailViewer; +})(); diff --git a/web/viewer.js b/web/viewer.js index 6cd58fb0c..ad9d90625 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -17,7 +17,7 @@ /* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar, DownloadManager, getFileName, scrollIntoView, getPDFFileNameFromURL, PDFHistory, Preferences, SidebarView, ViewHistory, PageView, - ThumbnailView, URL, noContextMenuHandler, SecondaryToolbar, + PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar, PasswordPrompt, PresentationMode, HandTool, Promise, DocumentProperties, DocumentOutlineView, DocumentAttachmentsView, OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, @@ -108,19 +108,17 @@ var currentPageNumber = 1; var PDFView = { pages: [], - thumbnails: [], currentScale: UNKNOWN_SCALE, currentScaleValue: null, initialBookmark: document.location.hash.substring(1), container: null, - thumbnailContainer: null, initialized: false, fellback: false, pdfDocument: null, sidebarOpen: false, printing: false, pageViewScroll: null, - thumbnailViewScroll: null, + pdfThumbnailViewer: null, pageRotation: 0, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, @@ -137,12 +135,12 @@ var PDFView = { var container = this.container = document.getElementById('viewerContainer'); this.pageViewScroll = watchScroll(container, updateViewarea); - var thumbnailContainer = this.thumbnailContainer = - document.getElementById('thumbnailView'); - this.thumbnailViewScroll = watchScroll(thumbnailContainer, function () { - this.renderHighestPriority(); - }.bind(this)); - + var thumbnailContainer = document.getElementById('thumbnailView'); + this.pdfThumbnailViewer = new PDFThumbnailViewer({ + container: thumbnailContainer, + renderingQueue: this, + linkService: this + }); Preferences.initialize(); @@ -591,10 +589,7 @@ var PDFView = { this.pdfDocument.destroy(); this.pdfDocument = null; - var thumbsView = document.getElementById('thumbnailView'); - while (thumbsView.hasChildNodes()) { - thumbsView.removeChild(thumbsView.lastChild); - } + this.pdfThumbnailViewer.removeAllThumbnails(); var container = document.getElementById('viewer'); while (container.hasChildNodes()) { @@ -953,7 +948,6 @@ var PDFView = { var pages = this.pages = []; var pagesRefMap = this.pagesRefMap = {}; - var thumbnails = this.thumbnails = []; var resolvePagesPromise; var pagesPromise = new Promise(function (resolve) { @@ -963,7 +957,7 @@ var PDFView = { var firstPagePromise = pdfDocument.getPage(1); var container = document.getElementById('viewer'); - var thumbsView = document.getElementById('thumbnailView'); + var thumbsViewer = this.pdfThumbnailViewer; // Fetch a single page so we can get a viewport that will be the default // viewport for all pages @@ -974,11 +968,9 @@ var PDFView = { var pageView = new PageView(container, pageNum, scale, self.navigateTo.bind(self), viewportClone); - var thumbnailView = new ThumbnailView(thumbsView, pageNum, - viewportClone); + var thumbnailView = thumbsViewer.addThumbnail(pageNum, viewportClone); bindOnAfterDraw(pageView, thumbnailView); pages.push(pageView); - thumbnails.push(thumbnailView); } // Fetch all the pages since the viewport is needed before printing @@ -1239,12 +1231,7 @@ var PDFView = { } // No pages needed rendering so check thumbnails. if (this.sidebarOpen) { - var visibleThumbs = this.getVisibleThumbs(); - var thumbView = this.getHighestPriority(visibleThumbs, - this.thumbnails, - this.thumbnailViewScroll.down); - if (thumbView) { - this.renderView(thumbView, 'thumbnail'); + if (this.pdfThumbnailViewer.forceRendering()) { return; } } @@ -1268,7 +1255,7 @@ var PDFView = { } this.pdfDocument.cleanup(); - ThumbnailView.tempImageCache = null; + this.pdfThumbnailViewer.cleanup(); }, getHighestPriority: function pdfViewGetHighestPriority(visible, views, @@ -1424,10 +1411,7 @@ var PDFView = { PDFView.renderHighestPriority(); if (wasAnotherViewVisible) { - // Ensure that the thumbnail of the current page is visible - // when switching from another view. - scrollIntoView(document.getElementById('thumbnailContainer' + - this.page)); + this.pdfThumbnailViewer.ensureThumbnailVisible(this.page); } break; @@ -1472,10 +1456,6 @@ var PDFView = { } }, - getVisibleThumbs: function pdfViewGetVisibleThumbs() { - return getVisibleElements(this.thumbnailContainer, this.thumbnails); - }, - // Helper function to parse query string (e.g. ?param1=value&parm2=...). parseQueryString: function pdfViewParseQueryString(query) { var parts = query.split('&'); @@ -1552,10 +1532,7 @@ var PDFView = { page.update(page.scale, this.pageRotation); } - for (i = 0, l = this.thumbnails.length; i < l; i++) { - var thumb = this.thumbnails[i]; - thumb.update(this.pageRotation); - } + this.pdfThumbnailViewer.updateRotation(this.pageRotation); this.setScale(this.currentScaleValue, true, true); @@ -2131,24 +2108,7 @@ window.addEventListener('pagechange', function pagechange(evt) { var page = evt.pageNumber; if (PDFView.previousPageNumber !== page) { document.getElementById('pageNumber').value = page; - var selected = document.querySelector('.thumbnail.selected'); - if (selected) { - selected.classList.remove('selected'); - } - var thumbnail = document.getElementById('thumbnailContainer' + page); - thumbnail.classList.add('selected'); - var visibleThumbs = PDFView.getVisibleThumbs(); - var numVisibleThumbs = visibleThumbs.views.length; - - // If the thumbnail isn't currently visible, scroll it into view. - if (numVisibleThumbs > 0) { - var first = visibleThumbs.first.id; - // Account for only one thumbnail being visible. - var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first); - if (page <= first || page >= last) { - scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN }); - } - } + PDFView.pdfThumbnailViewer.updatePage(page); } var numPages = PDFView.pages.length; From 7af8748151b174fc2206a6ed543b5474a589fb25 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 12 Sep 2014 21:27:45 -0500 Subject: [PATCH 03/11] Moves viewer code into PDFViewer and some code from PageView. --- web/page_view.js | 88 +++----- web/pdf_find_controller.js | 10 +- web/pdf_viewer.js | 314 +++++++++++++++++++++++++++ web/presentation_mode.js | 6 +- web/viewer.html | 1 + web/viewer.js | 428 +++++++++++++------------------------ 6 files changed, 502 insertions(+), 345 deletions(-) create mode 100644 web/pdf_viewer.js diff --git a/web/page_view.js b/web/page_view.js index 62a90686d..e5663272f 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -14,15 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals RenderingStates, PDFView, PDFHistory, PDFJS, mozL10n, CustomStyle, +/* globals RenderingStates, PDFView, PDFJS, mozL10n, CustomStyle, PresentationMode, scrollIntoView, SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE, getOutputScale, TextLayerBuilder, - cache, Stats */ + Stats */ 'use strict'; -var PageView = function pageView(container, id, scale, - navigateTo, defaultViewport) { +var PageView = function pageView(container, id, scale, defaultViewport, + linkService, renderingQueue, cache, viewer) { this.id = id; this.rotation = 0; @@ -31,6 +31,11 @@ var PageView = function pageView(container, id, scale, this.pdfPageRotate = defaultViewport.rotation; this.hasRestrictedScaling = false; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.cache = cache; + this.viewer = viewer; + this.renderingState = RenderingStates.INITIAL; this.resume = null; @@ -241,10 +246,10 @@ var PageView = function pageView(container, id, scale, function setupAnnotations(pageDiv, pdfPage, viewport) { function bindLink(link, dest) { - link.href = PDFView.getDestinationHash(dest); + link.href = linkService.getDestinationHash(dest); link.onclick = function pageViewSetupLinksOnclick() { if (dest) { - PDFView.navigateTo(dest); + linkService.navigateTo(dest); } return false; }; @@ -254,47 +259,9 @@ var PageView = function pageView(container, id, scale, } function bindNamedAction(link, action) { - link.href = PDFView.getAnchorUrl(''); + link.href = linkService.getAnchorUrl(''); link.onclick = function pageViewSetupNamedActionOnClick() { - // See PDF reference, table 8.45 - Named action - switch (action) { - case 'GoToPage': - document.getElementById('pageNumber').focus(); - break; - - case 'GoBack': - PDFHistory.back(); - break; - - case 'GoForward': - PDFHistory.forward(); - break; - - case 'Find': - if (!PDFView.supportsIntegratedFind) { - PDFView.findBar.toggle(); - } - break; - - case 'NextPage': - PDFView.page++; - break; - - case 'PrevPage': - PDFView.page--; - break; - - case 'LastPage': - PDFView.page = PDFView.pages.length; - break; - - case 'FirstPage': - PDFView.page = 1; - break; - - default: - break; // No action according to spec - } + linkService.executeNamedAction(action); return false; }; link.className = 'internalLink'; @@ -377,13 +344,13 @@ var PageView = function pageView(container, id, scale, this.scrollIntoView = function pageViewScrollIntoView(dest) { if (PresentationMode.active) { - if (PDFView.page !== this.id) { - // Avoid breaking PDFView.getVisiblePages in presentation mode. - PDFView.page = this.id; + if (this.linkService.page !== this.id) { + // Avoid breaking getVisiblePages in presentation mode. + this.linkService.page = this.id; return; } dest = null; - PDFView.setScale(PDFView.currentScaleValue, true, true); + this.viewer.setScale(this.viewer.currentScaleValue, true, true); } if (!dest) { scrollIntoView(div); @@ -431,9 +398,10 @@ var PageView = function pageView(container, id, scale, y = dest[3]; width = dest[4] - x; height = dest[5] - y; - widthScale = (PDFView.container.clientWidth - SCROLLBAR_PADDING) / + var viewerContainer = this.viewer.container; + widthScale = (viewerContainer.clientWidth - SCROLLBAR_PADDING) / width / CSS_UNITS; - heightScale = (PDFView.container.clientHeight - SCROLLBAR_PADDING) / + heightScale = (viewerContainer.clientHeight - SCROLLBAR_PADDING) / height / CSS_UNITS; scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); break; @@ -441,10 +409,10 @@ var PageView = function pageView(container, id, scale, return; } - if (scale && scale !== PDFView.currentScale) { - PDFView.setScale(scale, true, true); - } else if (PDFView.currentScale === UNKNOWN_SCALE) { - PDFView.setScale(DEFAULT_SCALE, true, true); + if (scale && scale !== this.viewer.currentScale) { + this.viewer.setScale(scale, true, true); + } else if (this.viewer.currentScale === UNKNOWN_SCALE) { + this.viewer.setScale(DEFAULT_SCALE, true, true); } if (scale === 'page-fit' && !dest[4]) { @@ -463,7 +431,7 @@ var PageView = function pageView(container, id, scale, }; this.getTextContent = function pageviewGetTextContent() { - return PDFView.getPage(this.id).then(function(pdfPage) { + return this.renderingQueue.getPage(this.id).then(function(pdfPage) { return pdfPage.getTextContent(); }); }; @@ -475,7 +443,7 @@ var PageView = function pageView(container, id, scale, return; } if (!pdfPage) { - var promise = PDFView.getPage(this.id); + var promise = this.renderingQueue.getPage(this.id); promise.then(function(pdfPage) { delete this.pagePdfPromise; this.setPdfPage(pdfPage); @@ -559,7 +527,7 @@ var PageView = function pageView(container, id, scale, textLayerDiv ? new TextLayerBuilder({ textLayerDiv: textLayerDiv, pageIndex: this.id - 1, - lastScrollSource: PDFView, + lastScrollSource: this.linkService, viewport: this.viewport, isViewerInPresentationMode: PresentationMode.active, findController: PDFView.findController @@ -646,7 +614,7 @@ var PageView = function pageView(container, id, scale, viewport: this.viewport, // intent: 'default', // === 'display' continueCallback: function pdfViewcContinueCallback(cont) { - if (PDFView.highestPriorityPage !== 'page' + self.id) { + if (self.renderingQueue.highestPriorityPage !== 'page' + self.id) { self.renderingState = RenderingStates.PAUSED; self.resume = function resumeCallback() { self.renderingState = RenderingStates.RUNNING; diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js index 6459faf27..46c724d0e 100644 --- a/web/pdf_find_controller.js +++ b/web/pdf_find_controller.js @@ -137,7 +137,7 @@ var PDFFindController = (function PDFFindControllerClosure() { this.pageContents = []; var extractTextPromisesResolves = []; - var numPages = this.pdfPageSource.pdfDocument.numPages; + var numPages = this.pdfPageSource.pagesCount; for (var i = 0; i < numPages; i++) { this.extractTextPromises.push(new Promise(function (resolve) { extractTextPromisesResolves.push(resolve); @@ -146,7 +146,7 @@ var PDFFindController = (function PDFFindControllerClosure() { var self = this; function extractPageText(pageIndex) { - self.pdfPageSource.pages[pageIndex].getTextContent().then( + self.pdfPageSource.getPageView(pageIndex).getTextContent().then( function textContentResolved(textContent) { var textItems = textContent.items; var str = []; @@ -159,7 +159,7 @@ var PDFFindController = (function PDFFindControllerClosure() { self.pageContents.push(str.join('')); extractTextPromisesResolves[pageIndex](pageIndex); - if ((pageIndex + 1) < self.pdfPageSource.pages.length) { + if ((pageIndex + 1) < self.pdfPageSource.pagesCount) { extractPageText(pageIndex + 1); } } @@ -189,7 +189,7 @@ var PDFFindController = (function PDFFindControllerClosure() { }, updatePage: function PDFFindController_updatePage(index) { - var page = this.pdfPageSource.pages[index]; + var page = this.pdfPageSource.getPageView(index); if (this.selected.pageIdx === index) { // If the page is selected, scroll the page into view, which triggers @@ -206,7 +206,7 @@ var PDFFindController = (function PDFFindControllerClosure() { nextMatch: function PDFFindController_nextMatch() { var previous = this.state.findPrevious; var currentPageIndex = this.pdfPageSource.page - 1; - var numPages = this.pdfPageSource.pages.length; + var numPages = this.pdfPageSource.pagesCount; this.active = true; diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js new file mode 100644 index 000000000..f2bc25758 --- /dev/null +++ b/web/pdf_viewer.js @@ -0,0 +1,314 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2014 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 watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, + IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, + MAX_AUTO_SCALE, getVisibleElements, PresentationMode, + RenderingStates */ + +'use strict'; + +var PDFViewer = (function pdfViewer() { + function PDFViewer(options) { + this.container = options.container; + this.viewer = options.viewer; + this.renderingQueue = options.renderingQueue; + this.linkService = options.linkService; + + this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); + this.pages = []; + this.cache = new Cache(DEFAULT_CACHE_SIZE); + this.currentPageNumber = 1; + this.previousPageNumber = 1; + this.updateInProgress = true; + this.resetView(); + } + + PDFViewer.prototype = { + get pagesCount() { + return this.pages.length; + }, + + setCurrentPageNumber: function (val) { + var event = document.createEvent('UIEvents'); + event.initUIEvent('pagechange', true, true, window, 0); + event.updateInProgress = this.updateInProgress; + + if (!(0 < val && val <= this.pagesCount)) { + this.previousPageNumber = val; + event.pageNumber = this.page; + this.container.dispatchEvent(event); + return; + } + + this.pages[val - 1].updateStats(); + this.previousPageNumber = this.currentPageNumber; + this.currentPageNumber = val; + event.pageNumber = val; + this.container.dispatchEvent(event); + }, + + addPage: function (pageNum, scale, viewport) { + var pageView = new PageView(this.viewer, pageNum, scale, viewport, + this.linkService, this.renderingQueue, + this.cache, this); + this.pages.push(pageView); + return pageView; + }, + + resetView: function () { + this.currentScale = UNKNOWN_SCALE; + this.currentScaleValue = null; + this.location = null; + }, + + _scrollUpdate: function () { + if (this.pagesCount === 0) { + return; + } + this.update(); + }, + + _setScaleUpdatePages: function pdfViewer_setScaleUpdatePages( + newScale, newValue, resetAutoSettings, noScroll, preset) { + this.currentScaleValue = newValue; + if (newScale === this.currentScale) { + return; + } + for (var i = 0, ii = this.pages.length; i < ii; i++) { + this.pages[i].update(newScale); + } + this.currentScale = newScale; + + if (!noScroll) { + var page = this.currentPageNumber, dest; + if (this.location && !this.inPresentationMode && + !IGNORE_CURRENT_POSITION_ON_ZOOM) { + page = this.location.pageNumber; + dest = [null, { name: 'XYZ' }, this.location.left, + this.location.top, null]; + } + this.pages[page - 1].scrollIntoView(dest); + } + + var event = document.createEvent('UIEvents'); + event.initUIEvent('scalechange', true, true, window, 0); + event.scale = newScale; + event.resetAutoSettings = resetAutoSettings; + if (preset) { + event.presetValue = newValue; + } + this.container.dispatchEvent(event); + }, + + setScale: function pdfViewer_setScale(value, resetAutoSettings, noScroll) { + if (value === 'custom') { + return; + } + var scale = parseFloat(value); + + if (scale > 0) { + this._setScaleUpdatePages(scale, value, true, noScroll, false); + } else { + var currentPage = this.pages[this.currentPageNumber - 1]; + if (!currentPage) { + return; + } + var hPadding = PresentationMode.active ? 0 : SCROLLBAR_PADDING; + var vPadding = PresentationMode.active ? 0 : VERTICAL_PADDING; + var pageWidthScale = (this.container.clientWidth - hPadding) / + currentPage.width * currentPage.scale; + var pageHeightScale = (this.container.clientHeight - vPadding) / + currentPage.height * currentPage.scale; + switch (value) { + case 'page-actual': + scale = 1; + break; + case 'page-width': + scale = pageWidthScale; + break; + case 'page-height': + scale = pageHeightScale; + break; + case 'page-fit': + scale = Math.min(pageWidthScale, pageHeightScale); + break; + case 'auto': + var isLandscape = (currentPage.width > currentPage.height); + var horizontalScale = isLandscape ? pageHeightScale : + pageWidthScale; + scale = Math.min(MAX_AUTO_SCALE, horizontalScale); + break; + default: + console.error('pdfViewSetScale: \'' + value + + '\' is an unknown zoom value.'); + return; + } + this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll, + true); + } + }, + + updateRotation: function pdfViewRotatePages(rotation) { + for (var i = 0, l = this.pages.length; i < l; i++) { + var page = this.pages[i]; + page.update(page.scale, rotation); + } + + this.setScale(this.currentScaleValue, true, true); + }, + + removeAllPages: function () { + var container = this.viewer; + while (container.hasChildNodes()) { + container.removeChild(container.lastChild); + } + this.pages = []; + }, + + updateLocation: function (firstPage) { + var currentScale = this.currentScale; + var currentScaleValue = this.currentScaleValue; + var normalizedScaleValue = + parseFloat(currentScaleValue) === currentScale ? + Math.round(currentScale * 10000) / 100 : currentScaleValue; + + var pageNumber = firstPage.id; + var pdfOpenParams = '#page=' + pageNumber; + pdfOpenParams += '&zoom=' + normalizedScaleValue; + var currentPageView = this.pages[pageNumber - 1]; + var container = this.container; + var topLeft = currentPageView.getPagePoint( + (container.scrollLeft - firstPage.x), + (container.scrollTop - firstPage.y)); + var intLeft = Math.round(topLeft[0]); + var intTop = Math.round(topLeft[1]); + pdfOpenParams += ',' + intLeft + ',' + intTop; + + this.location = { + pageNumber: pageNumber, + scale: normalizedScaleValue, + top: intTop, + left: intLeft, + pdfOpenParams: pdfOpenParams + }; + }, + + get inPresentationMode() { + return PresentationMode.active || PresentationMode.switchInProgress; + }, + + update: function () { + var visible = this.getVisiblePages(); + var visiblePages = visible.views; + if (visiblePages.length === 0) { + return; + } + + this.updateInProgress = true; + + var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, + 2 * visiblePages.length + 1); + this.cache.resize(suggestedCacheSize); + + this.renderingQueue.renderHighestPriority(visible); + + var currentId = this.currentPageNumber; + var firstPage = visible.first; + + for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; + i < ii; ++i) { + var page = visiblePages[i]; + + if (page.percent < 100) { + break; + } + if (page.id === this.currentPageNumber) { + stillFullyVisible = true; + break; + } + } + + if (!stillFullyVisible) { + currentId = visiblePages[0].id; + } + + if (!PresentationMode.active) { + this.setCurrentPageNumber(currentId); + } + + this.updateLocation(firstPage); + + this.updateInProgress = false; + + var event = document.createEvent('UIEvents'); + event.initUIEvent('updateviewarea', true, true, window, 0); + this.container.dispatchEvent(event); + }, + + containsElement: function (element) { + return this.container.contains(element); + }, + + focus: function () { + this.container.focus(); + }, + + blur: function () { + this.container.blur(); + }, + + get isHorizontalScrollbarEnabled() { + return (PresentationMode.active ? false : + (this.container.scrollWidth > this.container.clientWidth)); + }, + + getVisiblePages: function () { + if (!PresentationMode.active) { + return getVisibleElements(this.container, this.pages, true); + } else { + // The algorithm in getVisibleElements doesn't work in all browsers and + // configurations when presentation mode is active. + var visible = []; + var currentPage = this.pages[this.currentPageNumber - 1]; + visible.push({ id: currentPage.id, view: currentPage }); + return { first: currentPage, last: currentPage, views: visible }; + } + }, + + cleanup: function () { + for (var i = 0, ii = this.pages.length; i < ii; i++) { + if (this.pages[i] && + this.pages[i].renderingState !== RenderingStates.FINISHED) { + this.pages[i].reset(); + } + } + }, + + forceRendering: function (currentlyVisiblePages) { + var visiblePages = currentlyVisiblePages || this.getVisiblePages(); + var pageView = this.renderingQueue.getHighestPriority(visiblePages, + this.pages, + this.scroll.down); + if (pageView) { + this.renderingQueue.renderView(pageView, 'page'); + return; + } + }, + }; + + return PDFViewer; +})(); diff --git a/web/presentation_mode.js b/web/presentation_mode.js index 46a4fc2de..f297623c8 100644 --- a/web/presentation_mode.js +++ b/web/presentation_mode.js @@ -68,7 +68,7 @@ var PresentationMode = { }, /** - * Initialize a timeout that is used to reset PDFView.currentPosition when the + * Initialize a timeout that is used to specify switchInProgress when the * browser transitions to fullscreen mode. Since resize events are triggered * multiple times during the switch to fullscreen mode, this is necessary in * order to prevent the page from being scrolled partially, or completely, @@ -82,8 +82,6 @@ var PresentationMode = { this.switchInProgress = setTimeout(function switchInProgressTimeout() { delete this.switchInProgress; }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); - - PDFView.currentPosition = null; }, _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { @@ -150,7 +148,7 @@ var PresentationMode = { // Note: This is only necessary in non-Mozilla browsers. setTimeout(function exitPresentationModeTimeout() { this.active = false; - PDFView.setScale(this.args.previousScale); + PDFView.setScale(this.args.previousScale, true); PDFView.page = page; this.args = null; }.bind(this), 0); diff --git a/web/viewer.html b/web/viewer.html index d15c3456d..6df149d18 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -69,6 +69,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/ + diff --git a/web/viewer.js b/web/viewer.js index ad9d90625..48ff868ab 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 */ + watchScroll, PDFViewer */ 'use strict'; @@ -92,9 +92,6 @@ var mozL10n = document.mozL10n || document.webL10n; //#include chromecom.js //#endif -var cache = new Cache(DEFAULT_CACHE_SIZE); -var currentPageNumber = 1; - //#include view_history.js //#include pdf_find_bar.js //#include pdf_find_controller.js @@ -107,33 +104,32 @@ var currentPageNumber = 1; //#include document_properties.js var PDFView = { - pages: [], - currentScale: UNKNOWN_SCALE, - currentScaleValue: null, initialBookmark: document.location.hash.substring(1), - container: null, initialized: false, fellback: false, pdfDocument: null, sidebarOpen: false, printing: false, - pageViewScroll: null, + pdfViewer: null, pdfThumbnailViewer: null, pageRotation: 0, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, lastScroll: 0, - previousPageNumber: 1, isViewerEmbedded: (window.parent !== window), idleTimeout: null, - currentPosition: null, url: '', // called once when the document is loaded initialize: function pdfViewInitialize() { - var self = this; - var container = this.container = document.getElementById('viewerContainer'); - this.pageViewScroll = watchScroll(container, updateViewarea); + var container = document.getElementById('viewerContainer'); + var viewer = document.getElementById('viewer'); + this.pdfViewer = new PDFViewer({ + container: container, + viewer: viewer, + renderingQueue: this, + linkService: this + }); var thumbnailContainer = document.getElementById('thumbnailView'); this.pdfThumbnailViewer = new PDFThumbnailViewer({ @@ -271,133 +267,44 @@ var PDFView = { return this.pdfDocument.getPage(n); }, - _setScaleUpdatePages: function pdfView_setScaleUpdatePages( - newScale, newValue, resetAutoSettings, noScroll) { - this.currentScaleValue = newValue; - if (newScale === this.currentScale) { - return; - } - for (var i = 0, ii = this.pages.length; i < ii; i++) { - this.pages[i].update(newScale); - } - this.currentScale = newScale; - - if (!noScroll) { - var page = this.page, dest; - if (this.currentPosition && !IGNORE_CURRENT_POSITION_ON_ZOOM) { - page = this.currentPosition.page; - dest = [null, { name: 'XYZ' }, this.currentPosition.left, - this.currentPosition.top, null]; - } - this.pages[page - 1].scrollIntoView(dest); - } - var event = document.createEvent('UIEvents'); - event.initUIEvent('scalechange', false, false, window, 0); - event.scale = newScale; - event.resetAutoSettings = resetAutoSettings; - window.dispatchEvent(event); - }, - - setScale: function pdfViewSetScale(value, resetAutoSettings, noScroll) { - if (value === 'custom') { - return; - } - var scale = parseFloat(value); - - if (scale > 0) { - this._setScaleUpdatePages(scale, value, true, noScroll); - } else { - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - var hPadding = PresentationMode.active ? 0 : SCROLLBAR_PADDING; - var vPadding = PresentationMode.active ? 0 : VERTICAL_PADDING; - var pageWidthScale = (this.container.clientWidth - hPadding) / - currentPage.width * currentPage.scale; - var pageHeightScale = (this.container.clientHeight - vPadding) / - currentPage.height * currentPage.scale; - switch (value) { - case 'page-actual': - scale = 1; - break; - case 'page-width': - scale = pageWidthScale; - break; - case 'page-height': - scale = pageHeightScale; - break; - case 'page-fit': - scale = Math.min(pageWidthScale, pageHeightScale); - break; - case 'auto': - var isLandscape = (currentPage.width > currentPage.height); - var horizontalScale = isLandscape ? pageHeightScale : pageWidthScale; - scale = Math.min(MAX_AUTO_SCALE, horizontalScale); - break; - default: - console.error('pdfViewSetScale: \'' + value + - '\' is an unknown zoom value.'); - return; - } - this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll); - - selectScaleOption(value); - } + getPageView: function pdfViewGetPageView(index) { + return this.pdfViewer.pages[index]; }, zoomIn: function pdfViewZoomIn(ticks) { - var newScale = this.currentScale; + var newScale = this.pdfViewer.currentScale; do { newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.ceil(newScale * 10) / 10; newScale = Math.min(MAX_SCALE, newScale); } while (--ticks && newScale < MAX_SCALE); - this.setScale(newScale, true); + this.pdfViewer.setScale(newScale, true); }, zoomOut: function pdfViewZoomOut(ticks) { - var newScale = this.currentScale; + var newScale = this.pdfViewer.currentScale; do { newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.floor(newScale * 10) / 10; newScale = Math.max(MIN_SCALE, newScale); } while (--ticks && newScale > MIN_SCALE); - this.setScale(newScale, true); + this.pdfViewer.setScale(newScale, true); + }, + + get currentScaleValue() { + return this.pdfViewer.currentScaleValue; + }, + + get pagesCount() { + return this.pdfDocument.numPages; }, set page(val) { - var pages = this.pages; - var event = document.createEvent('UIEvents'); - event.initUIEvent('pagechange', false, false, window, 0); - - if (!(0 < val && val <= pages.length)) { - this.previousPageNumber = val; - event.pageNumber = this.page; - window.dispatchEvent(event); - return; - } - - pages[val - 1].updateStats(); - this.previousPageNumber = currentPageNumber; - currentPageNumber = val; - event.pageNumber = val; - window.dispatchEvent(event); - - // checking if the this.page was called from the updateViewarea function: - // avoiding the creation of two "set page" method (internal and public) - if (updateViewarea.inProgress) { - return; - } - // Avoid scrolling the first page during loading - if (this.loading && val === 1) { - return; - } - pages[val - 1].scrollIntoView(); + this.pdfViewer.setCurrentPageNumber(val); }, get page() { - return currentPageNumber; + return this.pdfViewer.currentPageNumber; }, get supportsPrinting() { @@ -478,11 +385,6 @@ var PDFView = { return bar; }, - get isHorizontalScrollbarEnabled() { - return (PresentationMode.active ? false : - (this.container.scrollWidth > this.container.clientWidth)); - }, - //#if (FIREFOX || MOZCENTRAL) initPassiveLoading: function pdfViewInitPassiveLoading() { var pdfDataRangeTransport = { @@ -590,11 +492,7 @@ var PDFView = { this.pdfDocument = null; this.pdfThumbnailViewer.removeAllThumbnails(); - - var container = document.getElementById('viewer'); - while (container.hasChildNodes()) { - container.removeChild(container.lastChild); - } + this.pdfViewer.removeAllPages(); if (typeof PDFBug !== 'undefined') { PDFBug.cleanup(); @@ -745,10 +643,10 @@ var PDFView = { self.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1); if (pageNumber) { - if (pageNumber > self.pages.length) { - pageNumber = self.pages.length; + if (pageNumber > self.pagesCount) { + pageNumber = self.pagesCount; } - var currentPage = self.pages[pageNumber - 1]; + var currentPage = self.getPageView(pageNumber - 1); currentPage.scrollIntoView(dest); // Update the browsing history. @@ -774,6 +672,48 @@ var PDFView = { }); }, + executeNamedAction: function pdfViewExecuteNamedAction(action) { + // See PDF reference, table 8.45 - Named action + switch (action) { + case 'GoToPage': + document.getElementById('pageNumber').focus(); + break; + + case 'GoBack': + PDFHistory.back(); + break; + + case 'GoForward': + PDFHistory.forward(); + break; + + case 'Find': + if (!PDFView.supportsIntegratedFind) { + PDFView.findBar.toggle(); + } + break; + + case 'NextPage': + PDFView.page++; + break; + + case 'PrevPage': + PDFView.page--; + break; + + case 'LastPage': + PDFView.page = PDFView.pagesCount; + break; + + case 'FirstPage': + PDFView.page = 1; + break; + + default: + break; // No action according to spec + } + }, + getDestinationHash: function pdfViewGetDestinationHash(dest) { if (typeof dest === 'string') { return PDFView.getAnchorUrl('#' + escape(dest)); @@ -946,7 +886,6 @@ var PDFView = { this.pageRotation = 0; - var pages = this.pages = []; var pagesRefMap = this.pagesRefMap = {}; var resolvePagesPromise; @@ -956,7 +895,7 @@ var PDFView = { this.pagesPromise = pagesPromise; var firstPagePromise = pdfDocument.getPage(1); - var container = document.getElementById('viewer'); + var pagesViewer = this.pdfViewer; var thumbsViewer = this.pdfThumbnailViewer; // Fetch a single page so we can get a viewport that will be the default @@ -965,12 +904,9 @@ var PDFView = { var viewport = pdfPage.getViewport((scale || 1.0) * CSS_UNITS); for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { var viewportClone = viewport.clone(); - var pageView = new PageView(container, pageNum, scale, - self.navigateTo.bind(self), - viewportClone); + var pageView = pagesViewer.addPage(pageNum, scale, viewportClone); var thumbnailView = thumbsViewer.addThumbnail(pageNum, viewportClone); bindOnAfterDraw(pageView, thumbnailView); - pages.push(pageView); } // Fetch all the pages since the viewport is needed before printing @@ -981,7 +917,7 @@ var PDFView = { var getPagesLeft = pagesCount; for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) { - var pageView = pages[pageNum - 1]; + var pageView = PDFView.getPageView(pageNum - 1); if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } @@ -1005,7 +941,7 @@ var PDFView = { window.dispatchEvent(event); }); - PDFView.loadingBar.setWidth(container); + PDFView.loadingBar.setWidth(document.getElementById('viewer')); PDFView.findController.resolveFirstPage(); @@ -1031,7 +967,8 @@ var PDFView = { var storedHash = null; if (showPreviousViewOnLoad && store.get('exists', false)) { var pageNum = store.get('page', '1'); - var zoom = defaultZoomValue || store.get('zoom', PDFView.currentScale); + var zoom = defaultZoomValue || + store.get('zoom', PDFView.pdfViewer.currentScale); var left = store.get('scrollLeft', '0'); var top = store.get('scrollTop', '0'); @@ -1045,9 +982,9 @@ var PDFView = { // Make all navigation keys work on document load, // unless the viewer is embedded in a web page. if (!self.isViewerEmbedded) { - self.container.focus(); + self.pdfViewer.focus(); //#if (FIREFOX || MOZCENTRAL) -// self.container.blur(); +// self.pdfViewer.blur(); //#endif } }, function rejected(reason) { @@ -1183,15 +1120,13 @@ var PDFView = { setInitialView: function pdfViewSetInitialView(storedHash, scale) { // Reset the current scale, as otherwise the page's scale might not get // updated if the zoom level stayed the same. - this.currentScale = UNKNOWN_SCALE; - this.currentScaleValue = null; + this.pdfViewer.resetView(); + // When opening a new file (when one is already loaded in the viewer): // Reset 'currentPageNumber', since otherwise the page's scale will be wrong // if 'currentPageNumber' is larger than the number of pages in the file. - document.getElementById('pageNumber').value = currentPageNumber = 1; - // Reset the current position when loading a new file, - // to prevent displaying the wrong position in the document. - this.currentPosition = null; + document.getElementById('pageNumber').value = + this.pdfViewer.currentPageNumber = 1; if (PDFHistory.initialDestination) { this.navigateTo(PDFHistory.initialDestination); @@ -1203,14 +1138,14 @@ var PDFView = { } else if (storedHash) { this.setHash(storedHash); } else if (scale) { - this.setScale(scale, true); + this.pdfViewer.setScale(scale, true); this.page = 1; } - if (PDFView.currentScale === UNKNOWN_SCALE) { + if (PDFView.pdfViewer.currentScale === UNKNOWN_SCALE) { // Scale was not initialized: invalid bookmark or scale was not specified. // Setting the default one. - this.setScale(DEFAULT_SCALE, true); + this.pdfViewer.setScale(DEFAULT_SCALE, true); } }, @@ -1222,11 +1157,7 @@ var PDFView = { } // Pages have a higher priority than thumbnails, so check them first. - var visiblePages = currentlyVisiblePages || this.getVisiblePages(); - var pageView = this.getHighestPriority(visiblePages, this.pages, - this.pageViewScroll.down); - if (pageView) { - this.renderView(pageView, 'page'); + if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { return; } // No pages needed rendering so check thumbnails. @@ -1247,15 +1178,9 @@ var PDFView = { }, cleanup: function pdfViewCleanup() { - for (var i = 0, ii = this.pages.length; i < ii; i++) { - if (this.pages[i] && - this.pages[i].renderingState !== RenderingStates.FINISHED) { - this.pages[i].reset(); - } - } - this.pdfDocument.cleanup(); - + this.pdfViewer.cleanup(); this.pdfThumbnailViewer.cleanup(); + this.pdfDocument.cleanup(); }, getHighestPriority: function pdfViewGetHighestPriority(visible, views, @@ -1363,7 +1288,7 @@ var PDFView = { zoomArg]; } if (dest) { - var currentPage = this.pages[(pageNumber || this.page) - 1]; + var currentPage = this.getPageView((pageNumber || this.page) - 1); currentPage.scrollIntoView(dest); } else if (pageNumber) { this.page = pageNumber; // simple page @@ -1443,19 +1368,6 @@ var PDFView = { } }, - getVisiblePages: function pdfViewGetVisiblePages() { - if (!PresentationMode.active) { - return getVisibleElements(this.container, this.pages, true); - } else { - // The algorithm in getVisibleElements doesn't work in all browsers and - // configurations when presentation mode is active. - var visible = []; - var currentPage = this.pages[this.page - 1]; - visible.push({ id: currentPage.id, view: currentPage }); - return { first: currentPage, last: currentPage, views: visible }; - } - }, - // Helper function to parse query string (e.g. ?param1=value&parm2=...). parseQueryString: function pdfViewParseQueryString(query) { var parts = query.split('&'); @@ -1479,11 +1391,11 @@ var PDFView = { var alertNotReady = false; var i, ii; - if (!this.pages.length) { + if (!this.pagesCount) { alertNotReady = true; } else { - for (i = 0, ii = this.pages.length; i < ii; ++i) { - if (!this.pages[i].pdfPage) { + for (i = 0, ii = this.pagesCount; i < ii; ++i) { + if (!this.getPageView(i).pdfPage) { alertNotReady = true; break; } @@ -1501,8 +1413,8 @@ var PDFView = { var body = document.querySelector('body'); body.setAttribute('data-mozPrintCallback', true); - for (i = 0, ii = this.pages.length; i < ii; ++i) { - this.pages[i].beforePrint(); + for (i = 0, ii = this.pagesCount; i < ii; ++i) { + this.getPageView(i).beforePrint(); } //#if (FIREFOX || MOZCENTRAL) @@ -1522,20 +1434,17 @@ var PDFView = { this.renderHighestPriority(); }, + setScale: function (value, resetAutoSettings, noScroll) { + this.pdfViewer.setScale(value, resetAutoSettings, noScroll); + }, + rotatePages: function pdfViewRotatePages(delta) { - var currentPage = this.pages[this.page - 1]; - var i, l; + var currentPage = this.getPageView(this.page - 1); + this.pageRotation = (this.pageRotation + 360 + delta) % 360; - - for (i = 0, l = this.pages.length; i < l; i++) { - var page = this.pages[i]; - page.update(page.scale, this.pageRotation); - } - + this.pdfViewer.updateRotation(this.pageRotation); this.pdfThumbnailViewer.updateRotation(this.pageRotation); - this.setScale(this.currentScaleValue, true, true); - this.renderHighestPriority(); if (currentPage) { @@ -1590,7 +1499,7 @@ var PDFView = { // In case we are already on the first or the last page there is no need // to do anything. if ((currentPage === 1 && pageFlipDirection === PageFlipDirection.UP) || - (currentPage === this.pages.length && + (currentPage === this.pagesCount && pageFlipDirection === PageFlipDirection.DOWN)) { return; } @@ -1613,6 +1522,7 @@ var PDFView = { }; //#include page_view.js +//#include pdf_viewer.js //#include thumbnail_view.js //#include text_layer_builder.js //#include document_outline_view.js @@ -1847,7 +1757,7 @@ function webViewerInitialized() { document.getElementById('scaleSelect').addEventListener('change', function() { - PDFView.setScale(this.value); + PDFView.pdfViewer.setScale(this.value); }); document.getElementById('presentationMode').addEventListener('click', @@ -1905,100 +1815,49 @@ function webViewerInitialized() { document.addEventListener('DOMContentLoaded', webViewerLoad, true); function updateViewarea() { - if (!PDFView.initialized) { return; } - var visible = PDFView.getVisiblePages(); - var visiblePages = visible.views; - if (visiblePages.length === 0) { + PDFView.pdfViewer.update(); +} + +window.addEventListener('updateviewarea', function () { + if (!PDFView.initialized) { return; } - var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, - 2 * visiblePages.length + 1); - cache.resize(suggestedCacheSize); - - PDFView.renderHighestPriority(visible); - - var currentId = PDFView.page; - var firstPage = visible.first; - - for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; - i < ii; ++i) { - var page = visiblePages[i]; - - if (page.percent < 100) { - break; - } - if (page.id === PDFView.page) { - stillFullyVisible = true; - break; - } - } - - if (!stillFullyVisible) { - currentId = visiblePages[0].id; - } - - if (!PresentationMode.active) { - updateViewarea.inProgress = true; // used in "set page" - PDFView.page = currentId; - updateViewarea.inProgress = false; - } - - var currentScale = PDFView.currentScale; - var currentScaleValue = PDFView.currentScaleValue; - var normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? - Math.round(currentScale * 10000) / 100 : currentScaleValue; - - var pageNumber = firstPage.id; - var pdfOpenParams = '#page=' + pageNumber; - pdfOpenParams += '&zoom=' + normalizedScaleValue; - var currentPage = PDFView.pages[pageNumber - 1]; - var container = PDFView.container; - var topLeft = currentPage.getPagePoint((container.scrollLeft - firstPage.x), - (container.scrollTop - firstPage.y)); - var intLeft = Math.round(topLeft[0]); - var intTop = Math.round(topLeft[1]); - pdfOpenParams += ',' + intLeft + ',' + intTop; - - if (PresentationMode.active || PresentationMode.switchInProgress) { - PDFView.currentPosition = null; - } else { - PDFView.currentPosition = { page: pageNumber, left: intLeft, top: intTop }; - } + var location = PDFView.pdfViewer.location; PDFView.store.initializedPromise.then(function() { PDFView.store.setMultiple({ 'exists': true, - 'page': pageNumber, - 'zoom': normalizedScaleValue, - 'scrollLeft': intLeft, - 'scrollTop': intTop + 'page': location.pageNumber, + 'zoom': location.scale, + 'scrollLeft': location.left, + 'scrollTop': location.top }).catch(function() { // unable to write to storage }); }); - var href = PDFView.getAnchorUrl(pdfOpenParams); + var href = PDFView.getAnchorUrl(location.pdfOpenParams); document.getElementById('viewBookmark').href = href; document.getElementById('secondaryViewBookmark').href = href; // Update the current bookmark in the browsing history. - PDFHistory.updateCurrentBookmark(pdfOpenParams, pageNumber); -} + PDFHistory.updateCurrentBookmark(location.pdfOpenParams, location.pageNumber); +}, true); window.addEventListener('resize', function webViewerResize(evt) { if (PDFView.initialized && (document.getElementById('pageWidthOption').selected || document.getElementById('pageFitOption').selected || document.getElementById('pageAutoOption').selected)) { - PDFView.setScale(document.getElementById('scaleSelect').value); + PDFView.pdfViewer.setScale(document.getElementById('scaleSelect').value); } updateViewarea(); // Set the 'max-height' CSS property of the secondary toolbar. - SecondaryToolbar.setMaxHeight(PDFView.container); + SecondaryToolbar.setMaxHeight(document.getElementById('viewerContainer')); }); window.addEventListener('hashchange', function webViewerHashchange(evt) { @@ -2077,7 +1936,7 @@ window.addEventListener('localized', function localized(evt) { } // Set the 'max-height' CSS property of the secondary toolbar. - SecondaryToolbar.setMaxHeight(PDFView.container); + SecondaryToolbar.setMaxHeight(document.getElementById('viewerContainer')); }); }, true); @@ -2096,6 +1955,12 @@ window.addEventListener('scalechange', function scalechange(evt) { return; } + if (evt.presetValue) { + selectScaleOption(evt.presetValue); + updateViewarea(); + return; + } + var predefinedValueFound = selectScaleOption('' + evt.scale); if (!predefinedValueFound) { customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%'; @@ -2106,17 +1971,27 @@ window.addEventListener('scalechange', function scalechange(evt) { window.addEventListener('pagechange', function pagechange(evt) { var page = evt.pageNumber; - if (PDFView.previousPageNumber !== page) { + if (PDFView.pdfViewer.previousPageNumber !== page) { document.getElementById('pageNumber').value = page; PDFView.pdfThumbnailViewer.updatePage(page); } - var numPages = PDFView.pages.length; + var numPages = PDFView.pagesCount; document.getElementById('previous').disabled = (page <= 1); document.getElementById('next').disabled = (page >= numPages); document.getElementById('firstPage').disabled = (page <= 1); document.getElementById('lastPage').disabled = (page >= numPages); + + // checking if the this.page was called from the updateViewarea function + if (evt.updateInProgress) { + return; + } + // Avoid scrolling the first page during loading + if (this.loading && page === 1) { + return; + } + PDFView.getPageView(page - 1).scrollIntoView(); }, true); function handleMouseWheel(evt) { @@ -2138,7 +2013,8 @@ window.addEventListener('mousewheel', handleMouseWheel); window.addEventListener('click', function click(evt) { if (!PresentationMode.active) { - if (SecondaryToolbar.opened && PDFView.container.contains(evt.target)) { + if (SecondaryToolbar.opened && + PDFView.pdfViewer.containsElement(evt.target)) { SecondaryToolbar.close(); } } else if (evt.button === 0) { @@ -2194,7 +2070,7 @@ window.addEventListener('keydown', function keydown(evt) { // keeping it unhandled (to restore page zoom to 100%) setTimeout(function () { // ... and resetting the scale after browser adjusts its scale - PDFView.setScale(DEFAULT_SCALE, true); + PDFView.pdfViewer.setScale(DEFAULT_SCALE, true); }); handled = false; break; @@ -2259,7 +2135,7 @@ window.addEventListener('keydown', function keydown(evt) { /* falls through */ case 37: // left arrow // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { + if (PDFView.pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ @@ -2288,7 +2164,7 @@ window.addEventListener('keydown', function keydown(evt) { /* falls through */ case 39: // right arrow // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { + if (PDFView.pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ @@ -2306,8 +2182,8 @@ window.addEventListener('keydown', function keydown(evt) { break; case 35: // end if (PresentationMode.active || (PDFView.pdfDocument && - PDFView.page < PDFView.pdfDocument.numPages)) { - PDFView.page = PDFView.pdfDocument.numPages; + PDFView.page < PDFView.pagesCount)) { + PDFView.page = PDFView.pagesCount; handled = true; } break; @@ -2344,21 +2220,21 @@ window.addEventListener('keydown', function keydown(evt) { // 33=Page Up 34=Page Down 35=End 36=Home // 37=Left 38=Up 39=Right 40=Down if (evt.keyCode >= 33 && evt.keyCode <= 40 && - !PDFView.container.contains(curElement)) { + !PDFView.pdfViewer.containsElement(curElement)) { // The page container is not focused, but a page navigation key has been // pressed. Change the focus to the viewer container to make sure that // navigation by keyboard works as expected. - PDFView.container.focus(); + PDFView.pdfViewer.focus(); } // 32=Spacebar if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') { //#if (FIREFOX || MOZCENTRAL) // // Workaround for issue in Firefox, that prevents scroll keys from // // working when elements with 'tabindex' are focused. (#3498) -// PDFView.container.blur(); +// PDFView.pdfViewer.blur(); //#else - if (!PDFView.container.contains(curElement)) { - PDFView.container.focus(); + if (!PDFView.pdfViewer.containsElement(curElement)) { + PDFView.pdfViewer.focus(); } //#endif } From 7642c397342cf4535e22b57c0ba8e5361760fca2 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 09:49:24 -0500 Subject: [PATCH 04/11] Moves pdfDocument.getPage/getTextContent requests out of PDFView --- web/page_view.js | 14 ++-- web/pdf_find_controller.js | 25 ++++--- web/pdf_viewer.js | 149 ++++++++++++++++++++++++++++++++----- web/thumbnail_view.js | 52 ++++++++----- web/viewer.js | 98 +++++------------------- 5 files changed, 204 insertions(+), 134 deletions(-) diff --git a/web/page_view.js b/web/page_view.js index e5663272f..7330f19e7 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -22,7 +22,8 @@ 'use strict'; var PageView = function pageView(container, id, scale, defaultViewport, - linkService, renderingQueue, cache, viewer) { + linkService, renderingQueue, cache, + pageSource, viewer) { this.id = id; this.rotation = 0; @@ -34,6 +35,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, this.linkService = linkService; this.renderingQueue = renderingQueue; this.cache = cache; + this.pageSource = pageSource; this.viewer = viewer; this.renderingState = RenderingStates.INITIAL; @@ -430,12 +432,6 @@ var PageView = function pageView(container, id, scale, defaultViewport, scrollIntoView(div, { left: left, top: top }); }; - this.getTextContent = function pageviewGetTextContent() { - return this.renderingQueue.getPage(this.id).then(function(pdfPage) { - return pdfPage.getTextContent(); - }); - }; - this.draw = function pageviewDraw(callback) { var pdfPage = this.pdfPage; @@ -443,7 +439,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, return; } if (!pdfPage) { - var promise = this.renderingQueue.getPage(this.id); + var promise = this.pageSource.getPage(); promise.then(function(pdfPage) { delete this.pagePdfPromise; this.setPdfPage(pdfPage); @@ -631,7 +627,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, function pdfPageRenderCallback() { pageViewDrawCallback(null); if (textLayer) { - self.getTextContent().then( + self.pdfPage.getTextContent().then( function textContentResolved(textContent) { textLayer.setTextContent(textContent); } diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js index 46c724d0e..1b2dc6497 100644 --- a/web/pdf_find_controller.js +++ b/web/pdf_find_controller.js @@ -13,10 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFJS, FindStates, FirefoxCom, Promise */ +/* globals PDFJS, FirefoxCom, Promise */ 'use strict'; +var FindStates = { + FIND_FOUND: 0, + FIND_NOTFOUND: 1, + FIND_WRAPPED: 2, + FIND_PENDING: 3 +}; + /** * Provides "search" or "find" functionality for the PDF. * This object actually performs the search for a given string. @@ -41,7 +48,7 @@ var PDFFindController = (function PDFFindControllerClosure() { this.state = null; this.dirtyMatch = false; this.findTimeout = null; - this.pdfPageSource = options.pdfPageSource || null; + this.pdfViewer = options.pdfViewer || null; this.integratedFind = options.integratedFind || false; this.charactersToNormalize = { '\u2018': '\'', // Left single quotation mark @@ -137,7 +144,7 @@ var PDFFindController = (function PDFFindControllerClosure() { this.pageContents = []; var extractTextPromisesResolves = []; - var numPages = this.pdfPageSource.pagesCount; + var numPages = this.pdfViewer.pagesCount; for (var i = 0; i < numPages; i++) { this.extractTextPromises.push(new Promise(function (resolve) { extractTextPromisesResolves.push(resolve); @@ -146,7 +153,7 @@ var PDFFindController = (function PDFFindControllerClosure() { var self = this; function extractPageText(pageIndex) { - self.pdfPageSource.getPageView(pageIndex).getTextContent().then( + self.pdfViewer.getPageTextContent(pageIndex).then( function textContentResolved(textContent) { var textItems = textContent.items; var str = []; @@ -159,7 +166,7 @@ var PDFFindController = (function PDFFindControllerClosure() { self.pageContents.push(str.join('')); extractTextPromisesResolves[pageIndex](pageIndex); - if ((pageIndex + 1) < self.pdfPageSource.pagesCount) { + if ((pageIndex + 1) < self.pdfViewer.pagesCount) { extractPageText(pageIndex + 1); } } @@ -189,7 +196,7 @@ var PDFFindController = (function PDFFindControllerClosure() { }, updatePage: function PDFFindController_updatePage(index) { - var page = this.pdfPageSource.getPageView(index); + var page = this.pdfViewer.getPageView(index); if (this.selected.pageIdx === index) { // If the page is selected, scroll the page into view, which triggers @@ -205,8 +212,8 @@ var PDFFindController = (function PDFFindControllerClosure() { nextMatch: function PDFFindController_nextMatch() { var previous = this.state.findPrevious; - var currentPageIndex = this.pdfPageSource.page - 1; - var numPages = this.pdfPageSource.pagesCount; + var currentPageIndex = this.pdfViewer.currentPageNumber - 1; + var numPages = this.pdfViewer.pagesCount; this.active = true; @@ -346,7 +353,7 @@ var PDFFindController = (function PDFFindControllerClosure() { this.updateUIState(state, this.state.findPrevious); if (this.selected.pageIdx !== -1) { - this.updatePage(this.selected.pageIdx, true); + this.updatePage(this.selected.pageIdx); } }, diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index f2bc25758..30f82b534 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -17,7 +17,7 @@ /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, getVisibleElements, PresentationMode, - RenderingStates */ + RenderingStates, Promise, CSS_UNITS, PDFJS */ 'use strict'; @@ -29,11 +29,7 @@ var PDFViewer = (function pdfViewer() { this.linkService = options.linkService; this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); - this.pages = []; - this.cache = new Cache(DEFAULT_CACHE_SIZE); - this.currentPageNumber = 1; - this.previousPageNumber = 1; - this.updateInProgress = true; + this.updateInProgress = false; this.resetView(); } @@ -42,6 +38,10 @@ var PDFViewer = (function pdfViewer() { return this.pages.length; }, + getPageView: function (index) { + return this.pages[index]; + }, + setCurrentPageNumber: function (val) { var event = document.createEvent('UIEvents'); event.initUIEvent('pagechange', true, true, window, 0); @@ -61,18 +61,114 @@ var PDFViewer = (function pdfViewer() { this.container.dispatchEvent(event); }, - addPage: function (pageNum, scale, viewport) { - var pageView = new PageView(this.viewer, pageNum, scale, viewport, - this.linkService, this.renderingQueue, - this.cache, this); - this.pages.push(pageView); - return pageView; + setDocument: function (pdfDocument) { + if (this.pdfDocument) { + this.resetView(); + } + + this.pdfDocument = pdfDocument; + if (!pdfDocument) { + return; + } + + var pagesCount = pdfDocument.numPages; + var pagesRefMap = this.pagesRefMap = {}; + var self = this; + + var resolvePagesPromise; + var pagesPromise = new Promise(function (resolve) { + resolvePagesPromise = resolve; + }); + this.pagesPromise = pagesPromise; + pagesPromise.then(function () { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagesloaded', true, true, { + pagesCount: pagesCount + }); + self.container.dispatchEvent(event); + }); + + var isOnePageRenderedResolved = false; + var resolveOnePageRendered = null; + var onePageRendered = new Promise(function (resolve) { + resolveOnePageRendered = resolve; + }); + this.onePageRendered = onePageRendered; + + var bindOnAfterDraw = function (pageView) { + // when page is painted, using the image as thumbnail base + pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { + if (!isOnePageRenderedResolved) { + isOnePageRenderedResolved = true; + resolveOnePageRendered(); + } + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagerendered', true, true, { + pageNumber: pageView.id + }); + self.container.dispatchEvent(event); + }; + }; + + var firstPagePromise = pdfDocument.getPage(1); + this.firstPagePromise = firstPagePromise; + + // Fetch a single page so we can get a viewport that will be the default + // viewport for all pages + return firstPagePromise.then(function(pdfPage) { + var scale = this.currentScale || 1.0; + var viewport = pdfPage.getViewport(scale * CSS_UNITS); + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var pageSource = new PDFPageSource(pdfDocument, pageNum); + var pageView = new PageView(this.viewer, pageNum, scale, + viewport.clone(), this.linkService, + this.renderingQueue, this.cache, + pageSource, this); + bindOnAfterDraw(pageView); + this.pages.push(pageView); + } + + // Fetch all the pages since the viewport is needed before printing + // starts to create the correct size canvas. Wait until one page is + // rendered so we don't tie up too many resources early on. + onePageRendered.then(function () { + if (!PDFJS.disableAutoFetch) { + var getPagesLeft = pagesCount; + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) { + var pageView = self.pages[pageNum - 1]; + if (!pageView.pdfPage) { + pageView.setPdfPage(pdfPage); + } + var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R'; + pagesRefMap[refStr] = pageNum; + getPagesLeft--; + if (!getPagesLeft) { + resolvePagesPromise(); + } + }.bind(null, pageNum)); + } + } else { + // XXX: Printing is semi-broken with auto fetch disabled. + resolvePagesPromise(); + } + }); + }.bind(this)); }, resetView: function () { + this.cache = new Cache(DEFAULT_CACHE_SIZE); + this.pages = []; + this.currentPageNumber = 1; + this.previousPageNumber = 1; this.currentScale = UNKNOWN_SCALE; this.currentScaleValue = null; this.location = null; + + var container = this.viewer; + while (container.hasChildNodes()) { + container.removeChild(container.lastChild); + } }, _scrollUpdate: function () { @@ -171,14 +267,6 @@ var PDFViewer = (function pdfViewer() { this.setScale(this.currentScaleValue, true, true); }, - removeAllPages: function () { - var container = this.viewer; - while (container.hasChildNodes()) { - container.removeChild(container.lastChild); - } - this.pages = []; - }, - updateLocation: function (firstPage) { var currentScale = this.currentScale; var currentScaleValue = this.currentScaleValue; @@ -308,7 +396,28 @@ var PDFViewer = (function pdfViewer() { return; } }, + + getPageTextContent: function (pageIndex) { + return this.pdfDocument.getPage(pageIndex + 1).then(function (page) { + return page.getTextContent(); + }); + }, }; return PDFViewer; })(); + +var PDFPageSource = (function PDFPageSourceClosure() { + function PDFPageSource(pdfDocument, pageNumber) { + this.pdfDocument = pdfDocument; + this.pageNumber = pageNumber; + } + + PDFPageSource.prototype = { + getPage: function () { + return this.pdfDocument.getPage(this.pageNumber); + } + }; + + return PDFPageSource; +})(); diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index d6721295e..38a653dda 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -14,13 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals mozL10n, RenderingStates, THUMBNAIL_SCROLL_MARGIN, - watchScroll, getVisibleElements, scrollIntoView */ +/* globals mozL10n, RenderingStates, THUMBNAIL_SCROLL_MARGIN, Promise, + watchScroll, getVisibleElements, scrollIntoView, PDFPageSource */ 'use strict'; var ThumbnailView = function thumbnailView(container, id, defaultViewport, - linkService, renderingQueue) { + linkService, renderingQueue, + pageSource) { var anchor = document.createElement('a'); anchor.href = linkService.getAnchorUrl('#page=' + id); anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); @@ -65,6 +66,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, this.hasImage = false; this.renderingState = RenderingStates.INITIAL; this.renderingQueue = renderingQueue; + this.pageSource = pageSource; this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { this.pdfPage = pdfPage; @@ -128,7 +130,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, this.draw = function thumbnailViewDraw(callback) { if (!this.pdfPage) { - var promise = this.renderingQueue.getPage(this.id); + var promise = this.pageSource.getPage(this.id); promise.then(function(pdfPage) { this.setPdfPage(pdfPage); this.draw(callback); @@ -190,7 +192,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, this.setImage = function thumbnailViewSetImage(img) { if (!this.pdfPage) { - var promise = this.renderingQueue.getPage(this.id); + var promise = this.pageSource.getPage(); promise.then(function(pdfPage) { this.setPdfPage(pdfPage); this.setImage(img); @@ -252,6 +254,10 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { this.renderingQueue.renderHighestPriority(); }, + getThumbnail: function PDFThumbnailViewer_getThumbnail(index) { + return this.thumbnails[index]; + }, + getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { return getVisibleElements(this.container, this.thumbnails); }, @@ -289,20 +295,32 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { ThumbnailView.tempImageCache = null; }, - removeAllThumbnails: function PDFThumbnailViewer_cleanup() { - var thumbsView = this.container; - while (thumbsView.hasChildNodes()) { - thumbsView.removeChild(thumbsView.lastChild); + setDocument: function (pdfDocument) { + if (this.pdfDocument) { + // cleanup of the elements and views + var thumbsView = this.container; + while (thumbsView.hasChildNodes()) { + thumbsView.removeChild(thumbsView.lastChild); + } + this.thumbnails = []; } - this.thumbnails = []; - }, - addThumbnail: function PDFThumbnailViewer_addThumbnail(pageNum, viewport, - linkService) { - var thumbnail = new ThumbnailView(this.container, pageNum, viewport, - this.linkService, this.renderingQueue); - this.thumbnails.push(thumbnail); - return thumbnail; + this.pdfDocument = pdfDocument; + if (!pdfDocument) { + return Promise.resolve(); + } + + return pdfDocument.getPage(1).then(function (firstPage) { + var pagesCount = pdfDocument.numPages; + var viewport = firstPage.getViewport(1.0); + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var pageSource = new PDFPageSource(pdfDocument, pageNum); + var thumbnail = new ThumbnailView(this.container, pageNum, + viewport.clone(), this.linkService, + this.renderingQueue, pageSource); + this.thumbnails.push(thumbnail); + } + }.bind(this)); }, ensureThumbnailVisible: diff --git a/web/viewer.js b/web/viewer.js index 48ff868ab..937a9264f 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -52,12 +52,6 @@ var RenderingStates = { PAUSED: 2, FINISHED: 3 }; -var FindStates = { - FIND_FOUND: 0, - FIND_NOTFOUND: 1, - FIND_WRAPPED: 2, - FIND_PENDING: 3 -}; PDFJS.imageResourcesPath = './images/'; //#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME) @@ -141,7 +135,7 @@ var PDFView = { Preferences.initialize(); this.findController = new PDFFindController({ - pdfPageSource: this, + pdfViewer: this.pdfViewer, integratedFind: this.supportsIntegratedFind }); @@ -263,10 +257,6 @@ var PDFView = { }); }, - getPage: function pdfViewGetPage(n) { - return this.pdfDocument.getPage(n); - }, - getPageView: function pdfViewGetPageView(index) { return this.pdfViewer.pages[index]; }, @@ -491,8 +481,8 @@ var PDFView = { this.pdfDocument.destroy(); this.pdfDocument = null; - this.pdfThumbnailViewer.removeAllThumbnails(); - this.pdfViewer.removeAllPages(); + this.pdfThumbnailViewer.setDocument(null); + this.pdfViewer.setDocument(null); if (typeof PDFBug !== 'undefined') { PDFBug.cleanup(); @@ -845,21 +835,6 @@ var PDFView = { load: function pdfViewLoad(pdfDocument, scale) { var self = this; - var isOnePageRenderedResolved = false; - var resolveOnePageRendered = null; - var onePageRendered = new Promise(function (resolve) { - resolveOnePageRendered = resolve; - }); - function bindOnAfterDraw(pageView, thumbnailView) { - // when page is painted, using the image as thumbnail base - pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { - if (!isOnePageRenderedResolved) { - isOnePageRenderedResolved = true; - resolveOnePageRendered(); - } - thumbnailView.setImage(pageView.canvas); - }; - } PDFView.findController.reset(); @@ -884,57 +859,19 @@ var PDFView = { PDFView.documentFingerprint = id; var store = PDFView.store = new ViewHistory(id); + var pdfViewer = this.pdfViewer; + pdfViewer.currentScale = scale; + pdfViewer.setDocument(pdfDocument); + var firstPagePromise = pdfViewer.firstPagePromise; + var pagesPromise = pdfViewer.pagesPromise; + var onePageRendered = pdfViewer.onePageRendered; + this.pageRotation = 0; + this.pagesRefMap = pdfViewer.pagesRefMap; - var pagesRefMap = this.pagesRefMap = {}; + this.pdfThumbnailViewer.setDocument(pdfDocument); - var resolvePagesPromise; - var pagesPromise = new Promise(function (resolve) { - resolvePagesPromise = resolve; - }); - this.pagesPromise = pagesPromise; - - var firstPagePromise = pdfDocument.getPage(1); - var pagesViewer = this.pdfViewer; - var thumbsViewer = this.pdfThumbnailViewer; - - // Fetch a single page so we can get a viewport that will be the default - // viewport for all pages firstPagePromise.then(function(pdfPage) { - var viewport = pdfPage.getViewport((scale || 1.0) * CSS_UNITS); - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var viewportClone = viewport.clone(); - var pageView = pagesViewer.addPage(pageNum, scale, viewportClone); - var thumbnailView = thumbsViewer.addThumbnail(pageNum, viewportClone); - bindOnAfterDraw(pageView, thumbnailView); - } - - // Fetch all the pages since the viewport is needed before printing - // starts to create the correct size canvas. Wait until one page is - // rendered so we don't tie up too many resources early on. - onePageRendered.then(function () { - if (!PDFJS.disableAutoFetch) { - var getPagesLeft = pagesCount; - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) { - var pageView = PDFView.getPageView(pageNum - 1); - if (!pageView.pdfPage) { - pageView.setPdfPage(pdfPage); - } - var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R'; - pagesRefMap[refStr] = pageNum; - getPagesLeft--; - if (!getPagesLeft) { - resolvePagesPromise(); - } - }.bind(null, pageNum)); - } - } else { - // XXX: Printing is semi-broken with auto fetch disabled. - resolvePagesPromise(); - } - }); - downloadedPromise.then(function () { var event = document.createEvent('CustomEvent'); event.initCustomEvent('documentload', true, true, {}); @@ -1118,10 +1055,6 @@ var PDFView = { }, setInitialView: function pdfViewSetInitialView(storedHash, scale) { - // Reset the current scale, as otherwise the page's scale might not get - // updated if the zoom level stayed the same. - this.pdfViewer.resetView(); - // When opening a new file (when one is already loaded in the viewer): // Reset 'currentPageNumber', since otherwise the page's scale will be wrong // if 'currentPageNumber' is larger than the number of pages in the file. @@ -1814,6 +1747,13 @@ function webViewerInitialized() { document.addEventListener('DOMContentLoaded', webViewerLoad, true); +document.addEventListener('pagerendered', function (e) { + var pageIndex = e.detail.pageNumber - 1; + var pageView = PDFView.pdfViewer.getPageView(pageIndex); + var thumbnailView = PDFView.pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView.canvas); +}, true); + function updateViewarea() { if (!PDFView.initialized) { return; From a06a974f78b17b8ab72d11a33e9a8a8b2067caa5 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 11:18:28 -0500 Subject: [PATCH 05/11] Moves rendering queue logic from PDFView --- web/page_view.js | 3 +- web/pdf_rendering_queue.js | 151 +++++++++++++++++++++++++++++++++++++ web/pdf_viewer.js | 2 +- web/thumbnail_view.js | 5 +- web/viewer.html | 1 + web/viewer.js | 126 +++++-------------------------- 6 files changed, 178 insertions(+), 110 deletions(-) create mode 100644 web/pdf_rendering_queue.js 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', From fbd7eedce8d945ea3c14191a61b4329631f429e2 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 12:37:03 -0500 Subject: [PATCH 06/11] Removes PresentationMode dependency from PDFViewer --- web/page_view.js | 13 ++++++++----- web/pdf_viewer.js | 35 ++++++++++++++++++++++------------- web/presentation_mode.js | 14 ++++++++++++++ web/viewer.js | 10 +++++++++- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/web/page_view.js b/web/page_view.js index c6cc9e31e..583cba585 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -15,9 +15,9 @@ * limitations under the License. */ /* globals RenderingStates, PDFView, PDFJS, mozL10n, CustomStyle, - PresentationMode, scrollIntoView, SCROLLBAR_PADDING, CSS_UNITS, - UNKNOWN_SCALE, DEFAULT_SCALE, getOutputScale, TextLayerBuilder, - Stats */ + SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE, + getOutputScale, TextLayerBuilder, scrollIntoView, Stats, + PresentationModeState */ 'use strict'; @@ -346,7 +346,8 @@ var PageView = function pageView(container, id, scale, defaultViewport, }; this.scrollIntoView = function pageViewScrollIntoView(dest) { - if (PresentationMode.active) { + if (this.viewer.presentationModeState === + PresentationModeState.FULLSCREEN) { if (this.linkService.page !== this.id) { // Avoid breaking getVisiblePages in presentation mode. this.linkService.page = this.id; @@ -520,13 +521,15 @@ var PageView = function pageView(container, id, scale, defaultViewport, div.appendChild(textLayerDiv); } } + var isViewerInPresentationMode = + this.viewer.presentationModeState === PresentationModeState.FULLSCREEN; var textLayer = this.textLayer = textLayerDiv ? new TextLayerBuilder({ textLayerDiv: textLayerDiv, pageIndex: this.id - 1, lastScrollSource: this.linkService, viewport: this.viewport, - isViewerInPresentationMode: PresentationMode.active, + isViewerInPresentationMode: isViewerInPresentationMode, findController: PDFView.findController }) : null; // TODO(mack): use data attributes to store these diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 8e6105d44..1f5ac7c85 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -16,11 +16,18 @@ */ /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, - MAX_AUTO_SCALE, getVisibleElements, PresentationMode, - RenderingStates, Promise, CSS_UNITS, PDFJS */ + MAX_AUTO_SCALE, getVisibleElements, RenderingStates, Promise, + CSS_UNITS, PDFJS */ 'use strict'; +var PresentationModeState = { + UNKNOWN: 0, + NORMAL: 1, + CHANGING: 2, + FULLSCREEN: 3, +}; + var PDFViewer = (function pdfViewer() { function PDFViewer(options) { this.container = options.container; @@ -30,6 +37,7 @@ var PDFViewer = (function pdfViewer() { this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); this.updateInProgress = false; + this.presentationModeState = PresentationModeState.UNKNOWN; this.resetView(); } @@ -191,7 +199,10 @@ var PDFViewer = (function pdfViewer() { if (!noScroll) { var page = this.currentPageNumber, dest; - if (this.location && !this.inPresentationMode && + var inPresentationMode = + this.presentationModeState === PresentationModeState.CHANGING || + this.presentationModeState === PresentationModeState.FULLSCREEN; + if (this.location && !inPresentationMode && !IGNORE_CURRENT_POSITION_ON_ZOOM) { page = this.location.pageNumber; dest = [null, { name: 'XYZ' }, this.location.left, @@ -223,8 +234,10 @@ var PDFViewer = (function pdfViewer() { if (!currentPage) { return; } - var hPadding = PresentationMode.active ? 0 : SCROLLBAR_PADDING; - var vPadding = PresentationMode.active ? 0 : VERTICAL_PADDING; + var inPresentationMode = + this.presentationModeState === PresentationModeState.FULLSCREEN; + var hPadding = inPresentationMode ? 0 : SCROLLBAR_PADDING; + var vPadding = inPresentationMode ? 0 : VERTICAL_PADDING; var pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale; var pageHeightScale = (this.container.clientHeight - vPadding) / @@ -295,10 +308,6 @@ var PDFViewer = (function pdfViewer() { }; }, - get inPresentationMode() { - return PresentationMode.active || PresentationMode.switchInProgress; - }, - update: function () { var visible = this.getVisiblePages(); var visiblePages = visible.views; @@ -334,7 +343,7 @@ var PDFViewer = (function pdfViewer() { currentId = visiblePages[0].id; } - if (!PresentationMode.active) { + if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { this.setCurrentPageNumber(currentId); } @@ -360,12 +369,12 @@ var PDFViewer = (function pdfViewer() { }, get isHorizontalScrollbarEnabled() { - return (PresentationMode.active ? false : - (this.container.scrollWidth > this.container.clientWidth)); + return (this.presentationModeState === PresentationModeState.FULLSCREEN ? + false : (this.container.scrollWidth > this.container.clientWidth)); }, getVisiblePages: function () { - if (!PresentationMode.active) { + if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { return getVisibleElements(this.container, this.pages, true); } else { // The algorithm in getVisibleElements doesn't work in all browsers and diff --git a/web/presentation_mode.js b/web/presentation_mode.js index f297623c8..ee4e78157 100644 --- a/web/presentation_mode.js +++ b/web/presentation_mode.js @@ -81,6 +81,7 @@ var PresentationMode = { } this.switchInProgress = setTimeout(function switchInProgressTimeout() { delete this.switchInProgress; + this._notifyStateChange(); }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); }, @@ -97,6 +98,7 @@ var PresentationMode = { return false; } this._setSwitchInProgress(); + this._notifyStateChange(); if (this.container.requestFullscreen) { this.container.requestFullscreen(); @@ -118,9 +120,19 @@ var PresentationMode = { return true; }, + _notifyStateChange: function presentationModeNotifyStateChange() { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('presentationmodechanged', true, true, { + active: PresentationMode.active, + switchInProgress: !!PresentationMode.switchInProgress + }); + window.dispatchEvent(event); + }, + enter: function presentationModeEnter() { this.active = true; this._resetSwitchInProgress(); + this._notifyStateChange(); // Ensure that the correct page is scrolled into view when entering // Presentation Mode, by waiting until fullscreen mode in enabled. @@ -148,6 +160,8 @@ var PresentationMode = { // Note: This is only necessary in non-Mozilla browsers. setTimeout(function exitPresentationModeTimeout() { this.active = false; + this._notifyStateChange(); + PDFView.setScale(this.args.previousScale, true); PDFView.page = page; this.args = null; diff --git a/web/viewer.js b/web/viewer.js index 43b0fea02..00ba94f23 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, PDFRenderingQueue */ + watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState */ 'use strict'; @@ -1668,6 +1668,14 @@ document.addEventListener('pagerendered', function (e) { thumbnailView.setImage(pageView.canvas); }, true); +window.addEventListener('presentationmodechanged', function (e) { + var active = e.detail.active; + var switchInProgress = e.detail.switchInProgress; + PDFView.pdfViewer.presentationModeState = + switchInProgress ? PresentationModeState.CHANGING : + active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL; +}); + function updateViewarea() { if (!PDFView.initialized) { return; From f1851c6393a233b0ad9019fa2dd8f76557b4a89b Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 14:57:12 -0500 Subject: [PATCH 07/11] Removes any usage of PDFView in the PageView --- web/page_view.js | 51 +++++++++-------------------------------------- web/pdf_viewer.js | 22 +++++++++++++++++++- web/viewer.js | 36 ++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/web/page_view.js b/web/page_view.js index 583cba585..86572cb89 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals RenderingStates, PDFView, PDFJS, mozL10n, CustomStyle, +/* globals RenderingStates, PDFJS, mozL10n, CustomStyle, SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE, - getOutputScale, TextLayerBuilder, scrollIntoView, Stats, - PresentationModeState */ + getOutputScale, scrollIntoView, Stats, PresentationModeState */ 'use strict'; @@ -509,6 +508,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, canvas._viewport = viewport; var textLayerDiv = null; + var textLayer = null; if (!PDFJS.disableTextLayer) { textLayerDiv = document.createElement('div'); textLayerDiv.className = 'textLayer'; @@ -520,18 +520,12 @@ var PageView = function pageView(container, id, scale, defaultViewport, } else { div.appendChild(textLayerDiv); } + + textLayer = this.viewer.createTextLayerBuilder(textLayerDiv, this.id - 1, + this.viewport); } - var isViewerInPresentationMode = - this.viewer.presentationModeState === PresentationModeState.FULLSCREEN; - var textLayer = this.textLayer = - textLayerDiv ? new TextLayerBuilder({ - textLayerDiv: textLayerDiv, - pageIndex: this.id - 1, - lastScrollSource: this.linkService, - viewport: this.viewport, - isViewerInPresentationMode: isViewerInPresentationMode, - findController: PDFView.findController - }) : null; + this.textLayer = textLayer; + // TODO(mack): use data attributes to store these ctx._scaleX = outputScale.sx; ctx._scaleY = outputScale.sy; @@ -566,22 +560,7 @@ var PageView = function pageView(container, id, scale, defaultViewport, self.zoomLayer = null; } -//#if (FIREFOX || MOZCENTRAL) -// if (self.textLayer && self.textLayer.textDivs && -// self.textLayer.textDivs.length > 0 && -// !PDFView.supportsDocumentColors) { -// console.error(mozL10n.get('document_colors_disabled', null, -// 'PDF documents are not allowed to use their own colors: ' + -// '\'Allow pages to choose their own colors\' ' + -// 'is deactivated in the browser.')); -// PDFView.fallback(); -// } -//#endif - if (error) { - PDFView.error(mozL10n.get('rendering_error', null, - 'An error occurred while rendering the page.'), error); - } - + self.error = error; self.stats = pdfPage.stats; self.updateStats(); if (self.onAfterDraw) { @@ -594,18 +573,6 @@ var PageView = function pageView(container, id, scale, defaultViewport, }); div.dispatchEvent(event); -//#if (FIREFOX || MOZCENTRAL) -// FirefoxCom.request('reportTelemetry', JSON.stringify({ -// type: 'pageInfo' -// })); -// // It is a good time to report stream and font types -// PDFView.pdfDocument.getStats().then(function (stats) { -// FirefoxCom.request('reportTelemetry', JSON.stringify({ -// type: 'documentStats', -// stats: stats -// })); -// }); -//#endif callback(); } diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 1f5ac7c85..e5f49d2ed 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -17,7 +17,7 @@ /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, getVisibleElements, RenderingStates, Promise, - CSS_UNITS, PDFJS */ + CSS_UNITS, PDFJS, TextLayerBuilder */ 'use strict'; @@ -36,6 +36,7 @@ var PDFViewer = (function pdfViewer() { this.linkService = options.linkService; this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); + this.lastScroll = 0; this.updateInProgress = false; this.presentationModeState = PresentationModeState.UNKNOWN; this.resetView(); @@ -180,6 +181,8 @@ var PDFViewer = (function pdfViewer() { }, _scrollUpdate: function () { + this.lastScroll = Date.now(); + if (this.pagesCount === 0) { return; } @@ -411,6 +414,23 @@ var PDFViewer = (function pdfViewer() { return page.getTextContent(); }); }, + + createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) { + var isViewerInPresentationMode = + this.presentationModeState === PresentationModeState.FULLSCREEN; + return new TextLayerBuilder({ + textLayerDiv: textLayerDiv, + pageIndex: pageIndex, + viewport: viewport, + lastScrollSource: this, + isViewerInPresentationMode: isViewerInPresentationMode, + findController: this.findController + }); + }, + + setFindController: function (findController) { + this.findController = findController; + }, }; return PDFViewer; diff --git a/web/viewer.js b/web/viewer.js index 00ba94f23..4d015486a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -104,7 +104,6 @@ var PDFView = { pageRotation: 0, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, - lastScroll: 0, isViewerEmbedded: (window.parent !== window), url: '', @@ -138,6 +137,7 @@ var PDFView = { pdfViewer: this.pdfViewer, integratedFind: this.supportsIntegratedFind }); + this.pdfViewer.setFindController(this.findController); this.findBar = new PDFFindBar({ bar: document.getElementById('findbar'), @@ -211,10 +211,6 @@ var PDFView = { pageCountField: document.getElementById('pageCountField') }); - container.addEventListener('scroll', function() { - self.lastScroll = Date.now(); - }, false); - var initializedPromise = Promise.all([ Preferences.get('enableWebGL').then(function resolved(value) { PDFJS.disableWebGL = !value; @@ -1666,6 +1662,36 @@ document.addEventListener('pagerendered', function (e) { var pageView = PDFView.pdfViewer.getPageView(pageIndex); var thumbnailView = PDFView.pdfThumbnailViewer.getThumbnail(pageIndex); thumbnailView.setImage(pageView.canvas); + +//#if (FIREFOX || MOZCENTRAL) +//if (pageView.textLayer && pageView.textLayer.textDivs && +// pageView.textLayer.textDivs.length > 0 && +// !PDFView.supportsDocumentColors) { +// console.error(mozL10n.get('document_colors_disabled', null, +// 'PDF documents are not allowed to use their own colors: ' + +// '\'Allow pages to choose their own colors\' ' + +// 'is deactivated in the browser.')); +// PDFView.fallback(); +//} +//#endif + + if (pageView.error) { + PDFView.error(mozL10n.get('rendering_error', null, + 'An error occurred while rendering the page.'), pageView.error); + } + +//#if (FIREFOX || MOZCENTRAL) +//FirefoxCom.request('reportTelemetry', JSON.stringify({ +// type: 'pageInfo' +//})); +//// It is a good time to report stream and font types +//PDFView.pdfDocument.getStats().then(function (stats) { +// FirefoxCom.request('reportTelemetry', JSON.stringify({ +// type: 'documentStats', +// stats: stats +// })); +//}); +//#endif }, true); window.addEventListener('presentationmodechanged', function (e) { From a1eca2084d0379ba5aa71ae97ec01967f7070a1a Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 15:46:01 -0500 Subject: [PATCH 08/11] Moves constants to avoid dependency on PDFView --- web/pdf_rendering_queue.js | 3 ++- web/pdf_viewer.js | 30 ++++++++++++++++++++++++------ web/thumbnail_view.js | 6 ++++-- web/ui_utils.js | 8 ++++++++ web/viewer.html | 2 +- web/viewer.js | 20 +++++--------------- 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js index 58424b728..65d30b781 100644 --- a/web/pdf_rendering_queue.js +++ b/web/pdf_rendering_queue.js @@ -14,10 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/*globals CLEANUP_TIMEOUT */ 'use strict'; +var CLEANUP_TIMEOUT = 30000; + var RenderingStates = { INITIAL: 0, RUNNING: 1, diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index e5f49d2ed..1ea61bb5a 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -15,9 +15,9 @@ * limitations under the License. */ /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, - IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, - MAX_AUTO_SCALE, getVisibleElements, RenderingStates, Promise, - CSS_UNITS, PDFJS, TextLayerBuilder */ + SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, CSS_UNITS, + getVisibleElements, RenderingStates, Promise, + PDFJS, TextLayerBuilder, PDFRenderingQueue */ 'use strict'; @@ -28,13 +28,27 @@ var PresentationModeState = { FULLSCREEN: 3, }; +var IGNORE_CURRENT_POSITION_ON_ZOOM = false; + +//#include pdf_rendering_queue.js +//#include page_view.js +//#include text_layer_builder.js + var PDFViewer = (function pdfViewer() { function PDFViewer(options) { this.container = options.container; - this.viewer = options.viewer; - this.renderingQueue = options.renderingQueue; + this.viewer = options.viewer || options.container.firstElementChild; this.linkService = options.linkService; + this.defaultRenderingQueue = !options.renderingQueue; + if (this.defaultRenderingQueue) { + // Custom rendering queue is not specified, using default one + this.renderingQueue = new PDFRenderingQueue(); + this.renderingQueue.setViewer(this); + } else { + this.renderingQueue = options.renderingQueue; + } + this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); this.lastScroll = 0; this.updateInProgress = false; @@ -162,6 +176,10 @@ var PDFViewer = (function pdfViewer() { resolvePagesPromise(); } }); + + if (this.defaultRenderingQueue) { + firstPagePromise.then(this.update.bind(this)); + } }.bind(this)); }, @@ -206,7 +224,7 @@ var PDFViewer = (function pdfViewer() { this.presentationModeState === PresentationModeState.CHANGING || this.presentationModeState === PresentationModeState.FULLSCREEN; if (this.location && !inPresentationMode && - !IGNORE_CURRENT_POSITION_ON_ZOOM) { + !IGNORE_CURRENT_POSITION_ON_ZOOM) { page = this.location.pageNumber; dest = [null, { name: 'XYZ' }, this.location.left, this.location.top, null]; diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index efd10a9d1..313b2339d 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -14,11 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals mozL10n, RenderingStates, THUMBNAIL_SCROLL_MARGIN, Promise, - watchScroll, getVisibleElements, scrollIntoView, PDFPageSource */ +/* globals mozL10n, RenderingStates, Promise, scrollIntoView, PDFPageSource, + watchScroll, getVisibleElements */ 'use strict'; +var THUMBNAIL_SCROLL_MARGIN = -19; + var ThumbnailView = function thumbnailView(container, id, defaultViewport, linkService, renderingQueue, pageSource) { diff --git a/web/ui_utils.js b/web/ui_utils.js index 04805c053..1779b60c3 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -16,6 +16,14 @@ 'use strict'; +var CSS_UNITS = 96.0 / 72.0; +var DEFAULT_SCALE = 'auto'; +var UNKNOWN_SCALE = 0; +var MAX_AUTO_SCALE = 1.25; +var SCROLLBAR_PADDING = 40; +var VERTICAL_PADDING = 5; +var DEFAULT_CACHE_SIZE = 10; + // optimised CSS custom property getter/setter var CustomStyle = (function CustomStyleClosure() { diff --git a/web/viewer.html b/web/viewer.html index 96af7b46e..471d0361a 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -70,9 +70,9 @@ http://sourceforge.net/adobe/cmap/wiki/License/ + - diff --git a/web/viewer.js b/web/viewer.js index 4d015486a..3d93ea964 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -21,27 +21,20 @@ PasswordPrompt, PresentationMode, HandTool, Promise, DocumentProperties, DocumentOutlineView, DocumentAttachmentsView, OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, - watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState */ + watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState, + DEFAULT_SCALE, UNKNOWN_SCALE, + IGNORE_CURRENT_POSITION_ON_ZOOM: true */ 'use strict'; var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf'; -var DEFAULT_SCALE = 'auto'; var DEFAULT_SCALE_DELTA = 1.1; -var UNKNOWN_SCALE = 0; -var DEFAULT_CACHE_SIZE = 10; -var CSS_UNITS = 96.0 / 72.0; -var SCROLLBAR_PADDING = 40; -var VERTICAL_PADDING = 5; -var MAX_AUTO_SCALE = 1.25; var MIN_SCALE = 0.25; var MAX_SCALE = 10.0; var VIEW_HISTORY_MEMORY = 20; var SCALE_SELECT_CONTAINER_PADDING = 8; var SCALE_SELECT_PADDING = 22; -var THUMBNAIL_SCROLL_MARGIN = -19; -var CLEANUP_TIMEOUT = 30000; -var IGNORE_CURRENT_POSITION_ON_ZOOM = false; + //#if B2G //PDFJS.useOnlyCssZoom = true; //PDFJS.disableTextLayer = true; @@ -90,6 +83,7 @@ var mozL10n = document.mozL10n || document.webL10n; //#include overlay_manager.js //#include password_prompt.js //#include document_properties.js +//#include pdf_viewer.js var PDFView = { initialBookmark: document.location.hash.substring(1), @@ -1363,11 +1357,7 @@ var PDFView = { } }; -//#include pdf_rendering_queue.js -//#include page_view.js -//#include pdf_viewer.js //#include thumbnail_view.js -//#include text_layer_builder.js //#include document_outline_view.js //#include document_attachments_view.js From 3773972dce48fb23724e259b1f88d557d500d061 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Sat, 20 Sep 2014 12:15:18 -0500 Subject: [PATCH 09/11] Marks some private methods in PDFViewer and PDFThumbnailViewer Conflicts: web/pdf_viewer.js --- web/page_view.js | 7 +- web/pdf_viewer.js | 147 ++++++++++++++++++++++++++++++------------ web/thumbnail_view.js | 32 +++++---- web/viewer.js | 34 +++++----- 4 files changed, 148 insertions(+), 72 deletions(-) diff --git a/web/page_view.js b/web/page_view.js index 86572cb89..109f0f515 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -353,7 +353,8 @@ var PageView = function pageView(container, id, scale, defaultViewport, return; } dest = null; - this.viewer.setScale(this.viewer.currentScaleValue, true, true); + // Fixes the case when PDF has different page sizes. + this.viewer.currentScaleValue = this.viewer.currentScaleValue; } if (!dest) { scrollIntoView(div); @@ -413,9 +414,9 @@ var PageView = function pageView(container, id, scale, defaultViewport, } if (scale && scale !== this.viewer.currentScale) { - this.viewer.setScale(scale, true, true); + this.viewer.currentScaleValue = scale; } else if (this.viewer.currentScale === UNKNOWN_SCALE) { - this.viewer.setScale(DEFAULT_SCALE, true, true); + this.viewer.currentScaleValue = DEFAULT_SCALE; } if (scale === 'page-fit' && !dest[4]) { diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 1ea61bb5a..9bbba0931 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -53,7 +53,7 @@ var PDFViewer = (function pdfViewer() { this.lastScroll = 0; this.updateInProgress = false; this.presentationModeState = PresentationModeState.UNKNOWN; - this.resetView(); + this._resetView(); } PDFViewer.prototype = { @@ -65,28 +65,102 @@ var PDFViewer = (function pdfViewer() { return this.pages[index]; }, - setCurrentPageNumber: function (val) { + get currentPageNumber() { + return this._currentPageNumber; + }, + + set currentPageNumber(val) { + if (!this.pdfDocument) { + this._currentPageNumber = val; + return; + } + var event = document.createEvent('UIEvents'); event.initUIEvent('pagechange', true, true, window, 0); event.updateInProgress = this.updateInProgress; if (!(0 < val && val <= this.pagesCount)) { - this.previousPageNumber = val; event.pageNumber = this.page; + event.previousPageNumber = val; this.container.dispatchEvent(event); return; } this.pages[val - 1].updateStats(); - this.previousPageNumber = this.currentPageNumber; - this.currentPageNumber = val; + event.previousPageNumber = this._currentPageNumber; + this._currentPageNumber = val; event.pageNumber = val; this.container.dispatchEvent(event); }, + /** + * @returns {number} + */ + get currentScale() { + return this._currentScale; + }, + + /** + * @param {number} val - Scale of the pages in percents. + */ + set currentScale(val) { + if (isNaN(val)) { + throw new Error('Invalid numeric scale'); + } + if (!this.pdfDocument) { + this._currentScale = val; + this._currentScaleValue = val.toString(); + return; + } + this._setScale(val, false); + }, + + /** + * @returns {string} + */ + get currentScaleValue() { + return this._currentScaleValue; + }, + + /** + * @param val - The scale of the pages (in percent or predefined value). + */ + set currentScaleValue(val) { + if (!this.pdfDocument) { + this._currentScale = isNaN(val) ? UNKNOWN_SCALE : val; + this._currentScaleValue = val; + return; + } + this._setScale(val, false); + }, + + /** + * @returns {number} + */ + get pagesRotation() { + return this._pagesRotation; + }, + + /** + * @param {number} rotation - The rotation of the pages (0, 90, 180, 270). + */ + set pagesRotation(rotation) { + this._pagesRotation = rotation; + + for (var i = 0, l = this.pages.length; i < l; i++) { + var page = this.pages[i]; + page.update(page.scale, rotation); + } + + this._setScale(this._currentScaleValue, true); + }, + + /** + * @param pdfDocument {PDFDocument} + */ setDocument: function (pdfDocument) { if (this.pdfDocument) { - this.resetView(); + this._resetView(); } this.pdfDocument = pdfDocument; @@ -139,7 +213,7 @@ var PDFViewer = (function pdfViewer() { // Fetch a single page so we can get a viewport that will be the default // viewport for all pages return firstPagePromise.then(function(pdfPage) { - var scale = this.currentScale || 1.0; + var scale = this._currentScale || 1.0; var viewport = pdfPage.getViewport(scale * CSS_UNITS); for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { var pageSource = new PDFPageSource(pdfDocument, pageNum); @@ -183,14 +257,14 @@ var PDFViewer = (function pdfViewer() { }.bind(this)); }, - resetView: function () { + _resetView: function () { this.cache = new Cache(DEFAULT_CACHE_SIZE); this.pages = []; - this.currentPageNumber = 1; - this.previousPageNumber = 1; - this.currentScale = UNKNOWN_SCALE; - this.currentScaleValue = null; + this._currentPageNumber = 1; + this._currentScale = UNKNOWN_SCALE; + this._currentScaleValue = null; this.location = null; + this._pagesRotation = 0; var container = this.viewer; while (container.hasChildNodes()) { @@ -208,18 +282,18 @@ var PDFViewer = (function pdfViewer() { }, _setScaleUpdatePages: function pdfViewer_setScaleUpdatePages( - newScale, newValue, resetAutoSettings, noScroll, preset) { - this.currentScaleValue = newValue; - if (newScale === this.currentScale) { + newScale, newValue, noScroll, preset) { + this._currentScaleValue = newValue; + if (newScale === this._currentScale) { return; } for (var i = 0, ii = this.pages.length; i < ii; i++) { this.pages[i].update(newScale); } - this.currentScale = newScale; + this._currentScale = newScale; if (!noScroll) { - var page = this.currentPageNumber, dest; + var page = this._currentPageNumber, dest; var inPresentationMode = this.presentationModeState === PresentationModeState.CHANGING || this.presentationModeState === PresentationModeState.FULLSCREEN; @@ -235,23 +309,22 @@ var PDFViewer = (function pdfViewer() { var event = document.createEvent('UIEvents'); event.initUIEvent('scalechange', true, true, window, 0); event.scale = newScale; - event.resetAutoSettings = resetAutoSettings; if (preset) { event.presetValue = newValue; } this.container.dispatchEvent(event); }, - setScale: function pdfViewer_setScale(value, resetAutoSettings, noScroll) { + _setScale: function pdfViewer_setScale(value, noScroll) { if (value === 'custom') { return; } var scale = parseFloat(value); if (scale > 0) { - this._setScaleUpdatePages(scale, value, true, noScroll, false); + this._setScaleUpdatePages(scale, value, noScroll, false); } else { - var currentPage = this.pages[this.currentPageNumber - 1]; + var currentPage = this.pages[this._currentPageNumber - 1]; if (!currentPage) { return; } @@ -287,23 +360,13 @@ var PDFViewer = (function pdfViewer() { '\' is an unknown zoom value.'); return; } - this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll, - true); + this._setScaleUpdatePages(scale, value, noScroll, true); } }, - updateRotation: function pdfViewRotatePages(rotation) { - for (var i = 0, l = this.pages.length; i < l; i++) { - var page = this.pages[i]; - page.update(page.scale, rotation); - } - - this.setScale(this.currentScaleValue, true, true); - }, - - updateLocation: function (firstPage) { - var currentScale = this.currentScale; - var currentScaleValue = this.currentScaleValue; + _updateLocation: function (firstPage) { + var currentScale = this._currentScale; + var currentScaleValue = this._currentScaleValue; var normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; @@ -330,7 +393,7 @@ var PDFViewer = (function pdfViewer() { }, update: function () { - var visible = this.getVisiblePages(); + var visible = this._getVisiblePages(); var visiblePages = visible.views; if (visiblePages.length === 0) { return; @@ -354,7 +417,7 @@ var PDFViewer = (function pdfViewer() { if (page.percent < 100) { break; } - if (page.id === this.currentPageNumber) { + if (page.id === currentId) { stillFullyVisible = true; break; } @@ -365,10 +428,10 @@ var PDFViewer = (function pdfViewer() { } if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { - this.setCurrentPageNumber(currentId); + this.currentPageNumber = currentId; } - this.updateLocation(firstPage); + this._updateLocation(firstPage); this.updateInProgress = false; @@ -394,14 +457,14 @@ var PDFViewer = (function pdfViewer() { false : (this.container.scrollWidth > this.container.clientWidth)); }, - getVisiblePages: function () { + _getVisiblePages: function () { if (this.presentationModeState !== PresentationModeState.FULLSCREEN) { return getVisibleElements(this.container, this.pages, true); } else { // The algorithm in getVisibleElements doesn't work in all browsers and // configurations when presentation mode is active. var visible = []; - var currentPage = this.pages[this.currentPageNumber - 1]; + var currentPage = this.pages[this._currentPageNumber - 1]; visible.push({ id: currentPage.id, view: currentPage }); return { first: currentPage, last: currentPage, views: visible }; } @@ -417,7 +480,7 @@ var PDFViewer = (function pdfViewer() { }, forceRendering: function (currentlyVisiblePages) { - var visiblePages = currentlyVisiblePages || this.getVisiblePages(); + var visiblePages = currentlyVisiblePages || this._getVisiblePages(); var pageView = this.renderingQueue.getHighestPriority(visiblePages, this.pages, this.scroll.down); diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index 313b2339d..205e31fd6 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -247,13 +247,12 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { this.renderingQueue = options.renderingQueue; this.linkService = options.linkService; - this.scroll = watchScroll(this.container, this.scrollUpdated.bind(this)); - this.thumbnails = []; - this.currentPage = -1; + this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this)); + this._resetView(); } PDFThumbnailViewer.prototype = { - scrollUpdated: function PDFThumbnailViewer_scrollUpdated() { + _scrollUpdated: function PDFThumbnailViewer_scrollUpdated() { this.renderingQueue.renderHighestPriority(); }, @@ -261,18 +260,18 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { return this.thumbnails[index]; }, - getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { + _getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { return getVisibleElements(this.container, this.thumbnails); }, - updatePage: function (page) { + scrollThumbnailIntoView: function (page) { var selected = document.querySelector('.thumbnail.selected'); if (selected) { selected.classList.remove('selected'); } var thumbnail = document.getElementById('thumbnailContainer' + page); thumbnail.classList.add('selected'); - var visibleThumbs = this.getVisibleThumbs(); + var visibleThumbs = this._getVisibleThumbs(); var numVisibleThumbs = visibleThumbs.views.length; // If the thumbnail isn't currently visible, scroll it into view. @@ -284,13 +283,17 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN }); } } - this.currentPage = page; }, - updateRotation: function (pageRotation) { + get pagesRotation() { + return this._pagesRotation; + }, + + set pagesRotation(rotation) { + this._pagesRotation = rotation; for (var i = 0, l = this.thumbnails.length; i < l; i++) { var thumb = this.thumbnails[i]; - thumb.update(pageRotation); + thumb.update(rotation); } }, @@ -298,6 +301,11 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { ThumbnailView.tempImageCache = null; }, + _resetView: function () { + this.thumbnails = []; + this._pagesRotation = 0; + }, + setDocument: function (pdfDocument) { if (this.pdfDocument) { // cleanup of the elements and views @@ -305,7 +313,7 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { while (thumbsView.hasChildNodes()) { thumbsView.removeChild(thumbsView.lastChild); } - this.thumbnails = []; + this._resetView(); } this.pdfDocument = pdfDocument; @@ -334,7 +342,7 @@ var PDFThumbnailViewer = (function pdfThumbnailViewer() { }, forceRendering: function () { - var visibleThumbs = this.getVisibleThumbs(); + var visibleThumbs = this._getVisibleThumbs(); var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this.thumbnails, this.scroll.down); diff --git a/web/viewer.js b/web/viewer.js index 3d93ea964..99f277a57 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -96,6 +96,7 @@ var PDFView = { pdfThumbnailViewer: null, pdfRenderingQueue: null, pageRotation: 0, + updateScaleControls: true, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, isViewerEmbedded: (window.parent !== window), @@ -258,7 +259,7 @@ var PDFView = { newScale = Math.ceil(newScale * 10) / 10; newScale = Math.min(MAX_SCALE, newScale); } while (--ticks && newScale < MAX_SCALE); - this.pdfViewer.setScale(newScale, true); + this.setScale(newScale, true); }, zoomOut: function pdfViewZoomOut(ticks) { @@ -268,7 +269,7 @@ var PDFView = { newScale = Math.floor(newScale * 10) / 10; newScale = Math.max(MIN_SCALE, newScale); } while (--ticks && newScale > MIN_SCALE); - this.pdfViewer.setScale(newScale, true); + this.setScale(newScale, true); }, get currentScaleValue() { @@ -280,7 +281,7 @@ var PDFView = { }, set page(val) { - this.pdfViewer.setCurrentPageNumber(val); + this.pdfViewer.currentPageNumber = val; }, get page() { @@ -825,6 +826,7 @@ var PDFView = { load: function pdfViewLoad(pdfDocument, scale) { var self = this; + scale = scale || UNKNOWN_SCALE; PDFView.findController.reset(); @@ -1061,14 +1063,14 @@ var PDFView = { } else if (storedHash) { this.setHash(storedHash); } else if (scale) { - this.pdfViewer.setScale(scale, true); + this.setScale(scale, true); this.page = 1; } if (PDFView.pdfViewer.currentScale === UNKNOWN_SCALE) { // Scale was not initialized: invalid bookmark or scale was not specified. // Setting the default one. - this.pdfViewer.setScale(DEFAULT_SCALE, true); + this.setScale(DEFAULT_SCALE, true); } }, @@ -1270,16 +1272,18 @@ var PDFView = { this.forceRendering(); }, - setScale: function (value, resetAutoSettings, noScroll) { - this.pdfViewer.setScale(value, resetAutoSettings, noScroll); + setScale: function (value, resetAutoSettings) { + this.updateScaleControls = !!resetAutoSettings; + this.pdfViewer.currentScaleValue = value; + this.updateScaleControls = true; }, rotatePages: function pdfViewRotatePages(delta) { var currentPage = this.getPageView(this.page - 1); this.pageRotation = (this.pageRotation + 360 + delta) % 360; - this.pdfViewer.updateRotation(this.pageRotation); - this.pdfThumbnailViewer.updateRotation(this.pageRotation); + this.pdfViewer.pagesRotation = this.pageRotation; + this.pdfThumbnailViewer.pagesRotation = this.pageRotation; this.forceRendering(); @@ -1590,7 +1594,7 @@ function webViewerInitialized() { document.getElementById('scaleSelect').addEventListener('change', function() { - PDFView.pdfViewer.setScale(this.value); + PDFView.setScale(this.value, false); }); document.getElementById('presentationMode').addEventListener('click', @@ -1730,7 +1734,7 @@ window.addEventListener('resize', function webViewerResize(evt) { (document.getElementById('pageWidthOption').selected || document.getElementById('pageFitOption').selected || document.getElementById('pageAutoOption').selected)) { - PDFView.pdfViewer.setScale(document.getElementById('scaleSelect').value); + PDFView.setScale(document.getElementById('scaleSelect').value, false); } updateViewarea(); @@ -1825,7 +1829,7 @@ window.addEventListener('scalechange', function scalechange(evt) { var customScaleOption = document.getElementById('customScaleOption'); customScaleOption.selected = false; - if (!evt.resetAutoSettings && + if (!PDFView.updateScaleControls && (document.getElementById('pageWidthOption').selected || document.getElementById('pageFitOption').selected || document.getElementById('pageAutoOption').selected)) { @@ -1849,9 +1853,9 @@ window.addEventListener('scalechange', function scalechange(evt) { window.addEventListener('pagechange', function pagechange(evt) { var page = evt.pageNumber; - if (PDFView.pdfViewer.previousPageNumber !== page) { + if (evt.previousPageNumber !== page) { document.getElementById('pageNumber').value = page; - PDFView.pdfThumbnailViewer.updatePage(page); + PDFView.pdfThumbnailViewer.scrollThumbnailIntoView(page); } var numPages = PDFView.pagesCount; @@ -1948,7 +1952,7 @@ window.addEventListener('keydown', function keydown(evt) { // keeping it unhandled (to restore page zoom to 100%) setTimeout(function () { // ... and resetting the scale after browser adjusts its scale - PDFView.pdfViewer.setScale(DEFAULT_SCALE, true); + PDFView.setScale(DEFAULT_SCALE, true); }); handled = false; break; From a89bba35b21c94944f52e22eaac3ac838f9ad9cc Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Sat, 20 Sep 2014 12:21:49 -0500 Subject: [PATCH 10/11] Adds types definitions (jsdoc) for the PDFViewer code. --- web/interfaces.js | 77 ++++++++++++++++++++++++++++++++++++++ web/page_view.js | 14 +++++++ web/pdf_rendering_queue.js | 32 ++++++++++++++-- web/pdf_viewer.js | 42 ++++++++++++++++++++- web/text_layer_builder.js | 12 ++++++ web/thumbnail_view.js | 26 +++++++++++++ web/viewer.js | 3 ++ 7 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 web/interfaces.js diff --git a/web/interfaces.js b/web/interfaces.js new file mode 100644 index 000000000..1c60f9882 --- /dev/null +++ b/web/interfaces.js @@ -0,0 +1,77 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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. + */ + +'use strict'; + +/** + * @interface + */ +function IPDFLinkService() {} +IPDFLinkService.prototype = { + /** + * @returns {number} + */ + get page() {}, + /** + * @param {number} value + */ + set page(value) {}, + /** + * @param dest - The PDF destination object. + */ + navigateTo: function (dest) {}, + /** + * @param dest - The PDF destination object. + * @returns {string} The hyperlink to the PDF object. + */ + getDestinationHash: function (dest) {}, + /** + * @param hash - The PDF parameters/hash. + * @returns {string} The hyperlink to the PDF object. + */ + getAnchorUrl: function (hash) {}, +}; + +/** + * @interface + */ +function IRenderableView() {} +IRenderableView.prototype = { + /** + * @returns {string} - Unique ID for rendering queue. + */ + get renderingId() {}, + /** + * @returns {RenderingStates} + */ + get renderingState() {}, + /** + * @param {function} callback - The draw completion callback. + */ + draw: function (callback) {}, + resume: function () {}, +}; + +/** + * @interface + */ +function ILastScrollSource() {} +ILastScrollSource.prototype = { + /** + * @returns {number} + */ + get lastScroll() {}, +}; diff --git a/web/page_view.js b/web/page_view.js index 109f0f515..46b53a6db 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -20,6 +20,20 @@ 'use strict'; +/** + * @constructor + * @param {HTMLDivElement} container - The viewer element. + * @param {number} id - The page unique ID (normally its number). + * @param {number} scale - The page scale display. + * @param {PageViewport} defaultViewport - The page viewport. + * @param {IPDFLinkService} linkService - The navigation/linking service. + * @param {PDFRenderingQueue} renderingQueue - The rendering queue object. + * @param {Cache} cache - The page cache. + * @param {PDFPageSource} pageSource + * @param {PDFViewer} viewer + * + * @implements {IRenderableView} + */ var PageView = function pageView(container, id, scale, defaultViewport, linkService, renderingQueue, cache, pageSource, viewer) { diff --git a/web/pdf_rendering_queue.js b/web/pdf_rendering_queue.js index 65d30b781..c7b1b3aba 100644 --- a/web/pdf_rendering_queue.js +++ b/web/pdf_rendering_queue.js @@ -26,7 +26,14 @@ var RenderingStates = { FINISHED: 3 }; +/** + * Controls rendering of the views for pages and thumbnails. + * @class + */ var PDFRenderingQueue = (function PDFRenderingQueueClosure() { + /** + * @constructs + */ function PDFRenderingQueue() { this.pdfViewer = null; this.pdfThumbnailViewer = null; @@ -38,16 +45,26 @@ var PDFRenderingQueue = (function PDFRenderingQueueClosure() { this.isThumbnailViewEnabled = false; } - PDFRenderingQueue.prototype = { + PDFRenderingQueue.prototype = /** @lends PDFRenderingQueue.prototype */ { + /** + * @param {PDFViewer} pdfViewer + */ setViewer: function PDFRenderingQueue_setViewer(pdfViewer) { this.pdfViewer = pdfViewer; }, + /** + * @param {PDFThumbnailViewer} pdfThumbnailViewer + */ setThumbnailViewer: function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) { this.pdfThumbnailViewer = pdfThumbnailViewer; }, + /** + * @param {IRenderableView} view + * @returns {boolean} + */ isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) { return this.highestPriorityPage === view.renderingId; }, @@ -120,13 +137,20 @@ var PDFRenderingQueue = (function PDFRenderingQueueClosure() { return null; }, + /** + * @param {IRenderableView} view + * @returns {boolean} + */ 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. + /** + * 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: function PDFRenderingQueue_renderView(view) { var state = view.renderingState; switch (state) { diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 9bbba0931..25c882586 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -34,7 +34,26 @@ var IGNORE_CURRENT_POSITION_ON_ZOOM = false; //#include page_view.js //#include text_layer_builder.js +/** + * @typedef {Object} PDFViewerOptions + * @property {HTMLDivElement} container - The container for the viewer element. + * @property {HTMLDivElement} viewer - (optional) The viewer element. + * @property {IPDFLinkService} linkService - The navigation/linking service. + * @property {PDFRenderingQueue} renderingQueue - (optional) The rendering + * queue object. + */ + +/** + * Simple viewer control to display PDF content/pages. + * @class + * @implements {ILastScrollSource} + * @implements {IRenderableView} + */ var PDFViewer = (function pdfViewer() { + /** + * @constructs PDFViewer + * @param {PDFViewerOptions} options + */ function PDFViewer(options) { this.container = options.container; this.viewer = options.viewer || options.container.firstElementChild; @@ -56,7 +75,7 @@ var PDFViewer = (function pdfViewer() { this._resetView(); } - PDFViewer.prototype = { + PDFViewer.prototype = /** @lends PDFViewer.prototype */{ get pagesCount() { return this.pages.length; }, @@ -496,6 +515,12 @@ var PDFViewer = (function pdfViewer() { }); }, + /** + * @param textLayerDiv {HTMLDivElement} + * @param pageIndex {number} + * @param viewport {PageViewport} + * @returns {TextLayerBuilder} + */ createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) { var isViewerInPresentationMode = this.presentationModeState === PresentationModeState.FULLSCREEN; @@ -517,13 +542,26 @@ var PDFViewer = (function pdfViewer() { return PDFViewer; })(); +/** + * PDFPage object source. + * @class + */ var PDFPageSource = (function PDFPageSourceClosure() { + /** + * @constructs + * @param {PDFDocument} pdfDocument + * @param {number} pageNumber + * @constructor + */ function PDFPageSource(pdfDocument, pageNumber) { this.pdfDocument = pdfDocument; this.pageNumber = pageNumber; } - PDFPageSource.prototype = { + PDFPageSource.prototype = /** @lends PDFPageSource.prototype */ { + /** + * @returns {Promise} + */ getPage: function () { return this.pdfDocument.getPage(this.pageNumber); } diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js index bc27bb81b..5fac1c493 100644 --- a/web/text_layer_builder.js +++ b/web/text_layer_builder.js @@ -28,11 +28,23 @@ function isAllWhitespace(str) { return !NonWhitespaceRegexp.test(str); } +/** + * @typedef {Object} TextLayerBuilderOptions + * @property {HTMLDivElement} textLayerDiv - The text layer container. + * @property {number} pageIndex - The page index. + * @property {PageViewport} viewport - The viewport of the text layer. + * @property {ILastScrollSource} lastScrollSource - The object that records when + * last time scroll happened. + * @property {boolean} isViewerInPresentationMode + * @property {PDFFindController} findController + */ + /** * TextLayerBuilder provides text-selection functionality for the PDF. * It does this by creating overlay divs over the PDF text. These divs * contain text that matches the PDF text they are overlaying. This object * also provides a way to highlight text that is being searched for. + * @class */ var TextLayerBuilder = (function TextLayerBuilderClosure() { function TextLayerBuilder(options) { diff --git a/web/thumbnail_view.js b/web/thumbnail_view.js index 205e31fd6..1e16a7de4 100644 --- a/web/thumbnail_view.js +++ b/web/thumbnail_view.js @@ -21,6 +21,17 @@ var THUMBNAIL_SCROLL_MARGIN = -19; +/** + * @constructor + * @param container + * @param id + * @param defaultViewport + * @param linkService + * @param renderingQueue + * @param pageSource + * + * @implements {IRenderableView} + */ var ThumbnailView = function thumbnailView(container, id, defaultViewport, linkService, renderingQueue, pageSource) { @@ -241,7 +252,22 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport, ThumbnailView.tempImageCache = null; +/** + * @typedef {Object} PDFThumbnailViewerOptions + * @property {HTMLDivElement} container - The container for the thumbs elements. + * @property {IPDFLinkService} linkService - The navigation/linking service. + * @property {PDFRenderingQueue} renderingQueue - The rendering queue object. + */ + +/** + * Simple viewer control to display thumbs for pages. + * @class + */ var PDFThumbnailViewer = (function pdfThumbnailViewer() { + /** + * @constructs + * @param {PDFThumbnailViewerOptions} options + */ function PDFThumbnailViewer(options) { this.container = options.container; this.renderingQueue = options.renderingQueue; diff --git a/web/viewer.js b/web/viewer.js index 99f277a57..ac8810472 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -92,8 +92,11 @@ var PDFView = { pdfDocument: null, sidebarOpen: false, printing: false, + /** @type {PDFViewer} */ pdfViewer: null, + /** @type {PDFThumbnailViewer} */ pdfThumbnailViewer: null, + /** @type {PDFRenderingQueue} */ pdfRenderingQueue: null, pageRotation: 0, updateScaleControls: true, From 44779f14b039552a07bf4e4f7e47accae58c5a5a Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 22 Sep 2014 06:41:17 -0500 Subject: [PATCH 11/11] Renames and refactors PDFView to PDFViewerApplication. --- web/chromecom.js | 12 +- web/document_attachments_view.js | 10 +- web/document_outline_view.js | 15 +- web/document_properties.js | 12 +- web/interfaces.js | 4 + web/pdf_history.js | 24 +-- web/presentation_mode.js | 22 +-- web/secondary_toolbar.js | 14 +- web/viewer.js | 305 ++++++++++++++++++------------- 9 files changed, 232 insertions(+), 186 deletions(-) diff --git a/web/chromecom.js b/web/chromecom.js index f1739860b..5fe69fef2 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -14,7 +14,7 @@ * limitations under the License. */ -/* globals chrome, PDFJS, PDFView */ +/* globals chrome, PDFJS, PDFViewerApplication */ 'use strict'; var ChromeCom = (function ChromeComClosure() { @@ -64,10 +64,10 @@ var ChromeCom = (function ChromeComClosure() { var streamUrl = response.streamUrl; if (streamUrl) { console.log('Found data stream for ' + file); - PDFView.open(streamUrl, 0, undefined, undefined, { + PDFViewerApplication.open(streamUrl, 0, undefined, undefined, { length: response.contentLength }); - PDFView.setTitleUsingUrl(file); + PDFViewerApplication.setTitleUsingUrl(file); return; } if (isFTPFile && !response.extensionSupportsFTP) { @@ -91,7 +91,7 @@ var ChromeCom = (function ChromeComClosure() { resolveLocalFileSystemURL(file, function onResolvedFSURL(fileEntry) { fileEntry.file(function(fileObject) { var blobUrl = URL.createObjectURL(fileObject); - PDFView.open(blobUrl, 0, undefined, undefined, { + PDFViewerApplication.open(blobUrl, 0, undefined, undefined, { length: fileObject.size }); }); @@ -100,11 +100,11 @@ var ChromeCom = (function ChromeComClosure() { // usual way of getting the File's data (via the Web worker). console.warn('Cannot resolve file ' + file + ', ' + error.name + ' ' + error.message); - PDFView.open(file, 0); + PDFViewerApplication.open(file, 0); }); return; } - PDFView.open(file, 0); + PDFViewerApplication.open(file, 0); }); }; return ChromeCom; diff --git a/web/document_attachments_view.js b/web/document_attachments_view.js index c8477dced..fd015040c 100644 --- a/web/document_attachments_view.js +++ b/web/document_attachments_view.js @@ -14,20 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, DownloadManager, getFileName */ +/* globals DownloadManager, getFileName */ 'use strict'; -var DocumentAttachmentsView = function documentAttachmentsView(attachments) { - var attachmentsView = document.getElementById('attachmentsView'); +var DocumentAttachmentsView = function documentAttachmentsView(options) { + var attachments = options.attachments; + var attachmentsView = options.attachmentsView; while (attachmentsView.firstChild) { attachmentsView.removeChild(attachmentsView.firstChild); } if (!attachments) { - if (!attachmentsView.classList.contains('hidden')) { - PDFView.switchSidebarView('thumbs'); - } return; } diff --git a/web/document_outline_view.js b/web/document_outline_view.js index 74dbe3fb4..5a3ccd315 100644 --- a/web/document_outline_view.js +++ b/web/document_outline_view.js @@ -14,27 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView */ 'use strict'; -var DocumentOutlineView = function documentOutlineView(outline) { - var outlineView = document.getElementById('outlineView'); +var DocumentOutlineView = function documentOutlineView(options) { + var outline = options.outline; + var outlineView = options.outlineView; while (outlineView.firstChild) { outlineView.removeChild(outlineView.firstChild); } if (!outline) { - if (!outlineView.classList.contains('hidden')) { - PDFView.switchSidebarView('thumbs'); - } return; } + var linkService = options.linkService; + function bindItemLink(domObj, item) { - domObj.href = PDFView.getDestinationHash(item.dest); + domObj.href = linkService.getDestinationHash(item.dest); domObj.onclick = function documentOutlineViewOnclick(e) { - PDFView.navigateTo(item.dest); + linkService.navigateTo(item.dest); return false; }; } diff --git a/web/document_properties.js b/web/document_properties.js index c718cc575..b8d30aa05 100644 --- a/web/document_properties.js +++ b/web/document_properties.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ +/* globals Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ 'use strict'; @@ -35,6 +35,8 @@ var DocumentProperties = { producerField: null, versionField: null, pageCountField: null, + url: null, + pdfDocument: null, initialize: function documentPropertiesInitialize(options) { this.overlayName = options.overlayName; @@ -72,7 +74,7 @@ var DocumentProperties = { return; } // Get the file size (if it hasn't already been set). - PDFView.pdfDocument.getDownloadInfo().then(function(data) { + this.pdfDocument.getDownloadInfo().then(function(data) { if (data.length === this.rawFileSize) { return; } @@ -81,10 +83,10 @@ var DocumentProperties = { }.bind(this)); // Get the document properties. - PDFView.pdfDocument.getMetadata().then(function(data) { + this.pdfDocument.getMetadata().then(function(data) { var fields = [ { field: this.fileNameField, - content: getPDFFileNameFromURL(PDFView.url) }, + content: getPDFFileNameFromURL(this.url) }, { field: this.fileSizeField, content: this.parseFileSize() }, { field: this.titleField, content: data.info.Title }, { field: this.authorField, content: data.info.Author }, @@ -97,7 +99,7 @@ var DocumentProperties = { { field: this.creatorField, content: data.info.Creator }, { field: this.producerField, content: data.info.Producer }, { field: this.versionField, content: data.info.PDFFormatVersion }, - { field: this.pageCountField, content: PDFView.pdfDocument.numPages } + { field: this.pageCountField, content: this.pdfDocument.numPages } ]; // Show the properties in the dialog. diff --git a/web/interfaces.js b/web/interfaces.js index 1c60f9882..54c2825f0 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -43,6 +43,10 @@ IPDFLinkService.prototype = { * @returns {string} The hyperlink to the PDF object. */ getAnchorUrl: function (hash) {}, + /** + * @param {string} hash + */ + setHash: function (hash) {}, }; /** diff --git a/web/pdf_history.js b/web/pdf_history.js index 79161da25..e15e03a66 100644 --- a/web/pdf_history.js +++ b/web/pdf_history.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFJS, PDFView, PresentationMode */ +/* globals PDFJS, PresentationMode */ 'use strict'; @@ -22,12 +22,11 @@ var PDFHistory = { initialized: false, initialDestination: null, - initialize: function pdfHistoryInitialize(fingerprint) { - if (PDFJS.disableHistory || PDFView.isViewerEmbedded) { - // The browsing history is only enabled when the viewer is standalone, - // i.e. not when it is embedded in a web page. - return; - } + /** + * @param {string} fingerprint + * @param {IPDFLinkService} linkService + */ + initialize: function pdfHistoryInitialize(fingerprint, linkService) { this.initialized = true; this.reInitialized = false; this.allowHashChange = true; @@ -42,6 +41,7 @@ var PDFHistory = { this.nextHashParam = ''; this.fingerprint = fingerprint; + this.linkService = linkService; this.currentUid = this.uid = 0; this.current = {}; @@ -52,7 +52,7 @@ var PDFHistory = { if (state.target.dest) { this.initialDestination = state.target.dest; } else { - PDFView.initialBookmark = state.target.hash; + linkService.setHash(state.target.hash); } this.currentUid = state.uid; this.uid = state.uid + 1; @@ -203,7 +203,7 @@ var PDFHistory = { params.hash = (this.current.hash && this.current.dest && this.current.dest === params.dest) ? this.current.hash : - PDFView.getDestinationHash(params.dest).split('#')[1]; + this.linkService.getDestinationHash(params.dest).split('#')[1]; } if (params.page) { params.page |= 0; @@ -212,7 +212,7 @@ var PDFHistory = { var target = window.history.state.target; if (!target) { // Invoked when the user specifies an initial bookmark, - // thus setting PDFView.initialBookmark, when the document is loaded. + // thus setting initialBookmark, when the document is loaded. this._pushToHistory(params, false); this.previousHash = window.location.hash.substring(1); } @@ -337,9 +337,9 @@ var PDFHistory = { this.historyUnlocked = false; if (state.target.dest) { - PDFView.navigateTo(state.target.dest); + this.linkService.navigateTo(state.target.dest); } else { - PDFView.setHash(state.target.hash); + this.linkService.setHash(state.target.hash); } this.currentUid = state.uid; if (state.uid > this.uid) { diff --git a/web/presentation_mode.js b/web/presentation_mode.js index ee4e78157..5d72e7c43 100644 --- a/web/presentation_mode.js +++ b/web/presentation_mode.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, scrollIntoView, HandTool */ +/* globals scrollIntoView, HandTool, PDFViewerApplication */ 'use strict'; @@ -93,7 +93,7 @@ var PresentationMode = { }, request: function presentationModeRequest() { - if (!PDFView.supportsFullscreen || this.isFullscreen || + if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen || !this.viewer.hasChildNodes()) { return false; } @@ -113,8 +113,8 @@ var PresentationMode = { } this.args = { - page: PDFView.page, - previousScale: PDFView.currentScaleValue + page: PDFViewerApplication.page, + previousScale: PDFViewerApplication.currentScaleValue }; return true; @@ -138,8 +138,8 @@ var PresentationMode = { // Presentation Mode, by waiting until fullscreen mode in enabled. // Note: This is only necessary in non-Mozilla browsers. setTimeout(function enterPresentationModeTimeout() { - PDFView.page = this.args.page; - PDFView.setScale('page-fit', true); + PDFViewerApplication.page = this.args.page; + PDFViewerApplication.setScale('page-fit', true); }.bind(this), 0); window.addEventListener('mousemove', this.mouseMove, false); @@ -153,7 +153,7 @@ var PresentationMode = { }, exit: function presentationModeExit() { - var page = PDFView.page; + var page = PDFViewerApplication.page; // Ensure that the correct page is scrolled into view when exiting // Presentation Mode, by waiting until fullscreen mode is disabled. @@ -162,8 +162,8 @@ var PresentationMode = { this.active = false; this._notifyStateChange(); - PDFView.setScale(this.args.previousScale, true); - PDFView.page = page; + PDFViewerApplication.setScale(this.args.previousScale, true); + PDFViewerApplication.page = page; this.args = null; }.bind(this), 0); @@ -172,7 +172,7 @@ var PresentationMode = { window.removeEventListener('contextmenu', this.contextMenu, false); this.hideControls(); - PDFView.clearMouseScrollState(); + PDFViewerApplication.clearMouseScrollState(); HandTool.exitPresentationMode(); this.container.removeAttribute('contextmenu'); this.contextMenuOpen = false; @@ -236,7 +236,7 @@ var PresentationMode = { if (!isInternalLink) { // Unless an internal link was clicked, advance one page. evt.preventDefault(); - PDFView.page += (evt.shiftKey ? -1 : 1); + PDFViewerApplication.page += (evt.shiftKey ? -1 : 1); } } }, diff --git a/web/secondary_toolbar.js b/web/secondary_toolbar.js index 7b6b5858c..7c94b3185 100644 --- a/web/secondary_toolbar.js +++ b/web/secondary_toolbar.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, SCROLLBAR_PADDING */ +/* globals PDFViewerApplication, SCROLLBAR_PADDING */ 'use strict'; @@ -87,7 +87,7 @@ var SecondaryToolbar = { }, downloadClick: function secondaryToolbarDownloadClick(evt) { - PDFView.download(); + PDFViewerApplication.download(); this.close(); }, @@ -96,23 +96,23 @@ var SecondaryToolbar = { }, firstPageClick: function secondaryToolbarFirstPageClick(evt) { - PDFView.page = 1; + PDFViewerApplication.page = 1; this.close(); }, lastPageClick: function secondaryToolbarLastPageClick(evt) { - if (PDFView.pdfDocument) { - PDFView.page = PDFView.pdfDocument.numPages; + if (PDFViewerApplication.pdfDocument) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; } this.close(); }, pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) { - PDFView.rotatePages(90); + PDFViewerApplication.rotatePages(90); }, pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) { - PDFView.rotatePages(-90); + PDFViewerApplication.rotatePages(-90); }, documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) { diff --git a/web/viewer.js b/web/viewer.js index ac8810472..80b8a532a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -85,7 +85,7 @@ var mozL10n = document.mozL10n || document.webL10n; //#include document_properties.js //#include pdf_viewer.js -var PDFView = { +var PDFViewerApplication = { initialBookmark: document.location.hash.substring(1), initialized: false, fellback: false, @@ -100,6 +100,8 @@ var PDFView = { pdfRenderingQueue: null, pageRotation: 0, updateScaleControls: true, + isInitialViewSet: false, + animationStartedPromise: null, mouseScrollTimeStamp: 0, mouseScrollDelta: 0, isViewerEmbedded: (window.parent !== window), @@ -247,7 +249,7 @@ var PDFView = { ]).catch(function (reason) { }); return initializedPromise.then(function () { - PDFView.initialized = true; + PDFViewerApplication.initialized = true; }); }, @@ -418,7 +420,8 @@ var PDFView = { } switch (args.pdfjsLoadAction) { case 'supportsRangedLoading': - PDFView.open(args.pdfUrl, 0, undefined, pdfDataRangeTransport, { + PDFViewerApplication.open(args.pdfUrl, 0, undefined, + pdfDataRangeTransport, { length: args.length, initialData: args.data }); @@ -430,15 +433,15 @@ var PDFView = { pdfDataRangeTransport.onDataProgress(args.loaded); break; case 'progress': - PDFView.progress(args.loaded / args.total); + PDFViewerApplication.progress(args.loaded / args.total); break; case 'complete': if (!args.data) { - PDFView.error(mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'), e); + PDFViewerApplication.error(mozL10n.get('loading_error', null, + 'An error occurred while loading the PDF.'), e); break; } - PDFView.open(args.data, 0); + PDFViewerApplication.open(args.data, 0); break; } }); @@ -574,7 +577,7 @@ var PDFView = { downloadManager.onerror = function (err) { // This error won't really be helpful because it's likely the // fallback won't work either (or is already open). - PDFView.error('PDF failed to download.'); + PDFViewerApplication.error('PDF failed to download.'); }; if (!this.pdfDocument) { // the PDF is not ready yet @@ -611,7 +614,7 @@ var PDFView = { // if (!download) { // return; // } -// PDFView.download(); +// PDFViewerApplication.download(); // }); //#endif }, @@ -672,25 +675,25 @@ var PDFView = { break; case 'Find': - if (!PDFView.supportsIntegratedFind) { - PDFView.findBar.toggle(); + if (!this.supportsIntegratedFind) { + this.findBar.toggle(); } break; case 'NextPage': - PDFView.page++; + this.page++; break; case 'PrevPage': - PDFView.page--; + this.page--; break; case 'LastPage': - PDFView.page = PDFView.pagesCount; + this.page = this.pagesCount; break; case 'FirstPage': - PDFView.page = 1; + this.page = 1; break; default: @@ -700,7 +703,7 @@ var PDFView = { getDestinationHash: function pdfViewGetDestinationHash(dest) { if (typeof dest === 'string') { - return PDFView.getAnchorUrl('#' + escape(dest)); + return this.getAnchorUrl('#' + escape(dest)); } if (dest instanceof Array) { var destRef = dest[0]; // see navigateTo method for dest format @@ -708,7 +711,7 @@ var PDFView = { this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1); if (pageNumber) { - var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber); + var pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber); var destKind = dest[1]; if (typeof destKind === 'object' && 'name' in destKind && destKind.name === 'XYZ') { @@ -822,8 +825,8 @@ var PDFView = { // that we discard some of the loaded data. This can cause the loading // bar to move backwards. So prevent this by only updating the bar if it // increases. - if (percent > PDFView.loadingBar.percent || isNaN(percent)) { - PDFView.loadingBar.percent = percent; + if (percent > this.loadingBar.percent || isNaN(percent)) { + this.loadingBar.percent = percent; } }, @@ -831,15 +834,17 @@ var PDFView = { var self = this; scale = scale || UNKNOWN_SCALE; - PDFView.findController.reset(); + this.findController.reset(); this.pdfDocument = pdfDocument; + DocumentProperties.url = this.url; + DocumentProperties.pdfDocument = pdfDocument; DocumentProperties.resolveDataAvailable(); var downloadedPromise = pdfDocument.getDownloadInfo().then(function() { self.downloadComplete = true; - PDFView.loadingBar.hide(); + self.loadingBar.hide(); var outerContainer = document.getElementById('outerContainer'); outerContainer.classList.remove('loadingInProgress'); }); @@ -851,8 +856,8 @@ var PDFView = { mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}'); document.getElementById('pageNumber').max = pagesCount; - PDFView.documentFingerprint = id; - var store = PDFView.store = new ViewHistory(id); + this.documentFingerprint = id; + var store = this.store = new ViewHistory(id); var pdfViewer = this.pdfViewer; pdfViewer.currentScale = scale; @@ -862,6 +867,7 @@ var PDFView = { var onePageRendered = pdfViewer.onePageRendered; this.pageRotation = 0; + this.isInitialViewSet = false; this.pagesRefMap = pdfViewer.pagesRefMap; this.pdfThumbnailViewer.setDocument(pdfDocument); @@ -873,12 +879,15 @@ var PDFView = { window.dispatchEvent(event); }); - PDFView.loadingBar.setWidth(document.getElementById('viewer')); + self.loadingBar.setWidth(document.getElementById('viewer')); - PDFView.findController.resolveFirstPage(); + self.findController.resolveFirstPage(); - // Initialize the browsing history. - PDFHistory.initialize(self.documentFingerprint); + if (!PDFJS.disableHistory && !self.isViewerEmbedded) { + // The browsing history is only enabled when the viewer is standalone, + // i.e. not when it is embedded in a web page. + PDFHistory.initialize(self.documentFingerprint, self); + } }); // Fetch the necessary preference values. @@ -900,7 +909,7 @@ var PDFView = { if (showPreviousViewOnLoad && store.get('exists', false)) { var pageNum = store.get('page', '1'); var zoom = defaultZoomValue || - store.get('zoom', PDFView.pdfViewer.currentScale); + store.get('zoom', self.pdfViewer.currentScale); var left = store.get('scrollLeft', '0'); var top = store.get('scrollTop', '0'); @@ -928,11 +937,11 @@ var PDFView = { }); pagesPromise.then(function() { - if (PDFView.supportsPrinting) { + if (self.supportsPrinting) { pdfDocument.getJavaScript().then(function(javaScript) { if (javaScript.length) { console.warn('Warning: JavaScript is not supported'); - PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript); + self.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript); } // Hack to support auto printing. var regex = /\bprint\s*\(/g; @@ -957,21 +966,36 @@ var PDFView = { // outline depends on destinations and pagesRefMap var promises = [pagesPromise, destinationsPromise, - PDFView.animationStartedPromise]; + this.animationStartedPromise]; Promise.all(promises).then(function() { pdfDocument.getOutline().then(function(outline) { - self.outline = new DocumentOutlineView(outline); + var outlineView = document.getElementById('outlineView'); + self.outline = new DocumentOutlineView({ + outline: outline, + outlineView: outlineView, + linkService: self + }); document.getElementById('viewOutline').disabled = !outline; + if (!outline && !outlineView.classList.contains('hidden')) { + self.switchSidebarView('thumbs'); + } if (outline && self.preferenceSidebarViewOnLoad === SidebarView.OUTLINE) { self.switchSidebarView('outline', true); } }); pdfDocument.getAttachments().then(function(attachments) { - self.attachments = new DocumentAttachmentsView(attachments); + var attachmentsView = document.getElementById('attachmentsView'); + self.attachments = new DocumentAttachmentsView({ + attachments: attachments, + attachmentsView: attachmentsView + }); document.getElementById('viewAttachments').disabled = !attachments; + if (!attachments && !attachmentsView.classList.contains('hidden')) { + self.switchSidebarView('thumbs'); + } if (attachments && self.preferenceSidebarViewOnLoad === SidebarView.ATTACHMENTS) { self.switchSidebarView('attachments', true); @@ -1016,7 +1040,7 @@ var PDFView = { if (info.IsAcroFormPresent) { console.warn('Warning: AcroForm/XFA is not supported'); - PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.forms); + self.fallback(PDFJS.UNSUPPORTED_FEATURES.forms); } //#if (FIREFOX || MOZCENTRAL) @@ -1050,6 +1074,8 @@ var PDFView = { }, setInitialView: function pdfViewSetInitialView(storedHash, scale) { + this.isInitialViewSet = true; + // When opening a new file (when one is already loaded in the viewer): // Reset 'currentPageNumber', since otherwise the page's scale will be wrong // if 'currentPageNumber' is larger than the number of pages in the file. @@ -1070,7 +1096,7 @@ var PDFView = { this.page = 1; } - if (PDFView.pdfViewer.currentScale === UNKNOWN_SCALE) { + if (this.pdfViewer.currentScale === UNKNOWN_SCALE) { // Scale was not initialized: invalid bookmark or scale was not specified. // Setting the default one. this.setScale(DEFAULT_SCALE, true); @@ -1090,6 +1116,11 @@ var PDFView = { }, setHash: function pdfViewSetHash(hash) { + if (!this.isInitialViewSet) { + this.initialBookmark = hash; + return; + } + var validFitZoomValues = ['Fit','FitB','FitH','FitBH', 'FitV','FitBV','FitR']; @@ -1098,11 +1129,11 @@ var PDFView = { } if (hash.indexOf('=') >= 0) { - var params = PDFView.parseQueryString(hash); + var params = this.parseQueryString(hash); // borrowing syntax from "Parameters for Opening PDF Files" if ('nameddest' in params) { PDFHistory.updateNextHashParam(params.nameddest); - PDFView.navigateTo(params.nameddest); + this.navigateTo(params.nameddest); return; } var pageNumber, dest; @@ -1147,7 +1178,7 @@ var PDFView = { this.page = hash; } else { // named destination PDFHistory.updateNextHashParam(unescape(hash)); - PDFView.navigateTo(unescape(hash)); + this.navigateTo(unescape(hash)); } }, @@ -1174,7 +1205,7 @@ var PDFView = { outlineView.classList.add('hidden'); attachmentsView.classList.add('hidden'); - PDFView.forceRendering(); + this.forceRendering(); if (wasAnotherViewVisible) { this.pdfThumbnailViewer.ensureThumbnailVisible(this.page); @@ -1363,6 +1394,9 @@ var PDFView = { this.mouseScrollDelta = 0; } }; +//#if GENERIC +window.PDFView = PDFViewerApplication; // obsolete name, using it as an alias +//#endif //#include thumbnail_view.js //#include document_outline_view.js @@ -1372,7 +1406,8 @@ var PDFView = { //(function rewriteUrlClosure() { // // Run this code outside DOMContentLoaded to make sure that the URL // // is rewritten as soon as possible. -// var params = PDFView.parseQueryString(document.location.search.slice(1)); +// var queryString = document.location.search.slice(1); +// var params = PDFViewerApplication.parseQueryString(queryString); // DEFAULT_URL = params.file || ''; // // // Example: chrome-extension://.../http://example.com/file.pdf @@ -1385,12 +1420,13 @@ var PDFView = { //#endif function webViewerLoad(evt) { - PDFView.initialize().then(webViewerInitialized); + PDFViewerApplication.initialize().then(webViewerInitialized); } function webViewerInitialized() { //#if (GENERIC || B2G) - var params = PDFView.parseQueryString(document.location.search.substring(1)); + var queryString = document.location.search.substring(1); + var params = PDFViewerApplication.parseQueryString(queryString); var file = 'file' in params ? params.file : DEFAULT_URL; //#endif //#if (FIREFOX || MOZCENTRAL) @@ -1426,11 +1462,11 @@ function webViewerInitialized() { //#if !PRODUCTION if (true) { //#else -//if (PDFView.preferencesPdfBugEnabled) { +//if (PDFViewerApplication.preferencesPdfBugEnabled) { //#endif // Special debugging flags in the hash section of the URL. var hash = document.location.hash.substring(1); - var hashParams = PDFView.parseQueryString(hash); + var hashParams = PDFViewerApplication.parseQueryString(hash); if ('disableworker' in hashParams) { PDFJS.disableWorker = (hashParams['disableworker'] === 'true'); @@ -1497,30 +1533,31 @@ function webViewerInitialized() { mozL10n.setLanguage(locale); //#endif //#if (FIREFOX || MOZCENTRAL) -//if (!PDFView.supportsDocumentFonts) { +//if (!PDFViewerApplication.supportsDocumentFonts) { // PDFJS.disableFontFace = true; // console.warn(mozL10n.get('web_fonts_disabled', null, // 'Web fonts are disabled: unable to use embedded PDF fonts.')); //} //#endif - if (!PDFView.supportsPrinting) { + if (!PDFViewerApplication.supportsPrinting) { document.getElementById('print').classList.add('hidden'); document.getElementById('secondaryPrint').classList.add('hidden'); } - if (!PDFView.supportsFullscreen) { + if (!PDFViewerApplication.supportsFullscreen) { document.getElementById('presentationMode').classList.add('hidden'); document.getElementById('secondaryPresentationMode'). classList.add('hidden'); } - if (PDFView.supportsIntegratedFind) { + if (PDFViewerApplication.supportsIntegratedFind) { document.getElementById('viewFind').classList.add('hidden'); } // Listen for unsupported features to trigger the fallback UI. - PDFJS.UnsupportedManager.listen(PDFView.fallback.bind(PDFView)); + PDFJS.UnsupportedManager.listen( + PDFViewerApplication.fallback.bind(PDFViewerApplication)); // Suppress context menus for some controls document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler; @@ -1541,43 +1578,44 @@ function webViewerInitialized() { this.classList.toggle('toggled'); outerContainer.classList.add('sidebarMoving'); outerContainer.classList.toggle('sidebarOpen'); - PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen'); - PDFView.forceRendering(); + PDFViewerApplication.sidebarOpen = + outerContainer.classList.contains('sidebarOpen'); + PDFViewerApplication.forceRendering(); }); document.getElementById('viewThumbnail').addEventListener('click', function() { - PDFView.switchSidebarView('thumbs'); + PDFViewerApplication.switchSidebarView('thumbs'); }); document.getElementById('viewOutline').addEventListener('click', function() { - PDFView.switchSidebarView('outline'); + PDFViewerApplication.switchSidebarView('outline'); }); document.getElementById('viewAttachments').addEventListener('click', function() { - PDFView.switchSidebarView('attachments'); + PDFViewerApplication.switchSidebarView('attachments'); }); document.getElementById('previous').addEventListener('click', function() { - PDFView.page--; + PDFViewerApplication.page--; }); document.getElementById('next').addEventListener('click', function() { - PDFView.page++; + PDFViewerApplication.page++; }); document.getElementById('zoomIn').addEventListener('click', function() { - PDFView.zoomIn(); + PDFViewerApplication.zoomIn(); }); document.getElementById('zoomOut').addEventListener('click', function() { - PDFView.zoomOut(); + PDFViewerApplication.zoomOut(); }); document.getElementById('pageNumber').addEventListener('click', @@ -1588,16 +1626,16 @@ function webViewerInitialized() { document.getElementById('pageNumber').addEventListener('change', function() { // Handle the user inputting a floating point number. - PDFView.page = (this.value | 0); + PDFViewerApplication.page = (this.value | 0); if (this.value !== (this.value | 0).toString()) { - this.value = PDFView.page; + this.value = PDFViewerApplication.page; } }); document.getElementById('scaleSelect').addEventListener('change', function() { - PDFView.setScale(this.value, false); + PDFViewerApplication.setScale(this.value, false); }); document.getElementById('presentationMode').addEventListener('click', @@ -1613,8 +1651,8 @@ function webViewerInitialized() { SecondaryToolbar.downloadClick.bind(SecondaryToolbar)); //#if (FIREFOX || MOZCENTRAL) -//PDFView.setTitleUsingUrl(file); -//PDFView.initPassiveLoading(); +//PDFViewerApplication.setTitleUsingUrl(file); +//PDFViewerApplication.initPassiveLoading(); //return; //#endif @@ -1623,18 +1661,18 @@ function webViewerInitialized() { // file:-scheme. Load the contents in the main thread because QtWebKit // cannot load file:-URLs in a Web Worker. file:-URLs are usually loaded // very quickly, so there is no need to set up progress event listeners. - PDFView.setTitleUsingUrl(file); + PDFViewerApplication.setTitleUsingUrl(file); var xhr = new XMLHttpRequest(); xhr.onload = function() { - PDFView.open(new Uint8Array(xhr.response), 0); + PDFViewerApplication.open(new Uint8Array(xhr.response), 0); }; try { xhr.open('GET', file); xhr.responseType = 'arraybuffer'; xhr.send(); } catch (e) { - PDFView.error(mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'), e); + PDFViewerApplication.error(mozL10n.get('loading_error', null, + 'An error occurred while loading the PDF.'), e); } return; } @@ -1642,7 +1680,7 @@ function webViewerInitialized() { //#if !B2G && !CHROME if (file) { - PDFView.open(file, 0); + PDFViewerApplication.open(file, 0); } //#endif //#if CHROME @@ -1656,24 +1694,25 @@ document.addEventListener('DOMContentLoaded', webViewerLoad, true); document.addEventListener('pagerendered', function (e) { var pageIndex = e.detail.pageNumber - 1; - var pageView = PDFView.pdfViewer.getPageView(pageIndex); - var thumbnailView = PDFView.pdfThumbnailViewer.getThumbnail(pageIndex); + var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex); + var thumbnailView = PDFViewerApplication.pdfThumbnailViewer. + getThumbnail(pageIndex); thumbnailView.setImage(pageView.canvas); //#if (FIREFOX || MOZCENTRAL) //if (pageView.textLayer && pageView.textLayer.textDivs && // pageView.textLayer.textDivs.length > 0 && -// !PDFView.supportsDocumentColors) { +// !PDFViewerApplication.supportsDocumentColors) { // console.error(mozL10n.get('document_colors_disabled', null, // 'PDF documents are not allowed to use their own colors: ' + // '\'Allow pages to choose their own colors\' ' + // 'is deactivated in the browser.')); -// PDFView.fallback(); +// PDFViewerApplication.fallback(); //} //#endif if (pageView.error) { - PDFView.error(mozL10n.get('rendering_error', null, + PDFViewerApplication.error(mozL10n.get('rendering_error', null, 'An error occurred while rendering the page.'), pageView.error); } @@ -1682,7 +1721,7 @@ document.addEventListener('pagerendered', function (e) { // type: 'pageInfo' //})); //// It is a good time to report stream and font types -//PDFView.pdfDocument.getStats().then(function (stats) { +//PDFViewerApplication.pdfDocument.getStats().then(function (stats) { // FirefoxCom.request('reportTelemetry', JSON.stringify({ // type: 'documentStats', // stats: stats @@ -1694,27 +1733,27 @@ document.addEventListener('pagerendered', function (e) { window.addEventListener('presentationmodechanged', function (e) { var active = e.detail.active; var switchInProgress = e.detail.switchInProgress; - PDFView.pdfViewer.presentationModeState = + PDFViewerApplication.pdfViewer.presentationModeState = switchInProgress ? PresentationModeState.CHANGING : active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL; }); function updateViewarea() { - if (!PDFView.initialized) { + if (!PDFViewerApplication.initialized) { return; } - PDFView.pdfViewer.update(); + PDFViewerApplication.pdfViewer.update(); } window.addEventListener('updateviewarea', function () { - if (!PDFView.initialized) { + if (!PDFViewerApplication.initialized) { return; } - var location = PDFView.pdfViewer.location; + var location = PDFViewerApplication.pdfViewer.location; - PDFView.store.initializedPromise.then(function() { - PDFView.store.setMultiple({ + PDFViewerApplication.store.initializedPromise.then(function() { + PDFViewerApplication.store.setMultiple({ 'exists': true, 'page': location.pageNumber, 'zoom': location.scale, @@ -1724,7 +1763,7 @@ window.addEventListener('updateviewarea', function () { // unable to write to storage }); }); - var href = PDFView.getAnchorUrl(location.pdfOpenParams); + var href = PDFViewerApplication.getAnchorUrl(location.pdfOpenParams); document.getElementById('viewBookmark').href = href; document.getElementById('secondaryViewBookmark').href = href; @@ -1733,11 +1772,12 @@ window.addEventListener('updateviewarea', function () { }, true); window.addEventListener('resize', function webViewerResize(evt) { - if (PDFView.initialized && + if (PDFViewerApplication.initialized && (document.getElementById('pageWidthOption').selected || document.getElementById('pageFitOption').selected || document.getElementById('pageAutoOption').selected)) { - PDFView.setScale(document.getElementById('scaleSelect').value, false); + var selectedScale = document.getElementById('scaleSelect').value; + PDFViewerApplication.setScale(selectedScale, false); } updateViewarea(); @@ -1747,7 +1787,7 @@ window.addEventListener('resize', function webViewerResize(evt) { window.addEventListener('hashchange', function webViewerHashchange(evt) { if (PDFHistory.isHashChangeUnlocked) { - PDFView.setHash(document.location.hash.substring(1)); + PDFViewerApplication.setHash(document.location.hash.substring(1)); } }); @@ -1761,19 +1801,19 @@ window.addEventListener('change', function webViewerChange(evt) { if (!PDFJS.disableCreateObjectURL && typeof URL !== 'undefined' && URL.createObjectURL) { - PDFView.open(URL.createObjectURL(file), 0); + PDFViewerApplication.open(URL.createObjectURL(file), 0); } else { // Read the local file into a Uint8Array. var fileReader = new FileReader(); fileReader.onload = function webViewerChangeFileReaderOnload(evt) { var buffer = evt.target.result; var uint8Array = new Uint8Array(buffer); - PDFView.open(uint8Array, 0); + PDFViewerApplication.open(uint8Array, 0); }; fileReader.readAsArrayBuffer(file); } - PDFView.setTitleUsingUrl(file.name); + PDFViewerApplication.setTitleUsingUrl(file.name); // URL does not reflect proper document location - hiding some icons. document.getElementById('viewBookmark').setAttribute('hidden', 'true'); @@ -1802,7 +1842,7 @@ function selectScaleOption(value) { window.addEventListener('localized', function localized(evt) { document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); - PDFView.animationStartedPromise.then(function() { + PDFViewerApplication.animationStartedPromise.then(function() { // Adjust the width of the zoom box to fit the content. // Note: If the window is narrow enough that the zoom box is not visible, // we temporarily show it to be able to adjust its width. @@ -1832,7 +1872,7 @@ window.addEventListener('scalechange', function scalechange(evt) { var customScaleOption = document.getElementById('customScaleOption'); customScaleOption.selected = false; - if (!PDFView.updateScaleControls && + if (!PDFViewerApplication.updateScaleControls && (document.getElementById('pageWidthOption').selected || document.getElementById('pageFitOption').selected || document.getElementById('pageAutoOption').selected)) { @@ -1858,9 +1898,9 @@ window.addEventListener('pagechange', function pagechange(evt) { var page = evt.pageNumber; if (evt.previousPageNumber !== page) { document.getElementById('pageNumber').value = page; - PDFView.pdfThumbnailViewer.scrollThumbnailIntoView(page); + PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page); } - var numPages = PDFView.pagesCount; + var numPages = PDFViewerApplication.pagesCount; document.getElementById('previous').disabled = (page <= 1); document.getElementById('next').disabled = (page >= numPages); @@ -1876,7 +1916,7 @@ window.addEventListener('pagechange', function pagechange(evt) { if (this.loading && page === 1) { return; } - PDFView.getPageView(page - 1).scrollIntoView(); + PDFViewerApplication.getPageView(page - 1).scrollIntoView(); }, true); function handleMouseWheel(evt) { @@ -1887,9 +1927,9 @@ function handleMouseWheel(evt) { if (evt.ctrlKey) { // Only zoom the pages, not the entire viewer evt.preventDefault(); - PDFView[direction](Math.abs(ticks)); + PDFViewerApplication[direction](Math.abs(ticks)); } else if (PresentationMode.active) { - PDFView.mouseScroll(ticks * MOUSE_WHEEL_DELTA_FACTOR); + PDFViewerApplication.mouseScroll(ticks * MOUSE_WHEEL_DELTA_FACTOR); } } @@ -1899,7 +1939,7 @@ window.addEventListener('mousewheel', handleMouseWheel); window.addEventListener('click', function click(evt) { if (!PresentationMode.active) { if (SecondaryToolbar.opened && - PDFView.pdfViewer.containsElement(evt.target)) { + PDFViewerApplication.pdfViewer.containsElement(evt.target)) { SecondaryToolbar.close(); } } else if (evt.button === 0) { @@ -1926,14 +1966,15 @@ window.addEventListener('keydown', function keydown(evt) { // either CTRL or META key with optional SHIFT. switch (evt.keyCode) { case 70: // f - if (!PDFView.supportsIntegratedFind) { - PDFView.findBar.open(); + if (!PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.findBar.open(); handled = true; } break; case 71: // g - if (!PDFView.supportsIntegratedFind) { - PDFView.findBar.dispatchEvent('again', cmd === 5 || cmd === 12); + if (!PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.findBar.dispatchEvent('again', + cmd === 5 || cmd === 12); handled = true; } break; @@ -1941,13 +1982,13 @@ window.addEventListener('keydown', function keydown(evt) { case 107: // FF '+' and '=' case 187: // Chrome '+' case 171: // FF with German keyboard - PDFView.zoomIn(); + PDFViewerApplication.zoomIn(); handled = true; break; case 173: // FF/Mac '-' case 109: // FF '-' case 189: // Chrome '-' - PDFView.zoomOut(); + PDFViewerApplication.zoomOut(); handled = true; break; case 48: // '0' @@ -1955,7 +1996,7 @@ window.addEventListener('keydown', function keydown(evt) { // keeping it unhandled (to restore page zoom to 100%) setTimeout(function () { // ... and resetting the scale after browser adjusts its scale - PDFView.setScale(DEFAULT_SCALE, true); + PDFViewerApplication.setScale(DEFAULT_SCALE, true); }); handled = false; break; @@ -1967,7 +2008,7 @@ window.addEventListener('keydown', function keydown(evt) { if (cmd === 1 || cmd === 8) { switch (evt.keyCode) { case 83: // s - PDFView.download(); + PDFViewerApplication.download(); handled = true; break; } @@ -2013,20 +2054,20 @@ window.addEventListener('keydown', function keydown(evt) { case 33: // pg up case 8: // backspace if (!PresentationMode.active && - PDFView.currentScaleValue !== 'page-fit') { + PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } /* in presentation mode */ /* falls through */ case 37: // left arrow // horizontal scrolling using arrow keys - if (PDFView.pdfViewer.isHorizontalScrollbarEnabled) { + if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ case 75: // 'k' case 80: // 'p' - PDFView.page--; + PDFViewerApplication.page--; handled = true; break; case 27: // esc key @@ -2034,8 +2075,9 @@ window.addEventListener('keydown', function keydown(evt) { SecondaryToolbar.close(); handled = true; } - if (!PDFView.supportsIntegratedFind && PDFView.findBar.opened) { - PDFView.findBar.close(); + if (!PDFViewerApplication.supportsIntegratedFind && + PDFViewerApplication.findBar.opened) { + PDFViewerApplication.findBar.close(); handled = true; } break; @@ -2043,32 +2085,32 @@ window.addEventListener('keydown', function keydown(evt) { case 34: // pg down case 32: // spacebar if (!PresentationMode.active && - PDFView.currentScaleValue !== 'page-fit') { + PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } /* falls through */ case 39: // right arrow // horizontal scrolling using arrow keys - if (PDFView.pdfViewer.isHorizontalScrollbarEnabled) { + if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) { break; } /* falls through */ case 74: // 'j' case 78: // 'n' - PDFView.page++; + PDFViewerApplication.page++; handled = true; break; case 36: // home - if (PresentationMode.active || PDFView.page > 1) { - PDFView.page = 1; + if (PresentationMode.active || PDFViewerApplication.page > 1) { + PDFViewerApplication.page = 1; handled = true; } break; case 35: // end - if (PresentationMode.active || (PDFView.pdfDocument && - PDFView.page < PDFView.pagesCount)) { - PDFView.page = PDFView.pagesCount; + if (PresentationMode.active || (PDFViewerApplication.pdfDocument && + PDFViewerApplication.page < PDFViewerApplication.pagesCount)) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; handled = true; } break; @@ -2079,7 +2121,7 @@ window.addEventListener('keydown', function keydown(evt) { } break; case 82: // 'r' - PDFView.rotatePages(90); + PDFViewerApplication.rotatePages(90); break; } } @@ -2088,15 +2130,15 @@ window.addEventListener('keydown', function keydown(evt) { switch (evt.keyCode) { case 32: // spacebar if (!PresentationMode.active && - PDFView.currentScaleValue !== 'page-fit') { + PDFViewerApplication.currentScaleValue !== 'page-fit') { break; } - PDFView.page--; + PDFViewerApplication.page--; handled = true; break; case 82: // 'r' - PDFView.rotatePages(-90); + PDFViewerApplication.rotatePages(-90); break; } } @@ -2105,21 +2147,21 @@ window.addEventListener('keydown', function keydown(evt) { // 33=Page Up 34=Page Down 35=End 36=Home // 37=Left 38=Up 39=Right 40=Down if (evt.keyCode >= 33 && evt.keyCode <= 40 && - !PDFView.pdfViewer.containsElement(curElement)) { + !PDFViewerApplication.pdfViewer.containsElement(curElement)) { // The page container is not focused, but a page navigation key has been // pressed. Change the focus to the viewer container to make sure that // navigation by keyboard works as expected. - PDFView.pdfViewer.focus(); + PDFViewerApplication.pdfViewer.focus(); } // 32=Spacebar if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') { //#if (FIREFOX || MOZCENTRAL) // // Workaround for issue in Firefox, that prevents scroll keys from // // working when elements with 'tabindex' are focused. (#3498) -// PDFView.pdfViewer.blur(); +// PDFViewerApplication.pdfViewer.blur(); //#else - if (!PDFView.pdfViewer.containsElement(curElement)) { - PDFView.pdfViewer.focus(); + if (!PDFViewerApplication.pdfViewer.containsElement(curElement)) { + PDFViewerApplication.pdfViewer.focus(); } //#endif } @@ -2144,22 +2186,23 @@ window.addEventListener('keydown', function keydown(evt) { if (handled) { evt.preventDefault(); - PDFView.clearMouseScrollState(); + PDFViewerApplication.clearMouseScrollState(); } }); window.addEventListener('beforeprint', function beforePrint(evt) { - PDFView.beforePrint(); + PDFViewerApplication.beforePrint(); }); window.addEventListener('afterprint', function afterPrint(evt) { - PDFView.afterPrint(); + PDFViewerApplication.afterPrint(); }); (function animationStartedClosure() { // The offsetParent is not set until the pdf.js iframe or object is visible. // Waiting for first animation. - PDFView.animationStartedPromise = new Promise(function (resolve) { + PDFViewerApplication.animationStartedPromise = new Promise( + function (resolve) { window.requestAnimationFrame(resolve); }); })(); @@ -2171,7 +2214,7 @@ window.addEventListener('afterprint', function afterPrint(evt) { // var fileURL = activity.source.data.url; // // var url = URL.createObjectURL(blob); -// PDFView.open({url : url, originalUrl: fileURL}); +// PDFViewerApplication.open({url : url, originalUrl: fileURL}); // // var header = document.getElementById('header'); // header.addEventListener('action', function() {