123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /* Copyright 2017 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';
- var uiUtils = require('./ui_utils.js');
- var pdfRenderingQueue = require('./pdf_rendering_queue.js');
- var mozL10n = uiUtils.mozL10n;
- var getOutputScale = uiUtils.getOutputScale;
- var RenderingStates = pdfRenderingQueue.RenderingStates;
- var THUMBNAIL_WIDTH = 98;
- var THUMBNAIL_CANVAS_BORDER_WIDTH = 1;
- var PDFThumbnailView = function PDFThumbnailViewClosure() {
- function getTempCanvas(width, height) {
- var tempCanvas = PDFThumbnailView.tempImageCache;
- if (!tempCanvas) {
- tempCanvas = document.createElement('canvas');
- PDFThumbnailView.tempImageCache = tempCanvas;
- }
- tempCanvas.width = width;
- tempCanvas.height = height;
- tempCanvas.mozOpaque = true;
- var ctx = tempCanvas.getContext('2d', { alpha: false });
- ctx.save();
- ctx.fillStyle = 'rgb(255, 255, 255)';
- ctx.fillRect(0, 0, width, height);
- ctx.restore();
- return tempCanvas;
- }
- 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;
- this.id = id;
- this.renderingId = 'thumbnail' + id;
- this.pageLabel = null;
- this.pdfPage = null;
- this.rotation = 0;
- this.viewport = defaultViewport;
- this.pdfPageRotate = defaultViewport.rotation;
- this.linkService = linkService;
- this.renderingQueue = renderingQueue;
- this.renderTask = null;
- this.renderingState = RenderingStates.INITIAL;
- this.resume = null;
- this.disableCanvasToImageConversion = disableCanvasToImageConversion;
- this.pageWidth = this.viewport.width;
- this.pageHeight = this.viewport.height;
- this.pageRatio = this.pageWidth / this.pageHeight;
- this.canvasWidth = THUMBNAIL_WIDTH;
- this.canvasHeight = this.canvasWidth / this.pageRatio | 0;
- this.scale = this.canvasWidth / this.pageWidth;
- var anchor = document.createElement('a');
- anchor.href = linkService.getAnchorUrl('#page=' + id);
- anchor.title = mozL10n.get('thumb_page_title', { page: id }, 'Page {{page}}');
- anchor.onclick = function stopNavigation() {
- linkService.page = id;
- return false;
- };
- this.anchor = anchor;
- var div = document.createElement('div');
- div.className = 'thumbnail';
- div.setAttribute('data-page-number', this.id);
- this.div = div;
- if (id === 1) {
- div.classList.add('selected');
- }
- var ring = document.createElement('div');
- ring.className = 'thumbnailSelectionRing';
- var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
- ring.style.width = this.canvasWidth + borderAdjustment + 'px';
- ring.style.height = this.canvasHeight + borderAdjustment + 'px';
- this.ring = ring;
- div.appendChild(ring);
- anchor.appendChild(div);
- 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();
- },
- reset: function PDFThumbnailView_reset() {
- this.cancelRendering();
- 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.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) {
- 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;
- },
- _getPageDrawContext: function PDFThumbnailView_getPageDrawContext(noCtxScale) {
- var canvas = document.createElement('canvas');
- this.canvas = canvas;
- 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;
- },
- _convertCanvasToImage: function PDFThumbnailView_convertCanvasToImage() {
- if (!this.canvas) {
- return;
- }
- if (this.renderingState !== RenderingStates.FINISHED) {
- return;
- }
- var id = this.renderingId;
- var className = 'thumbnailImage';
- var ariaLabel = mozL10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}');
- if (this.disableCanvasToImageConversion) {
- this.canvas.id = id;
- this.canvas.className = className;
- this.canvas.setAttribute('aria-label', ariaLabel);
- this.div.setAttribute('data-loaded', true);
- this.ring.appendChild(this.canvas);
- return;
- }
- var image = document.createElement('img');
- image.id = id;
- image.className = className;
- image.setAttribute('aria-label', ariaLabel);
- 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.canvas.width = 0;
- this.canvas.height = 0;
- delete this.canvas;
- },
- draw: function PDFThumbnailView_draw() {
- if (this.renderingState !== RenderingStates.INITIAL) {
- console.error('Must be in new state before drawing');
- return Promise.resolve(undefined);
- }
- this.renderingState = RenderingStates.RUNNING;
- var resolveRenderPromise, rejectRenderPromise;
- var promise = new Promise(function (resolve, reject) {
- resolveRenderPromise = resolve;
- rejectRenderPromise = reject;
- });
- var self = this;
- function thumbnailDrawCallback(error) {
- if (renderTask === self.renderTask) {
- self.renderTask = null;
- }
- if (error === 'cancelled') {
- rejectRenderPromise(error);
- return;
- }
- self.renderingState = RenderingStates.FINISHED;
- self._convertCanvasToImage();
- if (!error) {
- resolveRenderPromise(undefined);
- } else {
- rejectRenderPromise(error);
- }
- }
- var ctx = this._getPageDrawContext();
- var drawViewport = this.viewport.clone({ scale: this.scale });
- var renderContinueCallback = function renderContinueCallback(cont) {
- if (!self.renderingQueue.isHighestPriority(self)) {
- self.renderingState = RenderingStates.PAUSED;
- self.resume = function resumeCallback() {
- self.renderingState = RenderingStates.RUNNING;
- cont();
- };
- return;
- }
- cont();
- };
- var renderContext = {
- canvasContext: ctx,
- viewport: drawViewport
- };
- var renderTask = this.renderTask = this.pdfPage.render(renderContext);
- renderTask.onContinue = renderContinueCallback;
- renderTask.promise.then(function pdfPageRenderCallback() {
- thumbnailDrawCallback(null);
- }, function pdfPageRenderError(error) {
- thumbnailDrawCallback(error);
- });
- return promise;
- },
- setImage: function PDFThumbnailView_setImage(pageView) {
- if (this.renderingState !== RenderingStates.INITIAL) {
- return;
- }
- var img = pageView.canvas;
- if (!img) {
- return;
- }
- if (!this.pdfPage) {
- this.setPdfPage(pageView.pdfPage);
- }
- this.renderingState = RenderingStates.FINISHED;
- var ctx = this._getPageDrawContext(true);
- var 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;
- }
- var MAX_NUM_SCALING_STEPS = 3;
- var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
- var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
- var reducedImage = getTempCanvas(reducedWidth, reducedHeight);
- var reducedImageCtx = reducedImage.getContext('2d');
- 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();
- },
- get pageId() {
- return this.pageLabel !== null ? this.pageLabel : this.id;
- },
- setPageLabel: function PDFThumbnailView_setPageLabel(label) {
- this.pageLabel = typeof label === 'string' ? label : null;
- this.anchor.title = mozL10n.get('thumb_page_title', { page: this.pageId }, 'Page {{page}}');
- if (this.renderingState !== RenderingStates.FINISHED) {
- return;
- }
- var ariaLabel = mozL10n.get('thumb_page_canvas', { page: this.pageId }, 'Thumbnail of Page {{page}}');
- if (this.image) {
- this.image.setAttribute('aria-label', ariaLabel);
- } else if (this.disableCanvasToImageConversion && this.canvas) {
- this.canvas.setAttribute('aria-label', ariaLabel);
- }
- }
- };
- return PDFThumbnailView;
- }();
- PDFThumbnailView.tempImageCache = null;
- exports.PDFThumbnailView = PDFThumbnailView;
|