From 7642c397342cf4535e22b57c0ba8e5361760fca2 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 15 Sep 2014 09:49:24 -0500 Subject: [PATCH] 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;