|
|
@ -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) { |
|
|
|
if (this.textLayerRenderTask) { |
|
|
|
clearTimeout(this.renderTimer); |
|
|
|
this.textLayerRenderTask.cancel(); |
|
|
|
this.renderTimer = null; |
|
|
|
this.textLayerRenderTask = null; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!timeout) { // Render right away
|
|
|
|
|
|
|
|
this.renderLayer(); |
|
|
|
|
|
|
|
} else { // Schedule
|
|
|
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
this.renderTimer = setTimeout(function() { |
|
|
|
|
|
|
|
self.renderLayer(); |
|
|
|
|
|
|
|
self.renderTimer = null; |
|
|
|
|
|
|
|
}, timeout); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
appendText: function TextLayerBuilder_appendText(geom, styles) { |
|
|
|
this.textDivs = []; |
|
|
|
var style = styles[geom.fontName]; |
|
|
|
var textLayerFrag = document.createDocumentFragment(); |
|
|
|
var textDiv = document.createElement('div'); |
|
|
|
this.textLayerRenderTask = PDFJS.renderTextLayer({ |
|
|
|
this.textDivs.push(textDiv); |
|
|
|
textContent: this.textContent, |
|
|
|
if (isAllWhitespace(geom.str)) { |
|
|
|
container: textLayerFrag, |
|
|
|
textDiv.dataset.isWhitespace = true; |
|
|
|
viewport: this.viewport, |
|
|
|
return; |
|
|
|
textDivs: this.textDivs, |
|
|
|
} |
|
|
|
timeout: timeout |
|
|
|
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform); |
|
|
|
}); |
|
|
|
var angle = Math.atan2(tx[1], tx[0]); |
|
|
|
this.textLayerRenderTask.promise.then(function () { |
|
|
|
if (style.vertical) { |
|
|
|
this.textLayerDiv.appendChild(textLayerFrag); |
|
|
|
angle += Math.PI / 2; |
|
|
|
this._finishRendering(); |
|
|
|
} |
|
|
|
this.updateMatches(); |
|
|
|
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3])); |
|
|
|
}.bind(this), function (reason) { |
|
|
|
var fontAscent = fontHeight; |
|
|
|
// canceled or failed to render text layer -- skipping errors
|
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
setTextContent: function TextLayerBuilder_setTextContent(textContent) { |
|
|
|
setTextContent: function TextLayerBuilder_setTextContent(textContent) { |
|
|
|
this.textContent = textContent; |
|
|
|
if (this.textLayerRenderTask) { |
|
|
|
|
|
|
|
this.textLayerRenderTask.cancel(); |
|
|
|
var textItems = textContent.items; |
|
|
|
this.textLayerRenderTask = null; |
|
|
|
for (var i = 0, len = textItems.length; i < len; i++) { |
|
|
|
|
|
|
|
this.appendText(textItems[i], textContent.styles); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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 |
|
|
|