|
@@ -20,8 +20,8 @@ if (typeof PDFJS === 'undefined') {
|
|
|
(typeof window !== 'undefined' ? window : this).PDFJS = {};
|
|
|
}
|
|
|
|
|
|
-PDFJS.version = '1.3.6';
|
|
|
-PDFJS.build = '1250e35';
|
|
|
+PDFJS.version = '1.3.10';
|
|
|
+PDFJS.build = 'fc2d7e8';
|
|
|
|
|
|
(function pdfjsWrapper() {
|
|
|
// Use strict in our context only - users might not want it
|
|
@@ -6865,6 +6865,63 @@ var FontFaceObject = (function FontFaceObjectClosure() {
|
|
|
})();
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * Optimised CSS custom property getter/setter.
|
|
|
+ * @class
|
|
|
+ */
|
|
|
+var CustomStyle = (function CustomStyleClosure() {
|
|
|
+
|
|
|
+ // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
|
|
|
+ // animate-css-transforms-firefox-webkit.html
|
|
|
+ // in some versions of IE9 it is critical that ms appear in this list
|
|
|
+ // before Moz
|
|
|
+ var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
|
|
|
+ var _cache = {};
|
|
|
+
|
|
|
+ function CustomStyle() {}
|
|
|
+
|
|
|
+ CustomStyle.getProp = function get(propName, element) {
|
|
|
+ // check cache only when no element is given
|
|
|
+ if (arguments.length === 1 && typeof _cache[propName] === 'string') {
|
|
|
+ return _cache[propName];
|
|
|
+ }
|
|
|
+
|
|
|
+ element = element || document.documentElement;
|
|
|
+ var style = element.style, prefixed, uPropName;
|
|
|
+
|
|
|
+ // test standard property first
|
|
|
+ if (typeof style[propName] === 'string') {
|
|
|
+ return (_cache[propName] = propName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // capitalize
|
|
|
+ uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
|
|
|
+
|
|
|
+ // test vendor specific properties
|
|
|
+ for (var i = 0, l = prefixes.length; i < l; i++) {
|
|
|
+ prefixed = prefixes[i] + uPropName;
|
|
|
+ if (typeof style[prefixed] === 'string') {
|
|
|
+ return (_cache[propName] = prefixed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //if all fails then set to undefined
|
|
|
+ return (_cache[propName] = 'undefined');
|
|
|
+ };
|
|
|
+
|
|
|
+ CustomStyle.setProp = function set(propName, element, str) {
|
|
|
+ var prop = this.getProp(propName);
|
|
|
+ if (prop !== 'undefined') {
|
|
|
+ element.style[prop] = str;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return CustomStyle;
|
|
|
+})();
|
|
|
+
|
|
|
+PDFJS.CustomStyle = CustomStyle;
|
|
|
+
|
|
|
+
|
|
|
var ANNOT_MIN_SIZE = 10; // px
|
|
|
|
|
|
var AnnotationUtils = (function AnnotationUtilsClosure() {
|
|
@@ -7137,6 +7194,225 @@ var AnnotationUtils = (function AnnotationUtilsClosure() {
|
|
|
PDFJS.AnnotationUtils = AnnotationUtils;
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * Text layer render parameters.
|
|
|
+ *
|
|
|
+ * @typedef {Object} TextLayerRenderParameters
|
|
|
+ * @property {TextContent} textContent - Text content to render (the object is
|
|
|
+ * returned by the page's getTextContent() method).
|
|
|
+ * @property {HTMLElement} container - HTML element that will contain text runs.
|
|
|
+ * @property {PDFJS.PageViewport} viewport - The target viewport to properly
|
|
|
+ * layout the text runs.
|
|
|
+ * @property {Array} textDivs - (optional) HTML elements that are correspond
|
|
|
+ * the text items of the textContent input. This is output and shall be
|
|
|
+ * initially be set to empty array.
|
|
|
+ * @property {number} timeout - (optional) Delay in milliseconds before
|
|
|
+ * rendering of the text runs occurs.
|
|
|
+ */
|
|
|
+var renderTextLayer = (function renderTextLayerClosure() {
|
|
|
+ var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
|
|
+
|
|
|
+ var NonWhitespaceRegexp = /\S/;
|
|
|
+
|
|
|
+ function isAllWhitespace(str) {
|
|
|
+ return !NonWhitespaceRegexp.test(str);
|
|
|
+ }
|
|
|
+
|
|
|
+ function appendText(textDivs, viewport, geom, styles) {
|
|
|
+ var style = styles[geom.fontName];
|
|
|
+ var textDiv = document.createElement('div');
|
|
|
+ textDivs.push(textDiv);
|
|
|
+ if (isAllWhitespace(geom.str)) {
|
|
|
+ textDiv.dataset.isWhitespace = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var tx = PDFJS.Util.transform(viewport.transform, geom.transform);
|
|
|
+ var angle = Math.atan2(tx[1], tx[0]);
|
|
|
+ if (style.vertical) {
|
|
|
+ angle += Math.PI / 2;
|
|
|
+ }
|
|
|
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
|
|
|
+ var fontAscent = fontHeight;
|
|
|
+ if (style.ascent) {
|
|
|
+ fontAscent = style.ascent * fontAscent;
|
|
|
+ } else if (style.descent) {
|
|
|
+ fontAscent = (1 + style.descent) * fontAscent;
|
|
|
+ }
|
|
|
+
|
|
|
+ var left;
|
|
|
+ var top;
|
|
|
+ if (angle === 0) {
|
|
|
+ left = tx[4];
|
|
|
+ top = tx[5] - fontAscent;
|
|
|
+ } else {
|
|
|
+ left = tx[4] + (fontAscent * Math.sin(angle));
|
|
|
+ top = tx[5] - (fontAscent * Math.cos(angle));
|
|
|
+ }
|
|
|
+ textDiv.style.left = left + 'px';
|
|
|
+ textDiv.style.top = top + 'px';
|
|
|
+ textDiv.style.fontSize = fontHeight + 'px';
|
|
|
+ textDiv.style.fontFamily = style.fontFamily;
|
|
|
+
|
|
|
+ textDiv.textContent = geom.str;
|
|
|
+ // |fontName| is only used by the Font Inspector. This test will succeed
|
|
|
+ // when e.g. the Font Inspector is off but the Stepper is on, but it's
|
|
|
+ // not worth the effort to do a more accurate test.
|
|
|
+ if (PDFJS.pdfBug) {
|
|
|
+ textDiv.dataset.fontName = geom.fontName;
|
|
|
+ }
|
|
|
+ // Storing into dataset will convert number into string.
|
|
|
+ if (angle !== 0) {
|
|
|
+ textDiv.dataset.angle = angle * (180 / Math.PI);
|
|
|
+ }
|
|
|
+ // We don't bother scaling single-char text divs, because it has very
|
|
|
+ // little effect on text highlighting. This makes scrolling on docs with
|
|
|
+ // lots of such divs a lot faster.
|
|
|
+ if (geom.str.length > 1) {
|
|
|
+ if (style.vertical) {
|
|
|
+ textDiv.dataset.canvasWidth = geom.height * viewport.scale;
|
|
|
+ } else {
|
|
|
+ textDiv.dataset.canvasWidth = geom.width * viewport.scale;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function render(task) {
|
|
|
+ if (task._canceled) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var textLayerFrag = task._container;
|
|
|
+ var textDivs = task._textDivs;
|
|
|
+ var capability = task._capability;
|
|
|
+ var textDivsLength = textDivs.length;
|
|
|
+
|
|
|
+ // No point in rendering many divs as it would make the browser
|
|
|
+ // unusable even after the divs are rendered.
|
|
|
+ if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
|
|
|
+ capability.resolve();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var canvas = document.createElement('canvas');
|
|
|
+ canvas.mozOpaque = true;
|
|
|
+ var ctx = canvas.getContext('2d', {alpha: false});
|
|
|
+
|
|
|
+ var lastFontSize;
|
|
|
+ var lastFontFamily;
|
|
|
+ for (var i = 0; i < textDivsLength; i++) {
|
|
|
+ var textDiv = textDivs[i];
|
|
|
+ if (textDiv.dataset.isWhitespace !== undefined) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var fontSize = textDiv.style.fontSize;
|
|
|
+ var fontFamily = textDiv.style.fontFamily;
|
|
|
+
|
|
|
+ // Only build font string and set to context if different from last.
|
|
|
+ if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
|
|
|
+ ctx.font = fontSize + ' ' + fontFamily;
|
|
|
+ lastFontSize = fontSize;
|
|
|
+ lastFontFamily = fontFamily;
|
|
|
+ }
|
|
|
+
|
|
|
+ var width = ctx.measureText(textDiv.textContent).width;
|
|
|
+ if (width > 0) {
|
|
|
+ textLayerFrag.appendChild(textDiv);
|
|
|
+ var transform;
|
|
|
+ if (textDiv.dataset.canvasWidth !== undefined) {
|
|
|
+ // Dataset values come of type string.
|
|
|
+ var textScale = textDiv.dataset.canvasWidth / width;
|
|
|
+ transform = 'scaleX(' + textScale + ')';
|
|
|
+ } else {
|
|
|
+ transform = '';
|
|
|
+ }
|
|
|
+ var rotation = textDiv.dataset.angle;
|
|
|
+ if (rotation) {
|
|
|
+ transform = 'rotate(' + rotation + 'deg) ' + transform;
|
|
|
+ }
|
|
|
+ if (transform) {
|
|
|
+ PDFJS.CustomStyle.setProp('transform' , textDiv, transform);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ capability.resolve();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Text layer rendering task.
|
|
|
+ *
|
|
|
+ * @param {TextContent} textContent
|
|
|
+ * @param {HTMLElement} container
|
|
|
+ * @param {PDFJS.PageViewport} viewport
|
|
|
+ * @param {Array} textDivs
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ function TextLayerRenderTask(textContent, container, viewport, textDivs) {
|
|
|
+ this._textContent = textContent;
|
|
|
+ this._container = container;
|
|
|
+ this._viewport = viewport;
|
|
|
+ textDivs = textDivs || [];
|
|
|
+ this._textDivs = textDivs;
|
|
|
+ this._canceled = false;
|
|
|
+ this._capability = createPromiseCapability();
|
|
|
+ this._renderTimer = null;
|
|
|
+ }
|
|
|
+ TextLayerRenderTask.prototype = {
|
|
|
+ get promise() {
|
|
|
+ return this._capability.promise;
|
|
|
+ },
|
|
|
+
|
|
|
+ cancel: function TextLayer_cancel() {
|
|
|
+ this._canceled = true;
|
|
|
+ if (this._renderTimer !== null) {
|
|
|
+ clearTimeout(this._renderTimer);
|
|
|
+ this._renderTimer = null;
|
|
|
+ }
|
|
|
+ this._capability.reject('canceled');
|
|
|
+ },
|
|
|
+
|
|
|
+ _render: function TextLayer_render(timeout) {
|
|
|
+ var textItems = this._textContent.items;
|
|
|
+ var styles = this._textContent.styles;
|
|
|
+ var textDivs = this._textDivs;
|
|
|
+ var viewport = this._viewport;
|
|
|
+ for (var i = 0, len = textItems.length; i < len; i++) {
|
|
|
+ appendText(textDivs, viewport, textItems[i], styles);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!timeout) { // Render right away
|
|
|
+ render(this);
|
|
|
+ } else { // Schedule
|
|
|
+ var self = this;
|
|
|
+ this._renderTimer = setTimeout(function() {
|
|
|
+ render(self);
|
|
|
+ self._renderTimer = null;
|
|
|
+ }, timeout);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Starts rendering of the text layer.
|
|
|
+ *
|
|
|
+ * @param {TextLayerRenderParameters} renderParameters
|
|
|
+ * @returns {TextLayerRenderTask}
|
|
|
+ */
|
|
|
+ function renderTextLayer(renderParameters) {
|
|
|
+ var task = new TextLayerRenderTask(renderParameters.textContent,
|
|
|
+ renderParameters.container,
|
|
|
+ renderParameters.viewport,
|
|
|
+ renderParameters.textDivs);
|
|
|
+ task._render(renderParameters.timeout);
|
|
|
+ return task;
|
|
|
+ }
|
|
|
+
|
|
|
+ return renderTextLayer;
|
|
|
+})();
|
|
|
+
|
|
|
+PDFJS.renderTextLayer = renderTextLayer;
|
|
|
+
|
|
|
+
|
|
|
var SVG_DEFAULTS = {
|
|
|
fontStyle: 'normal',
|
|
|
fontWeight: 'normal',
|