Lazy rendering
This commit is contained in:
parent
e7d08e3a98
commit
98f3bab65c
122
src/canvas.js
122
src/canvas.js
@ -60,7 +60,7 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
// if we execute longer then `kExecutionTime`.
|
// if we execute longer then `kExecutionTime`.
|
||||||
var kExecutionTimeCheck = 500;
|
var kExecutionTimeCheck = 500;
|
||||||
|
|
||||||
function constructor(canvasCtx, objs, textLayer, textScale) {
|
function constructor(canvasCtx, objs, textLayer) {
|
||||||
this.ctx = canvasCtx;
|
this.ctx = canvasCtx;
|
||||||
this.current = new CanvasExtraState();
|
this.current = new CanvasExtraState();
|
||||||
this.stateStack = [];
|
this.stateStack = [];
|
||||||
@ -70,7 +70,6 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
this.ScratchCanvas = ScratchCanvas;
|
this.ScratchCanvas = ScratchCanvas;
|
||||||
this.objs = objs;
|
this.objs = objs;
|
||||||
this.textLayer = textLayer;
|
this.textLayer = textLayer;
|
||||||
this.textScale = textScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
||||||
@ -98,6 +97,10 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
}
|
}
|
||||||
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
||||||
this.textDivs = [];
|
this.textDivs = [];
|
||||||
|
this.textLayerQueue = [];
|
||||||
|
// Prevent textLayerQueue to be rendered while rendering a new page
|
||||||
|
if (this.textLayerTimer)
|
||||||
|
clearTimeout(this.textLayerTimer);
|
||||||
},
|
},
|
||||||
|
|
||||||
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
||||||
@ -152,17 +155,37 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
endDrawing: function canvasGraphicsEndDrawing() {
|
endDrawing: function canvasGraphicsEndDrawing() {
|
||||||
|
var self = this;
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
|
|
||||||
// Text selection-specific
|
var textLayer = self.textLayer;
|
||||||
var textLayer = this.textLayer;
|
if (textLayer) {
|
||||||
var textDivs = this.textDivs;
|
var renderTextLayer = function canvasRenderTextLayer() {
|
||||||
for (var i = 0, length = textDivs.length; i < length; ++i) {
|
var textDivs = self.textDivs;
|
||||||
if (textDivs[i].dataset.textLength>1) { // avoid div by zero
|
for (var i = 0, length = textDivs.length; i < length; ++i) {
|
||||||
textLayer.appendChild(textDivs[i]);
|
if (textDivs[i].dataset.textLength>1) { // avoid div by zero
|
||||||
// Adjust div width to match canvas text width
|
textLayer.appendChild(textDivs[i]);
|
||||||
textDivs[i].style.letterSpacing = ((textDivs[i].dataset.canvasWidth - textDivs[i].offsetWidth)/(textDivs[i].dataset.textLength-1)) + 'px';
|
// Adjust div width (via letterSpacing) to match canvas text
|
||||||
|
// Due to the .offsetWidth calls, this is slow
|
||||||
|
textDivs[i].style.letterSpacing =
|
||||||
|
((textDivs[i].dataset.canvasWidth
|
||||||
|
- textDivs[i].offsetWidth)/(textDivs[i].dataset.textLength-1))
|
||||||
|
+ 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var textLayerQueue = self.textLayerQueue;
|
||||||
|
textLayerQueue.push(renderTextLayer);
|
||||||
|
|
||||||
|
// Lazy textLayer rendering (to prevent UI hangs)
|
||||||
|
// Only render queue if activity has stopped, where "no activity" ==
|
||||||
|
// "no beginDrawing() calls in the last N ms"
|
||||||
|
self.textLayerTimer = setTimeout(function renderTextLayerQueue(){
|
||||||
|
// Render most recent (==most relevant) layers first
|
||||||
|
for (var i=textLayerQueue.length-1; i>=0; i--) {
|
||||||
|
textLayerQueue.pop().call();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -516,31 +539,32 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
var font = current.font;
|
var font = current.font;
|
||||||
var text = {str:'', length:0, canvasWidth:0, spaceWidth:0, geom:{}};
|
var text = {str:'', length:0, canvasWidth:0, spaceWidth:0, geom:{}};
|
||||||
|
|
||||||
// Text selection-specific
|
if (textLayer) {
|
||||||
text.spaceWidth = this.current.font.charsToGlyphs(' ')[0].width;
|
text.spaceWidth = this.current.font.charsToGlyphs(' ')[0].width;
|
||||||
if (!text.spaceWidth>0) {
|
if (!text.spaceWidth>0) {
|
||||||
// Hack (space is sometimes not encoded)
|
// Hack (space is sometimes not encoded)
|
||||||
text.spaceWidth = this.current.font.charsToGlyphs('i')[0].width;
|
text.spaceWidth = this.current.font.charsToGlyphs('i')[0].width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute text.geom
|
// Compute text.geom
|
||||||
// TODO: refactor the series of transformations below, and share it with showText()
|
// TODO: refactor the series of transformations below, and share it with showText()
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
ctx.scale(1, -1);
|
ctx.scale(1, -1);
|
||||||
ctx.translate(current.x, -1 * current.y);
|
ctx.translate(current.x, -1 * current.y);
|
||||||
ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
|
ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
|
||||||
ctx.scale(1 / textHScale, 1);
|
ctx.scale(1 / textHScale, 1);
|
||||||
var inv = ctx.mozCurrentTransform;
|
var inv = ctx.mozCurrentTransform;
|
||||||
if (inv) {
|
if (inv) {
|
||||||
var bl = Util.applyTransform([0, 0], inv);
|
var bl = Util.applyTransform([0, 0], inv);
|
||||||
var tr = Util.applyTransform([1, 1], inv);
|
var tr = Util.applyTransform([1, 1], inv);
|
||||||
text.geom.x = bl[0];
|
text.geom.x = bl[0];
|
||||||
text.geom.y = bl[1];
|
text.geom.y = bl[1];
|
||||||
text.geom.xFactor = tr[0] - bl[0];
|
text.geom.xFactor = tr[0] - bl[0];
|
||||||
text.geom.yFactor = tr[1] - bl[1];
|
text.geom.yFactor = tr[1] - bl[1];
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
for (var i = 0; i < arrLength; ++i) {
|
for (var i = 0; i < arrLength; ++i) {
|
||||||
var e = arr[i];
|
var e = arr[i];
|
||||||
@ -548,26 +572,28 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
var spacingLength = -e * 0.001 * fontSize * textHScale;
|
var spacingLength = -e * 0.001 * fontSize * textHScale;
|
||||||
current.x += spacingLength;
|
current.x += spacingLength;
|
||||||
|
|
||||||
// Text selection-specific
|
if (textLayer) {
|
||||||
// Emulate arbitrary spacing via HTML spaces
|
// Emulate precise spacing via HTML spaces
|
||||||
text.canvasWidth += spacingLength;
|
text.canvasWidth += spacingLength;
|
||||||
if (e<0 && text.spaceWidth>0) { // avoid div by zero
|
if (e<0 && text.spaceWidth>0) { // avoid div by zero
|
||||||
var numFakeSpaces = Math.round(-e / text.spaceWidth);
|
var numFakeSpaces = Math.round(-e / text.spaceWidth);
|
||||||
for (var j = 0; j < numFakeSpaces; ++j)
|
for (var j = 0; j < numFakeSpaces; ++j)
|
||||||
text.str += ' ';
|
text.str += ' ';
|
||||||
text.length += numFakeSpaces>0 ? 1 : 0;
|
text.length += numFakeSpaces>0 ? 1 : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (isString(e)) {
|
} else if (isString(e)) {
|
||||||
var shownText = this.showText(e);
|
var shownText = this.showText(e);
|
||||||
|
|
||||||
// Text selection-specific
|
if (textLayer) {
|
||||||
if (shownText.chars === ' ') {
|
if (shownText.chars === ' ') {
|
||||||
text.str += ' ';
|
text.str += ' ';
|
||||||
} else {
|
} else {
|
||||||
text.str += shownText.chars;
|
text.str += shownText.chars;
|
||||||
|
}
|
||||||
|
text.canvasWidth += shownText.width;
|
||||||
|
text.length += e.length;
|
||||||
}
|
}
|
||||||
text.canvasWidth += shownText.width;
|
|
||||||
text.length += e.length;
|
|
||||||
} else {
|
} else {
|
||||||
malformed('TJ array element ' + e + ' is not string or num');
|
malformed('TJ array element ' + e + ' is not string or num');
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ var globalScope = (typeof window === 'undefined') ? this : window;
|
|||||||
|
|
||||||
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
|
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
|
||||||
var verbosity = WARNINGS;
|
var verbosity = WARNINGS;
|
||||||
var useWorker = false;
|
var useWorker = true;
|
||||||
|
|
||||||
// The global PDFJS object exposes the API
|
// The global PDFJS object exposes the API
|
||||||
// In production, it will be declared outside a global wrapper
|
// In production, it will be declared outside a global wrapper
|
||||||
@ -157,7 +157,7 @@ var Page = (function pagePage() {
|
|||||||
IRQueue, fonts) {
|
IRQueue, fonts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.IRQueue = IRQueue;
|
this.IRQueue = IRQueue;
|
||||||
var gfx = new CanvasGraphics(this.ctx, this.objs, this.textLayer, this.textScale);
|
var gfx = new CanvasGraphics(this.ctx, this.objs, this.textLayer);
|
||||||
var startTime = Date.now();
|
var startTime = Date.now();
|
||||||
|
|
||||||
var displayContinuation = function pageDisplayContinuation() {
|
var displayContinuation = function pageDisplayContinuation() {
|
||||||
@ -306,11 +306,10 @@ var Page = (function pagePage() {
|
|||||||
}
|
}
|
||||||
return links;
|
return links;
|
||||||
},
|
},
|
||||||
startRendering: function(ctx, callback, textLayer, textScale) {
|
startRendering: function(ctx, callback, textLayer) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.textLayer = textLayer;
|
this.textLayer = textLayer;
|
||||||
this.textScale = textScale;
|
|
||||||
|
|
||||||
this.startRenderingTime = Date.now();
|
this.startRenderingTime = Date.now();
|
||||||
this.pdf.startRendering(this);
|
this.pdf.startRendering(this);
|
||||||
|
@ -491,7 +491,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
ctx.translate(-this.x * scale, -this.y * scale);
|
ctx.translate(-this.x * scale, -this.y * scale);
|
||||||
|
|
||||||
stats.begin = Date.now();
|
stats.begin = Date.now();
|
||||||
this.content.startRendering(ctx, this.updateStats, textLayer, scale);
|
this.content.startRendering(ctx, this.updateStats, textLayer);
|
||||||
|
|
||||||
setupLinks(this.content, this.scale);
|
setupLinks(this.content, this.scale);
|
||||||
div.setAttribute('data-loaded', true);
|
div.setAttribute('data-loaded', true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user