]> git.parisson.com Git - pdf.js.git/commitdiff
Lazy rendering
authorArtur Adib <arturadib@gmail.com>
Mon, 31 Oct 2011 20:49:18 +0000 (16:49 -0400)
committerArtur Adib <arturadib@gmail.com>
Mon, 31 Oct 2011 20:49:18 +0000 (16:49 -0400)
src/canvas.js
src/core.js
web/viewer.js

index d771fa15e8622dda1443e390c329f12257f3dabb..d5db79446df159f934d393de502f848b896f7180 100644 (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');
         }
index 7e7bb6ea88ad5060eb467c9911816f21fd0a3739..4313959a8243922711bafb335954a4ded01d9b71 100644 (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);
index 523b7dc56820999fe71f1839e1cb8d412a254f1a..d8a59e6514f0bf487952326e15936ec86f20fc8a 100644 (file)
@@ -491,7 +491,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
     ctx.translate(-this.x * scale, -this.y * scale);
 
     stats.begin = Date.now();
-    this.content.startRendering(ctx, this.updateStats, textLayer, scale);
+    this.content.startRendering(ctx, this.updateStats, textLayer);
 
     setupLinks(this.content, this.scale);
     div.setAttribute('data-loaded', true);