You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
12 KiB
322 lines
12 KiB
/* 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'; |
|
|
|
Object.defineProperty(exports, "__esModule", { |
|
value: true |
|
}); |
|
exports.PDFThumbnailView = undefined; |
|
|
|
var _pdfjs = require('./pdfjs'); |
|
|
|
var _ui_utils = require('./ui_utils'); |
|
|
|
var _pdf_rendering_queue = require('./pdf_rendering_queue'); |
|
|
|
var THUMBNAIL_WIDTH = 98; |
|
var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; |
|
var TempImageFactory = function TempImageFactoryClosure() { |
|
var tempCanvasCache = null; |
|
return { |
|
getCanvas: function getCanvas(width, height) { |
|
var tempCanvas = tempCanvasCache; |
|
if (!tempCanvas) { |
|
tempCanvas = document.createElement('canvas'); |
|
tempCanvasCache = 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; |
|
}, |
|
destroyCanvas: function destroyCanvas() { |
|
var tempCanvas = tempCanvasCache; |
|
if (tempCanvas) { |
|
tempCanvas.width = 0; |
|
tempCanvas.height = 0; |
|
} |
|
tempCanvasCache = null; |
|
} |
|
}; |
|
}(); |
|
var PDFThumbnailView = function PDFThumbnailViewClosure() { |
|
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 = _pdf_rendering_queue.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 = _ui_utils.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 = _pdf_rendering_queue.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 = (0, _ui_utils.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 !== _pdf_rendering_queue.RenderingStates.FINISHED) { |
|
return; |
|
} |
|
var id = this.renderingId; |
|
var className = 'thumbnailImage'; |
|
var ariaLabel = _ui_utils.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 draw() { |
|
var _this = this; |
|
|
|
if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { |
|
console.error('Must be in new state before drawing'); |
|
return Promise.resolve(undefined); |
|
} |
|
this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; |
|
var renderCapability = (0, _pdfjs.createPromiseCapability)(); |
|
var finishRenderTask = function finishRenderTask(error) { |
|
if (renderTask === _this.renderTask) { |
|
_this.renderTask = null; |
|
} |
|
if (error === 'cancelled' || error instanceof _pdfjs.RenderingCancelledException) { |
|
renderCapability.resolve(undefined); |
|
return; |
|
} |
|
_this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; |
|
_this._convertCanvasToImage(); |
|
if (!error) { |
|
renderCapability.resolve(undefined); |
|
} else { |
|
renderCapability.reject(error); |
|
} |
|
}; |
|
var ctx = this._getPageDrawContext(); |
|
var drawViewport = this.viewport.clone({ scale: this.scale }); |
|
var renderContinueCallback = function renderContinueCallback(cont) { |
|
if (!_this.renderingQueue.isHighestPriority(_this)) { |
|
_this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; |
|
_this.resume = function () { |
|
_this.renderingState = _pdf_rendering_queue.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 () { |
|
finishRenderTask(null); |
|
}, function (error) { |
|
finishRenderTask(error); |
|
}); |
|
return renderCapability.promise; |
|
}, |
|
|
|
setImage: function PDFThumbnailView_setImage(pageView) { |
|
if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { |
|
return; |
|
} |
|
var img = pageView.canvas; |
|
if (!img) { |
|
return; |
|
} |
|
if (!this.pdfPage) { |
|
this.setPdfPage(pageView.pdfPage); |
|
} |
|
this.renderingState = _pdf_rendering_queue.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 = TempImageFactory.getCanvas(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 = _ui_utils.mozL10n.get('thumb_page_title', { page: this.pageId }, 'Page {{page}}'); |
|
if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { |
|
return; |
|
} |
|
var ariaLabel = _ui_utils.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); |
|
} |
|
} |
|
}; |
|
PDFThumbnailView.cleanup = function () { |
|
TempImageFactory.destroyCanvas(); |
|
}; |
|
return PDFThumbnailView; |
|
}(); |
|
exports.PDFThumbnailView = PDFThumbnailView; |