1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-23 08:38:06 +02:00

Lazy rendering

This commit is contained in:
Artur Adib 2011-10-31 16:49:18 -04:00
parent e7d08e3a98
commit 98f3bab65c
3 changed files with 78 additions and 53 deletions

View file

@ -60,7 +60,7 @@ var CanvasGraphics = (function canvasGraphics() {
// if we execute longer then `kExecutionTime`.
var kExecutionTimeCheck = 500;
function constructor(canvasCtx, objs, textLayer, textScale) {
function constructor(canvasCtx, objs, textLayer) {
this.ctx = canvasCtx;
this.current = new CanvasExtraState();
this.stateStack = [];
@ -70,7 +70,6 @@ var CanvasGraphics = (function canvasGraphics() {
this.ScratchCanvas = ScratchCanvas;
this.objs = objs;
this.textLayer = textLayer;
this.textScale = textScale;
}
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.textDivs = [];
this.textLayerQueue = [];
// Prevent textLayerQueue to be rendered while rendering a new page
if (this.textLayerTimer)
clearTimeout(this.textLayerTimer);
},
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
@ -152,17 +155,37 @@ var CanvasGraphics = (function canvasGraphics() {
},
endDrawing: function canvasGraphicsEndDrawing() {
var self = this;
this.ctx.restore();
// Text selection-specific
var textLayer = this.textLayer;
var textDivs = this.textDivs;
for (var i = 0, length = textDivs.length; i < length; ++i) {
if (textDivs[i].dataset.textLength>1) { // avoid div by zero
textLayer.appendChild(textDivs[i]);
// Adjust div width to match canvas text width
textDivs[i].style.letterSpacing = ((textDivs[i].dataset.canvasWidth - textDivs[i].offsetWidth)/(textDivs[i].dataset.textLength-1)) + 'px';
var textLayer = self.textLayer;
if (textLayer) {
var renderTextLayer = function canvasRenderTextLayer() {
var textDivs = self.textDivs;
for (var i = 0, length = textDivs.length; i < length; ++i) {
if (textDivs[i].dataset.textLength>1) { // avoid div by zero
textLayer.appendChild(textDivs[i]);
// 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 text = {str:'', length:0, canvasWidth:0, spaceWidth:0, geom:{}};
// Text selection-specific
text.spaceWidth = this.current.font.charsToGlyphs(' ')[0].width;
if (!text.spaceWidth>0) {
// Hack (space is sometimes not encoded)
text.spaceWidth = this.current.font.charsToGlyphs('i')[0].width;
}
if (textLayer) {
text.spaceWidth = this.current.font.charsToGlyphs(' ')[0].width;
if (!text.spaceWidth>0) {
// Hack (space is sometimes not encoded)
text.spaceWidth = this.current.font.charsToGlyphs('i')[0].width;
}
// Compute text.geom
// TODO: refactor the series of transformations below, and share it with showText()
ctx.save();
ctx.transform.apply(ctx, current.textMatrix);
ctx.scale(1, -1);
ctx.translate(current.x, -1 * current.y);
ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
ctx.scale(1 / textHScale, 1);
var inv = ctx.mozCurrentTransform;
if (inv) {
var bl = Util.applyTransform([0, 0], inv);
var tr = Util.applyTransform([1, 1], inv);
text.geom.x = bl[0];
text.geom.y = bl[1];
text.geom.xFactor = tr[0] - bl[0];
text.geom.yFactor = tr[1] - bl[1];
// Compute text.geom
// TODO: refactor the series of transformations below, and share it with showText()
ctx.save();
ctx.transform.apply(ctx, current.textMatrix);
ctx.scale(1, -1);
ctx.translate(current.x, -1 * current.y);
ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
ctx.scale(1 / textHScale, 1);
var inv = ctx.mozCurrentTransform;
if (inv) {
var bl = Util.applyTransform([0, 0], inv);
var tr = Util.applyTransform([1, 1], inv);
text.geom.x = bl[0];
text.geom.y = bl[1];
text.geom.xFactor = tr[0] - bl[0];
text.geom.yFactor = tr[1] - bl[1];
}
ctx.restore();
}
ctx.restore();
for (var i = 0; i < arrLength; ++i) {
var e = arr[i];
@ -548,26 +572,28 @@ var CanvasGraphics = (function canvasGraphics() {
var spacingLength = -e * 0.001 * fontSize * textHScale;
current.x += spacingLength;
// Text selection-specific
// Emulate arbitrary spacing via HTML spaces
text.canvasWidth += spacingLength;
if (e<0 && text.spaceWidth>0) { // avoid div by zero
var numFakeSpaces = Math.round(-e / text.spaceWidth);
for (var j = 0; j < numFakeSpaces; ++j)
text.str += '&nbsp;';
text.length += numFakeSpaces>0 ? 1 : 0;
if (textLayer) {
// Emulate precise spacing via HTML spaces
text.canvasWidth += spacingLength;
if (e<0 && text.spaceWidth>0) { // avoid div by zero
var numFakeSpaces = Math.round(-e / text.spaceWidth);
for (var j = 0; j < numFakeSpaces; ++j)
text.str += '&nbsp;';
text.length += numFakeSpaces>0 ? 1 : 0;
}
}
} else if (isString(e)) {
var shownText = this.showText(e);
// Text selection-specific
if (shownText.chars === ' ') {
text.str += '&nbsp;';
} else {
text.str += shownText.chars;
if (textLayer) {
if (shownText.chars === ' ') {
text.str += '&nbsp;';
} else {
text.str += shownText.chars;
}
text.canvasWidth += shownText.width;
text.length += e.length;
}
text.canvasWidth += shownText.width;
text.length += e.length;
} else {
malformed('TJ array element ' + e + ' is not string or num');
}

View file

@ -7,7 +7,7 @@ var globalScope = (typeof window === 'undefined') ? this : window;
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
var verbosity = WARNINGS;
var useWorker = false;
var useWorker = true;
// The global PDFJS object exposes the API
// In production, it will be declared outside a global wrapper
@ -157,7 +157,7 @@ var Page = (function pagePage() {
IRQueue, fonts) {
var self = this;
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 displayContinuation = function pageDisplayContinuation() {
@ -306,11 +306,10 @@ var Page = (function pagePage() {
}
return links;
},
startRendering: function(ctx, callback, textLayer, textScale) {
startRendering: function(ctx, callback, textLayer) {
this.ctx = ctx;
this.callback = callback;
this.textLayer = textLayer;
this.textScale = textScale;
this.startRenderingTime = Date.now();
this.pdf.startRendering(this);