|
@@ -34,57 +34,6 @@ var MAX_AUTO_SCALE = 1.25;
|
|
var SCROLLBAR_PADDING = 40;
|
|
var SCROLLBAR_PADDING = 40;
|
|
var VERTICAL_PADDING = 5;
|
|
var VERTICAL_PADDING = 5;
|
|
|
|
|
|
-// optimised CSS custom property getter/setter
|
|
|
|
-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;
|
|
|
|
-})();
|
|
|
|
-
|
|
|
|
var NullCharactersRegExp = /\x00/g;
|
|
var NullCharactersRegExp = /\x00/g;
|
|
|
|
|
|
function removeNullCharacters(str) {
|
|
function removeNullCharacters(str) {
|
|
@@ -955,6 +904,8 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms
|
|
* @implements {IRenderableView}
|
|
* @implements {IRenderableView}
|
|
*/
|
|
*/
|
|
var PDFPageView = (function PDFPageViewClosure() {
|
|
var PDFPageView = (function PDFPageViewClosure() {
|
|
|
|
+ var CustomStyle = PDFJS.CustomStyle;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* @constructs PDFPageView
|
|
* @constructs PDFPageView
|
|
* @param {PDFPageViewOptions} options
|
|
* @param {PDFPageViewOptions} options
|
|
@@ -1490,14 +1441,6 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|
})();
|
|
})();
|
|
|
|
|
|
|
|
|
|
-var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
|
|
|
-
|
|
|
|
-var NonWhitespaceRegexp = /\S/;
|
|
|
|
-
|
|
|
|
-function isAllWhitespace(str) {
|
|
|
|
- return !NonWhitespaceRegexp.test(str);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* @typedef {Object} TextLayerBuilderOptions
|
|
* @typedef {Object} TextLayerBuilderOptions
|
|
* @property {HTMLDivElement} textLayerDiv - The text layer container.
|
|
* @property {HTMLDivElement} textLayerDiv - The text layer container.
|
|
@@ -1524,6 +1467,7 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
this.viewport = options.viewport;
|
|
this.viewport = options.viewport;
|
|
this.textDivs = [];
|
|
this.textDivs = [];
|
|
this.findController = options.findController || null;
|
|
this.findController = options.findController || null;
|
|
|
|
+ this.textLayerRenderTask = null;
|
|
this._bindMouse();
|
|
this._bindMouse();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1542,64 +1486,6 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
this.textLayerDiv.dispatchEvent(event);
|
|
this.textLayerDiv.dispatchEvent(event);
|
|
},
|
|
},
|
|
|
|
|
|
- renderLayer: function TextLayerBuilder_renderLayer() {
|
|
|
|
- var textLayerFrag = document.createDocumentFragment();
|
|
|
|
- var textDivs = this.textDivs;
|
|
|
|
- var textDivsLength = textDivs.length;
|
|
|
|
- var canvas = document.createElement('canvas');
|
|
|
|
- var ctx = canvas.getContext('2d', {alpha: false});
|
|
|
|
-
|
|
|
|
- // 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) {
|
|
|
|
- this._finishRendering();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- 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) {
|
|
|
|
- CustomStyle.setProp('transform' , textDiv, transform);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.textLayerDiv.appendChild(textLayerFrag);
|
|
|
|
- this._finishRendering();
|
|
|
|
- this.updateMatches();
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Renders the text layer.
|
|
* Renders the text layer.
|
|
* @param {number} timeout (optional) if specified, the rendering waits
|
|
* @param {number} timeout (optional) if specified, the rendering waits
|
|
@@ -1610,87 +1496,35 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- if (this.renderTimer) {
|
|
|
|
- clearTimeout(this.renderTimer);
|
|
|
|
- this.renderTimer = null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!timeout) { // Render right away
|
|
|
|
- this.renderLayer();
|
|
|
|
- } else { // Schedule
|
|
|
|
- var self = this;
|
|
|
|
- this.renderTimer = setTimeout(function() {
|
|
|
|
- self.renderLayer();
|
|
|
|
- self.renderTimer = null;
|
|
|
|
- }, timeout);
|
|
|
|
|
|
+ if (this.textLayerRenderTask) {
|
|
|
|
+ this.textLayerRenderTask.cancel();
|
|
|
|
+ this.textLayerRenderTask = null;
|
|
}
|
|
}
|
|
- },
|
|
|
|
|
|
|
|
- appendText: function TextLayerBuilder_appendText(geom, styles) {
|
|
|
|
- var style = styles[geom.fontName];
|
|
|
|
- var textDiv = document.createElement('div');
|
|
|
|
- this.textDivs.push(textDiv);
|
|
|
|
- if (isAllWhitespace(geom.str)) {
|
|
|
|
- textDiv.dataset.isWhitespace = true;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- var tx = PDFJS.Util.transform(this.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 * this.viewport.scale;
|
|
|
|
- } else {
|
|
|
|
- textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ this.textDivs = [];
|
|
|
|
+ var textLayerFrag = document.createDocumentFragment();
|
|
|
|
+ this.textLayerRenderTask = PDFJS.renderTextLayer({
|
|
|
|
+ textContent: this.textContent,
|
|
|
|
+ container: textLayerFrag,
|
|
|
|
+ viewport: this.viewport,
|
|
|
|
+ textDivs: this.textDivs,
|
|
|
|
+ timeout: timeout
|
|
|
|
+ });
|
|
|
|
+ this.textLayerRenderTask.promise.then(function () {
|
|
|
|
+ this.textLayerDiv.appendChild(textLayerFrag);
|
|
|
|
+ this._finishRendering();
|
|
|
|
+ this.updateMatches();
|
|
|
|
+ }.bind(this), function (reason) {
|
|
|
|
+ // canceled or failed to render text layer -- skipping errors
|
|
|
|
+ });
|
|
},
|
|
},
|
|
|
|
|
|
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
|
|
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
|
|
- this.textContent = textContent;
|
|
|
|
-
|
|
|
|
- var textItems = textContent.items;
|
|
|
|
- for (var i = 0, len = textItems.length; i < len; i++) {
|
|
|
|
- this.appendText(textItems[i], textContent.styles);
|
|
|
|
|
|
+ if (this.textLayerRenderTask) {
|
|
|
|
+ this.textLayerRenderTask.cancel();
|
|
|
|
+ this.textLayerRenderTask = null;
|
|
}
|
|
}
|
|
|
|
+ this.textContent = textContent;
|
|
this.divContentDone = true;
|
|
this.divContentDone = true;
|
|
},
|
|
},
|
|
|
|
|
|
@@ -1942,6 +1776,8 @@ DefaultTextLayerFactory.prototype = {
|
|
* @class
|
|
* @class
|
|
*/
|
|
*/
|
|
var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() {
|
|
var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() {
|
|
|
|
+ var CustomStyle = PDFJS.CustomStyle;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* @param {AnnotationsLayerBuilderOptions} options
|
|
* @param {AnnotationsLayerBuilderOptions} options
|
|
* @constructs AnnotationsLayerBuilder
|
|
* @constructs AnnotationsLayerBuilder
|