From a682d77e71e8d5f0901d190a3d3d674d0df4a55f Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 4 Jun 2017 19:26:57 +0200 Subject: [PATCH 1/2] Convert the thumbnail viewer to ES6 syntax --- web/pdf_thumbnail_viewer.js | 334 ++++++++++++++++++------------------ 1 file changed, 163 insertions(+), 171 deletions(-) diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index 1185371bf..5c2796b58 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -18,7 +18,7 @@ import { } from './ui_utils'; import { PDFThumbnailView } from './pdf_thumbnail_view'; -var THUMBNAIL_SCROLL_MARGIN = -19; +const THUMBNAIL_SCROLL_MARGIN = -19; /** * @typedef {Object} PDFThumbnailViewerOptions @@ -30,201 +30,193 @@ var THUMBNAIL_SCROLL_MARGIN = -19; */ /** - * Simple viewer control to display thumbnails for pages. - * @class + * Viewer control to display thumbnails for pages in a PDF document. + * * @implements {IRenderableView} */ -var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() { +class PDFThumbnailViewer { /** - * @constructs PDFThumbnailViewer * @param {PDFThumbnailViewerOptions} options */ - function PDFThumbnailViewer(options) { - this.container = options.container; - this.renderingQueue = options.renderingQueue; - this.linkService = options.linkService; - this.l10n = options.l10n || NullL10n; + constructor({ container, linkService, renderingQueue, l10n = NullL10n, }) { + this.container = container; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.l10n = l10n; this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this)); this._resetView(); } - PDFThumbnailViewer.prototype = { - /** - * @private - */ - _scrollUpdated: function PDFThumbnailViewer_scrollUpdated() { - this.renderingQueue.renderHighestPriority(); - }, + /** + * @private + */ + _scrollUpdated() { + this.renderingQueue.renderHighestPriority(); + } - getThumbnail: function PDFThumbnailViewer_getThumbnail(index) { - return this.thumbnails[index]; - }, + getThumbnail(index) { + return this._thumbnails[index]; + } - /** - * @private - */ - _getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() { - return getVisibleElements(this.container, this.thumbnails); - }, + /** + * @private + */ + _getVisibleThumbs() { + return getVisibleElements(this.container, this._thumbnails); + } - scrollThumbnailIntoView: - function PDFThumbnailViewer_scrollThumbnailIntoView(page) { - var selected = document.querySelector('.thumbnail.selected'); - if (selected) { - selected.classList.remove('selected'); + scrollThumbnailIntoView(page) { + let selected = document.querySelector('.thumbnail.selected'); + if (selected) { + selected.classList.remove('selected'); + } + let thumbnail = document.querySelector( + 'div.thumbnail[data-page-number="' + page + '"]'); + if (thumbnail) { + thumbnail.classList.add('selected'); + } + let visibleThumbs = this._getVisibleThumbs(); + let numVisibleThumbs = visibleThumbs.views.length; + + // If the thumbnail isn't currently visible, scroll it into view. + if (numVisibleThumbs > 0) { + let first = visibleThumbs.first.id; + // Account for only one thumbnail being visible. + let last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first); + if (page <= first || page >= last) { + scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN, }); } - var thumbnail = document.querySelector( - 'div.thumbnail[data-page-number="' + page + '"]'); - if (thumbnail) { - 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, }); - } - } - }, + get pagesRotation() { + return this._pagesRotation; + } - get pagesRotation() { - return this._pagesRotation; - }, + set pagesRotation(rotation) { + this._pagesRotation = rotation; + for (let i = 0, l = this._thumbnails.length; i < l; i++) { + this._thumbnails[i].update(rotation); + } + } - set pagesRotation(rotation) { - this._pagesRotation = rotation; - for (var i = 0, l = this.thumbnails.length; i < l; i++) { - var thumb = this.thumbnails[i]; - thumb.update(rotation); - } - }, + cleanup() { + PDFThumbnailView.cleanup(); + } - cleanup: function PDFThumbnailViewer_cleanup() { - PDFThumbnailView.cleanup(); - }, + /** + * @private + */ + _resetView() { + this._thumbnails = []; + this._pageLabels = null; + this._pagesRotation = 0; + this._pagesRequests = []; - /** - * @private - */ - _resetView: function PDFThumbnailViewer_resetView() { - this.thumbnails = []; - this._pageLabels = null; - this._pagesRotation = 0; - this._pagesRequests = []; + // Remove the thumbnails from the DOM. + this.container.textContent = ''; + } - // Remove the thumbnails from the DOM. - this.container.textContent = ''; - }, + setDocument(pdfDocument) { + if (this.pdfDocument) { + this._cancelRendering(); + this._resetView(); + } - setDocument: function PDFThumbnailViewer_setDocument(pdfDocument) { - if (this.pdfDocument) { - this._cancelRendering(); - this._resetView(); - } + this.pdfDocument = pdfDocument; + if (!pdfDocument) { + return Promise.resolve(); + } - this.pdfDocument = pdfDocument; - if (!pdfDocument) { - return Promise.resolve(); - } - - return pdfDocument.getPage(1).then((firstPage) => { - var pagesCount = pdfDocument.numPages; - var viewport = firstPage.getViewport(1.0); - for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var thumbnail = new PDFThumbnailView({ - container: this.container, - id: pageNum, - defaultViewport: viewport.clone(), - linkService: this.linkService, - renderingQueue: this.renderingQueue, - disableCanvasToImageConversion: false, - l10n: this.l10n, - }); - this.thumbnails.push(thumbnail); - } - }); - }, - - /** - * @private - */ - _cancelRendering: function PDFThumbnailViewer_cancelRendering() { - for (var i = 0, ii = this.thumbnails.length; i < ii; i++) { - if (this.thumbnails[i]) { - this.thumbnails[i].cancelRendering(); - } - } - }, - - /** - * @param {Array|null} labels - */ - setPageLabels: function PDFThumbnailViewer_setPageLabels(labels) { - if (!this.pdfDocument) { - return; - } - if (!labels) { - this._pageLabels = null; - } else if (!(labels instanceof Array && - this.pdfDocument.numPages === labels.length)) { - this._pageLabels = null; - console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.'); - } else { - this._pageLabels = labels; - } - // Update all the `PDFThumbnailView` instances. - for (var i = 0, ii = this.thumbnails.length; i < ii; i++) { - var thumbnailView = this.thumbnails[i]; - var label = this._pageLabels && this._pageLabels[i]; - thumbnailView.setPageLabel(label); - } - }, - - /** - * @param {PDFThumbnailView} thumbView - * @returns {PDFPage} - * @private - */ - _ensurePdfPageLoaded(thumbView) { - if (thumbView.pdfPage) { - return Promise.resolve(thumbView.pdfPage); - } - var pageNumber = thumbView.id; - if (this._pagesRequests[pageNumber]) { - return this._pagesRequests[pageNumber]; - } - var promise = this.pdfDocument.getPage(pageNumber).then((pdfPage) => { - thumbView.setPdfPage(pdfPage); - this._pagesRequests[pageNumber] = null; - return pdfPage; - }); - this._pagesRequests[pageNumber] = promise; - return promise; - }, - - forceRendering() { - var visibleThumbs = this._getVisibleThumbs(); - var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, - this.thumbnails, - this.scroll.down); - if (thumbView) { - this._ensurePdfPageLoaded(thumbView).then(() => { - this.renderingQueue.renderView(thumbView); + return pdfDocument.getPage(1).then((firstPage) => { + let pagesCount = pdfDocument.numPages; + let viewport = firstPage.getViewport(1.0); + for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { + let thumbnail = new PDFThumbnailView({ + container: this.container, + id: pageNum, + defaultViewport: viewport.clone(), + linkService: this.linkService, + renderingQueue: this.renderingQueue, + disableCanvasToImageConversion: false, + l10n: this.l10n, }); - return true; + this._thumbnails.push(thumbnail); } - return false; - }, - }; + }); + } - return PDFThumbnailViewer; -})(); + /** + * @private + */ + _cancelRendering() { + for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { + if (this._thumbnails[i]) { + this._thumbnails[i].cancelRendering(); + } + } + } + + /** + * @param {Array|null} labels + */ + setPageLabels(labels) { + if (!this.pdfDocument) { + return; + } + if (!labels) { + this._pageLabels = null; + } else if (!(labels instanceof Array && + this.pdfDocument.numPages === labels.length)) { + this._pageLabels = null; + console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.'); + } else { + this._pageLabels = labels; + } + // Update all the `PDFThumbnailView` instances. + for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { + let label = this._pageLabels && this._pageLabels[i]; + this._thumbnails[i].setPageLabel(label); + } + } + + /** + * @param {PDFThumbnailView} thumbView + * @returns {PDFPage} + * @private + */ + _ensurePdfPageLoaded(thumbView) { + if (thumbView.pdfPage) { + return Promise.resolve(thumbView.pdfPage); + } + let pageNumber = thumbView.id; + if (this._pagesRequests[pageNumber]) { + return this._pagesRequests[pageNumber]; + } + let promise = this.pdfDocument.getPage(pageNumber).then((pdfPage) => { + thumbView.setPdfPage(pdfPage); + this._pagesRequests[pageNumber] = null; + return pdfPage; + }); + this._pagesRequests[pageNumber] = promise; + return promise; + } + + forceRendering() { + let visibleThumbs = this._getVisibleThumbs(); + let thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, + this._thumbnails, + this.scroll.down); + if (thumbView) { + this._ensurePdfPageLoaded(thumbView).then(() => { + this.renderingQueue.renderView(thumbView); + }); + return true; + } + return false; + } +} export { PDFThumbnailViewer, From 733a58a31588bb953300bd05bac27325d1766396 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 4 Jun 2017 19:45:28 +0200 Subject: [PATCH 2/2] Convert the thumbnail view to ES6 syntax --- web/pdf_thumbnail_view.js | 528 ++++++++++++++++++-------------------- 1 file changed, 256 insertions(+), 272 deletions(-) diff --git a/web/pdf_thumbnail_view.js b/web/pdf_thumbnail_view.js index 1de4e530a..1c0c3a42f 100644 --- a/web/pdf_thumbnail_view.js +++ b/web/pdf_thumbnail_view.js @@ -19,8 +19,9 @@ import { import { getOutputScale, NullL10n } from './ui_utils'; import { RenderingStates } from './pdf_rendering_queue'; -var THUMBNAIL_WIDTH = 98; // px -var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px +const MAX_NUM_SCALING_STEPS = 3; +const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px +const THUMBNAIL_WIDTH = 98; // px /** * @typedef {Object} PDFThumbnailViewOptions @@ -31,7 +32,7 @@ var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px * @property {PDFRenderingQueue} renderingQueue - The rendering queue object. * @property {boolean} disableCanvasToImageConversion - (optional) Don't convert * the canvas thumbnails to images. This prevents `toDataURL` calls, - * but increases the overall memory usage. The default value is false. + * but increases the overall memory usage. The default value is `false`. * @property {IL10n} l10n - Localization service. */ @@ -77,23 +78,14 @@ const TempImageFactory = (function TempImageFactoryClosure() { })(); /** - * @class * @implements {IRenderableView} */ -var PDFThumbnailView = (function PDFThumbnailViewClosure() { +class PDFThumbnailView { /** - * @constructs PDFThumbnailView * @param {PDFThumbnailViewOptions} options */ - function PDFThumbnailView(options) { - var container = options.container; - var id = options.id; - var defaultViewport = options.defaultViewport; - var linkService = options.linkService; - var renderingQueue = options.renderingQueue; - var disableCanvasToImageConversion = - options.disableCanvasToImageConversion || false; - + constructor({ container, id, defaultViewport, linkService, renderingQueue, + disableCanvasToImageConversion = false, l10n = NullL10n, }) { this.id = id; this.renderingId = 'thumbnail' + id; this.pageLabel = null; @@ -119,21 +111,21 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; this.scale = this.canvasWidth / this.pageWidth; - this.l10n = options.l10n || NullL10n; + this.l10n = l10n; - var anchor = document.createElement('a'); + let anchor = document.createElement('a'); anchor.href = linkService.getAnchorUrl('#page=' + id); this.l10n.get('thumb_page_title', { page: id, }, 'Page {{page}}'). then((msg) => { anchor.title = msg; }); - anchor.onclick = function stopNavigation() { + anchor.onclick = function() { linkService.page = id; return false; }; this.anchor = anchor; - var div = document.createElement('div'); + let div = document.createElement('div'); div.className = 'thumbnail'; div.setAttribute('data-page-number', this.id); this.div = div; @@ -144,9 +136,9 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { div.classList.add('selected'); } - var ring = document.createElement('div'); + let ring = document.createElement('div'); ring.className = 'thumbnailSelectionRing'; - var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; ring.style.width = this.canvasWidth + borderAdjustment + 'px'; ring.style.height = this.canvasHeight + borderAdjustment + 'px'; this.ring = ring; @@ -156,296 +148,288 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { container.appendChild(anchor); } - PDFThumbnailView.prototype = { - setPdfPage: function PDFThumbnailView_setPdfPage(pdfPage) { - this.pdfPage = pdfPage; - this.pdfPageRotate = pdfPage.rotate; - var totalRotation = (this.rotation + this.pdfPageRotate) % 360; - this.viewport = pdfPage.getViewport(1, totalRotation); - this.reset(); - }, + setPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + let totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = pdfPage.getViewport(1, totalRotation); + this.reset(); + } - reset: function PDFThumbnailView_reset() { - this.cancelRendering(); + reset() { + this.cancelRendering(); - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; + this.pageWidth = this.viewport.width; + this.pageHeight = this.viewport.height; + this.pageRatio = this.pageWidth / this.pageHeight; - this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; - this.scale = (this.canvasWidth / this.pageWidth); + this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0; + this.scale = (this.canvasWidth / this.pageWidth); - this.div.removeAttribute('data-loaded'); - var ring = this.ring; - var childNodes = ring.childNodes; - for (var i = childNodes.length - 1; i >= 0; i--) { - ring.removeChild(childNodes[i]); - } - var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; - ring.style.width = this.canvasWidth + borderAdjustment + 'px'; - ring.style.height = this.canvasHeight + borderAdjustment + 'px'; - - if (this.canvas) { - // Zeroing the width and height causes Firefox to release graphics - // resources immediately, which can greatly reduce memory consumption. - this.canvas.width = 0; - this.canvas.height = 0; - delete this.canvas; - } - if (this.image) { - this.image.removeAttribute('src'); - delete this.image; - } - }, - - update: function PDFThumbnailView_update(rotation) { - if (typeof rotation !== 'undefined') { - this.rotation = rotation; - } - var totalRotation = (this.rotation + this.pdfPageRotate) % 360; - this.viewport = this.viewport.clone({ - scale: 1, - rotation: totalRotation, - }); - this.reset(); - }, - - cancelRendering: function PDFThumbnailView_cancelRendering() { - if (this.renderTask) { - this.renderTask.cancel(); - this.renderTask = null; - } - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - }, - - /** - * @private - */ - _getPageDrawContext: - function PDFThumbnailView_getPageDrawContext(noCtxScale) { - var canvas = document.createElement('canvas'); - // Keep the no-thumbnail outline visible, i.e. `data-loaded === false`, - // until rendering/image conversion is complete, to avoid display issues. - this.canvas = canvas; - - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) { - canvas.mozOpaque = true; - } - var ctx = canvas.getContext('2d', { alpha: false, }); - var outputScale = getOutputScale(ctx); - - canvas.width = (this.canvasWidth * outputScale.sx) | 0; - canvas.height = (this.canvasHeight * outputScale.sy) | 0; - canvas.style.width = this.canvasWidth + 'px'; - canvas.style.height = this.canvasHeight + 'px'; - - if (!noCtxScale && outputScale.scaled) { - ctx.scale(outputScale.sx, outputScale.sy); - } - return ctx; - }, - - /** - * @private - */ - _convertCanvasToImage: function PDFThumbnailView_convertCanvasToImage() { - if (!this.canvas) { - return; - } - if (this.renderingState !== RenderingStates.FINISHED) { - return; - } - var id = this.renderingId; - var className = 'thumbnailImage'; - - if (this.disableCanvasToImageConversion) { - this.canvas.id = id; - this.canvas.className = className; - this.l10n.get('thumb_page_canvas', { page: this.pageId, }, - 'Thumbnail of Page {{page}}').then((msg) => { - this.canvas.setAttribute('aria-label', msg); - }); - - this.div.setAttribute('data-loaded', true); - this.ring.appendChild(this.canvas); - return; - } - var image = document.createElement('img'); - image.id = id; - image.className = className; - this.l10n.get('thumb_page_canvas', { page: this.pageId, }, - 'Thumbnail of Page {{page}}'). - then((msg) => { - image.setAttribute('aria-label', msg); - }); - - image.style.width = this.canvasWidth + 'px'; - image.style.height = this.canvasHeight + 'px'; - - image.src = this.canvas.toDataURL(); - this.image = image; - - this.div.setAttribute('data-loaded', true); - this.ring.appendChild(image); + this.div.removeAttribute('data-loaded'); + let ring = this.ring; + let childNodes = ring.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + ring.removeChild(childNodes[i]); + } + let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + ring.style.width = this.canvasWidth + borderAdjustment + 'px'; + ring.style.height = this.canvasHeight + borderAdjustment + 'px'; + if (this.canvas) { // Zeroing the width and height causes Firefox to release graphics // resources immediately, which can greatly reduce memory consumption. this.canvas.width = 0; this.canvas.height = 0; delete this.canvas; - }, + } + if (this.image) { + this.image.removeAttribute('src'); + delete this.image; + } + } - draw() { - if (this.renderingState !== RenderingStates.INITIAL) { - console.error('Must be in new state before drawing'); - return Promise.resolve(undefined); - } + update(rotation) { + if (typeof rotation !== 'undefined') { + this.rotation = rotation; + } + let totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: 1, + rotation: totalRotation, + }); + this.reset(); + } - this.renderingState = RenderingStates.RUNNING; + cancelRendering() { + if (this.renderTask) { + this.renderTask.cancel(); + this.renderTask = null; + } + this.renderingState = RenderingStates.INITIAL; + this.resume = null; + } - let renderCapability = createPromiseCapability(); + /** + * @private + */ + _getPageDrawContext(noCtxScale = false) { + let canvas = document.createElement('canvas'); + // Keep the no-thumbnail outline visible, i.e. `data-loaded === false`, + // until rendering/image conversion is complete, to avoid display issues. + this.canvas = canvas; - let finishRenderTask = (error) => { - // The renderTask may have been replaced by a new one, so only remove - // the reference to the renderTask if it matches the one that is - // triggering this callback. - if (renderTask === this.renderTask) { - this.renderTask = null; - } + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) { + canvas.mozOpaque = true; + } + let ctx = canvas.getContext('2d', { alpha: false, }); + let outputScale = getOutputScale(ctx); - if (((typeof PDFJSDev === 'undefined' || - !PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') || - error instanceof RenderingCancelledException) { - renderCapability.resolve(undefined); - return; - } + canvas.width = (this.canvasWidth * outputScale.sx) | 0; + canvas.height = (this.canvasHeight * outputScale.sy) | 0; + canvas.style.width = this.canvasWidth + 'px'; + canvas.style.height = this.canvasHeight + 'px'; - this.renderingState = RenderingStates.FINISHED; - this._convertCanvasToImage(); + if (!noCtxScale && outputScale.scaled) { + ctx.scale(outputScale.sx, outputScale.sy); + } + return ctx; + } - if (!error) { - renderCapability.resolve(undefined); - } else { - renderCapability.reject(error); - } - }; + /** + * @private + */ + _convertCanvasToImage() { + if (!this.canvas) { + return; + } + if (this.renderingState !== RenderingStates.FINISHED) { + return; + } + let id = this.renderingId; + let className = 'thumbnailImage'; - let ctx = this._getPageDrawContext(); - let drawViewport = this.viewport.clone({ scale: this.scale, }); - let renderContinueCallback = (cont) => { - if (!this.renderingQueue.isHighestPriority(this)) { - this.renderingState = RenderingStates.PAUSED; - this.resume = () => { - this.renderingState = RenderingStates.RUNNING; - cont(); - }; - return; - } - cont(); - }; - - let renderContext = { - canvasContext: ctx, - viewport: drawViewport, - }; - let renderTask = this.renderTask = this.pdfPage.render(renderContext); - renderTask.onContinue = renderContinueCallback; - - renderTask.promise.then(function() { - finishRenderTask(null); - }, function(error) { - finishRenderTask(error); + if (this.disableCanvasToImageConversion) { + this.canvas.id = id; + this.canvas.className = className; + this.l10n.get('thumb_page_canvas', { page: this.pageId, }, + 'Thumbnail of Page {{page}}').then((msg) => { + this.canvas.setAttribute('aria-label', msg); }); - return renderCapability.promise; - }, - setImage: function PDFThumbnailView_setImage(pageView) { - if (this.renderingState !== RenderingStates.INITIAL) { - return; + this.div.setAttribute('data-loaded', true); + this.ring.appendChild(this.canvas); + return; + } + let image = document.createElement('img'); + image.id = id; + image.className = className; + this.l10n.get('thumb_page_canvas', { page: this.pageId, }, + 'Thumbnail of Page {{page}}'). + then((msg) => { + image.setAttribute('aria-label', msg); + }); + + image.style.width = this.canvasWidth + 'px'; + image.style.height = this.canvasHeight + 'px'; + + image.src = this.canvas.toDataURL(); + this.image = image; + + this.div.setAttribute('data-loaded', true); + this.ring.appendChild(image); + + // Zeroing the width and height causes Firefox to release graphics + // resources immediately, which can greatly reduce memory consumption. + this.canvas.width = 0; + this.canvas.height = 0; + delete this.canvas; + } + + draw() { + if (this.renderingState !== RenderingStates.INITIAL) { + console.error('Must be in new state before drawing'); + return Promise.resolve(undefined); + } + this.renderingState = RenderingStates.RUNNING; + + let renderCapability = createPromiseCapability(); + let finishRenderTask = (error) => { + // The renderTask may have been replaced by a new one, so only remove + // the reference to the renderTask if it matches the one that is + // triggering this callback. + if (renderTask === this.renderTask) { + this.renderTask = null; } - var img = pageView.canvas; - if (!img) { + + if (((typeof PDFJSDev === 'undefined' || + !PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') || + error instanceof RenderingCancelledException) { + renderCapability.resolve(undefined); return; } - if (!this.pdfPage) { - this.setPdfPage(pageView.pdfPage); - } this.renderingState = RenderingStates.FINISHED; + this._convertCanvasToImage(); - var ctx = this._getPageDrawContext(true); - var canvas = ctx.canvas; + if (!error) { + renderCapability.resolve(undefined); + } else { + renderCapability.reject(error); + } + }; - if (img.width <= 2 * canvas.width) { - ctx.drawImage(img, 0, 0, img.width, img.height, - 0, 0, canvas.width, canvas.height); - this._convertCanvasToImage(); + let ctx = this._getPageDrawContext(); + let drawViewport = this.viewport.clone({ scale: this.scale, }); + let renderContinueCallback = (cont) => { + if (!this.renderingQueue.isHighestPriority(this)) { + this.renderingState = RenderingStates.PAUSED; + this.resume = () => { + this.renderingState = RenderingStates.RUNNING; + cont(); + }; return; } - // drawImage does an awful job of rescaling the image, doing it gradually. - var MAX_NUM_SCALING_STEPS = 3; - var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; - var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; - var reducedImage = TempImageFactory.getCanvas(reducedWidth, - reducedHeight); - var reducedImageCtx = reducedImage.getContext('2d'); + cont(); + }; - while (reducedWidth > img.width || reducedHeight > img.height) { - reducedWidth >>= 1; - reducedHeight >>= 1; - } - reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, - 0, 0, reducedWidth, reducedHeight); - while (reducedWidth > 2 * canvas.width) { - reducedImageCtx.drawImage(reducedImage, - 0, 0, reducedWidth, reducedHeight, - 0, 0, reducedWidth >> 1, reducedHeight >> 1); - reducedWidth >>= 1; - reducedHeight >>= 1; - } - ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, + let renderContext = { + canvasContext: ctx, + viewport: drawViewport, + }; + let renderTask = this.renderTask = this.pdfPage.render(renderContext); + renderTask.onContinue = renderContinueCallback; + + renderTask.promise.then(function() { + finishRenderTask(null); + }, function(error) { + finishRenderTask(error); + }); + return renderCapability.promise; + } + + setImage(pageView) { + if (this.renderingState !== RenderingStates.INITIAL) { + return; + } + let img = pageView.canvas; + if (!img) { + return; + } + if (!this.pdfPage) { + this.setPdfPage(pageView.pdfPage); + } + + this.renderingState = RenderingStates.FINISHED; + + let ctx = this._getPageDrawContext(true); + let canvas = ctx.canvas; + if (img.width <= 2 * canvas.width) { + ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); this._convertCanvasToImage(); - }, + return; + } - get pageId() { - return (this.pageLabel !== null ? this.pageLabel : this.id); - }, + // drawImage does an awful job of rescaling the image, doing it gradually. + let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; + let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; + let reducedImage = TempImageFactory.getCanvas(reducedWidth, + reducedHeight); + let reducedImageCtx = reducedImage.getContext('2d'); - /** - * @param {string|null} label - */ - setPageLabel: function PDFThumbnailView_setPageLabel(label) { - this.pageLabel = (typeof label === 'string' ? label : null); + while (reducedWidth > img.width || reducedHeight > img.height) { + reducedWidth >>= 1; + reducedHeight >>= 1; + } + reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, + 0, 0, reducedWidth, reducedHeight); + while (reducedWidth > 2 * canvas.width) { + reducedImageCtx.drawImage(reducedImage, + 0, 0, reducedWidth, reducedHeight, + 0, 0, reducedWidth >> 1, reducedHeight >> 1); + reducedWidth >>= 1; + reducedHeight >>= 1; + } + ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, + 0, 0, canvas.width, canvas.height); + this._convertCanvasToImage(); + } - this.l10n.get('thumb_page_title', { page: this.pageId, }, - 'Page {{page}}').then((msg) => { - this.anchor.title = msg; - }); + get pageId() { + return (this.pageLabel !== null ? this.pageLabel : this.id); + } - if (this.renderingState !== RenderingStates.FINISHED) { - return; + /** + * @param {string|null} label + */ + setPageLabel(label) { + this.pageLabel = (typeof label === 'string' ? label : null); + + this.l10n.get('thumb_page_title', { page: this.pageId, }, + 'Page {{page}}').then((msg) => { + this.anchor.title = msg; + }); + + if (this.renderingState !== RenderingStates.FINISHED) { + return; + } + + this.l10n.get('thumb_page_canvas', { page: this.pageId, }, + 'Thumbnail of Page {{page}}').then((ariaLabel) => { + if (this.image) { + this.image.setAttribute('aria-label', ariaLabel); + } else if (this.disableCanvasToImageConversion && this.canvas) { + this.canvas.setAttribute('aria-label', ariaLabel); } + }); + } - this.l10n.get('thumb_page_canvas', { page: this.pageId, }, - 'Thumbnail of Page {{page}}').then((ariaLabel) => { - if (this.image) { - this.image.setAttribute('aria-label', ariaLabel); - } else if (this.disableCanvasToImageConversion && this.canvas) { - this.canvas.setAttribute('aria-label', ariaLabel); - } - }); - }, - }; - - PDFThumbnailView.cleanup = function() { + static cleanup() { TempImageFactory.destroyCanvas(); - }; - - return PDFThumbnailView; -})(); + } +} export { PDFThumbnailView,