[Pkg-javascript-commits] [pdf.js] 76/116: Refactor PDFThumbnailView to look more similar to PDFPageView

David Prévot taffit at moszumanska.debian.org
Fri Mar 6 16:20:03 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository pdf.js.

commit 878aa76c15ccd54c40adcbf9e59807244fceda69
Author: Jonas Jenwald <jonas.jenwald at gmail.com>
Date:   Sun Jan 25 13:27:11 2015 +0100

    Refactor PDFThumbnailView to look more similar to PDFPageView
    
    This includes an optimization to zero the height and width of existing thumbnail canvases, when they are removed and recreated during rotation of the document. (Credit goes to nnethercote, who initially found this in PR 4920.)
---
 web/pdf_thumbnail_view.js   | 183 ++++++++++++++++++++++++--------------------
 web/pdf_thumbnail_viewer.js |   7 ++
 2 files changed, 108 insertions(+), 82 deletions(-)

diff --git a/web/pdf_thumbnail_view.js b/web/pdf_thumbnail_view.js
index bf8c2d1..26a2a52 100644
--- a/web/pdf_thumbnail_view.js
+++ b/web/pdf_thumbnail_view.js
@@ -18,7 +18,8 @@
 
 'use strict';
 
-var THUMBNAIL_CANVAS_BORDER_WIDTH = 1;
+var THUMBNAIL_WIDTH = 98; // px
+var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
 
 /**
  * @typedef {Object} PDFThumbnailViewOptions
@@ -43,9 +44,8 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
     tempCanvas.width = width;
     tempCanvas.height = height;
 
-    // Since this is a temporary canvas, we need to fill
-    // the canvas with a white background ourselves.
-    // |getPageDrawContext| uses CSS rules for this.
+    // Since this is a temporary canvas, we need to fill the canvas with a white
+    // background ourselves. |_getPageDrawContext| uses CSS rules for this.
     var ctx = tempCanvas.getContext('2d');
     ctx.save();
     ctx.fillStyle = 'rgb(255, 255, 255)';
@@ -65,32 +65,41 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
     var linkService = options.linkService;
     var renderingQueue = options.renderingQueue;
 
-    var anchor = document.createElement('a');
-    anchor.href = linkService.getAnchorUrl('#page=' + id);
-    anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
-    anchor.onclick = function stopNavigation() {
-      linkService.page = id;
-      return false;
-    };
+    this.id = id;
+    this.renderingId = 'thumbnail' + id;
 
-    this.pdfPage = undefined;
+    this.pdfPage = null;
+    this.rotation = 0;
     this.viewport = defaultViewport;
     this.pdfPageRotate = defaultViewport.rotation;
 
-    this.rotation = 0;
+    this.linkService = linkService;
+    this.renderingQueue = renderingQueue;
+
+    this.hasImage = false;
+    this.resume = null;
+    this.renderingState = RenderingStates.INITIAL;
+
     this.pageWidth = this.viewport.width;
     this.pageHeight = this.viewport.height;
     this.pageRatio = this.pageWidth / this.pageHeight;
-    this.id = id;
-    this.renderingId = 'thumbnail' + id;
 
-    this.canvasWidth = 98;
+    this.canvasWidth = THUMBNAIL_WIDTH;
     this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0;
     this.scale = this.canvasWidth / this.pageWidth;
 
-    var div = this.el = document.createElement('div');
+    var anchor = document.createElement('a');
+    anchor.href = linkService.getAnchorUrl('#page=' + id);
+    anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
+    anchor.onclick = function stopNavigation() {
+      linkService.page = id;
+      return false;
+    };
+
+    var div = document.createElement('div');
     div.id = 'thumbnailContainer' + id;
     div.className = 'thumbnail';
+    this.el = div; // TODO: replace 'el' property usage.
     this.div = div;
 
     if (id === 1) {
@@ -101,19 +110,14 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
 
     var ring = document.createElement('div');
     ring.className = 'thumbnailSelectionRing';
-    ring.style.width =
-      this.canvasWidth + 2 * THUMBNAIL_CANVAS_BORDER_WIDTH + 'px';
-    ring.style.height =
-      this.canvasHeight + 2 * THUMBNAIL_CANVAS_BORDER_WIDTH + 'px';
+    var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
+    ring.style.width = this.canvasWidth + borderAdjustment + 'px';
+    ring.style.height = this.canvasHeight + borderAdjustment + 'px';
     this.ring = ring;
 
     div.appendChild(ring);
     anchor.appendChild(div);
     container.appendChild(anchor);
-
-    this.hasImage = false;
-    this.renderingState = RenderingStates.INITIAL;
-    this.renderingQueue = renderingQueue;
   }
 
   PDFThumbnailView.prototype = {
@@ -122,18 +126,14 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
       this.pdfPageRotate = pdfPage.rotate;
       var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
       this.viewport = pdfPage.getViewport(1, totalRotation);
-      this.update();
+      this.reset();
     },
 
-    update: function PDFThumbnailView_update(rotation) {
-      if (rotation !== undefined) {
-        this.rotation = rotation;
-      }
-      var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
-      this.viewport = this.viewport.clone({
-        scale: 1,
-        rotation: totalRotation
-      });
+    reset: function PDFThumbnailView_reset() {
+      this.hasImage = false;
+      this.resume = null;
+      this.renderingState = RenderingStates.INITIAL;
+
       this.pageWidth = this.viewport.width;
       this.pageHeight = this.viewport.height;
       this.pageRatio = this.pageWidth / this.pageHeight;
@@ -142,20 +142,42 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
       this.scale = (this.canvasWidth / this.pageWidth);
 
       this.div.removeAttribute('data-loaded');
-      this.ring.textContent = '';
-      this.ring.style.width =
-        this.canvasWidth + 2 * THUMBNAIL_CANVAS_BORDER_WIDTH + 'px';
-      this.ring.style.height =
-        this.canvasHeight + 2 * THUMBNAIL_CANVAS_BORDER_WIDTH + 'px';
+      var ring = this.ring;
+      var childNodes = ring.childNodes;
+      for (var i = childNodes.length - 1; i >= 0; i--) {
+        ring.removeChild(childNodes[i]);
+      }
+      var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
+      ring.style.width = this.canvasWidth + borderAdjustment + 'px';
+      ring.style.height = this.canvasHeight + borderAdjustment + 'px';
+
+      if (this.canvas) {
+        // Zeroing the width and height causes Firefox to release graphics
+        // resources immediately, which can greatly reduce memory consumption.
+        this.canvas.width = 0;
+        this.canvas.height = 0;
+        delete this.canvas;
+      }
+    },
 
-      this.hasImage = false;
-      this.renderingState = RenderingStates.INITIAL;
-      this.resume = null;
+    update: function PDFThumbnailView_update(rotation) {
+      if (typeof rotation !== 'undefined') {
+        this.rotation = rotation;
+      }
+      var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+      this.viewport = this.viewport.clone({
+        scale: 1,
+        rotation: totalRotation
+      });
+      this.reset();
     },
 
-    getPageDrawContext: function PDFThumbnailView_getPageDrawContext() {
+    /**
+     * @private
+     */
+    _getPageDrawContext: function PDFThumbnailView_getPageDrawContext() {
       var canvas = document.createElement('canvas');
-      canvas.id = 'thumbnail' + this.id;
+      canvas.id = this.renderingId;
 
       canvas.width = this.canvasWidth;
       canvas.height = this.canvasHeight;
@@ -163,8 +185,8 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
       canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
         {page: this.id}, 'Thumbnail of Page {{page}}'));
 
+      this.canvas = canvas;
       this.div.setAttribute('data-loaded', true);
-
       this.ring.appendChild(canvas);
 
       return canvas.getContext('2d');
@@ -178,25 +200,25 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
       if (this.renderingState !== RenderingStates.INITIAL) {
         console.error('Must be in new state before drawing');
       }
-
-      this.renderingState = RenderingStates.RUNNING;
       if (this.hasImage) {
         return Promise.resolve(undefined);
       }
+      this.hasImage = true;
+      this.renderingState = RenderingStates.RUNNING;
 
       var resolveRenderPromise, rejectRenderPromise;
       var promise = new Promise(function (resolve, reject) {
-          resolveRenderPromise = resolve;
-          rejectRenderPromise = reject;
-        });
+        resolveRenderPromise = resolve;
+        rejectRenderPromise = reject;
+      });
 
       var self = this;
-      var ctx = this.getPageDrawContext();
+      var ctx = this._getPageDrawContext();
       var drawViewport = this.viewport.clone({ scale: this.scale });
       var renderContext = {
         canvasContext: ctx,
         viewport: drawViewport,
-        continueCallback: function(cont) {
+        continueCallback: function renderContinueCallback(cont) {
           if (!self.renderingQueue.isHighestPriority(self)) {
             self.renderingState = RenderingStates.PAUSED;
             self.resume = function() {
@@ -218,7 +240,6 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
           rejectRenderPromise(error);
         }
       );
-      this.hasImage = true;
       return promise;
     },
 
@@ -230,41 +251,39 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
       if (!this.pdfPage) {
         this.setPdfPage(pageView.pdfPage);
       }
+      this.hasImage = true;
       this.renderingState = RenderingStates.FINISHED;
-      var ctx = this.getPageDrawContext();
+
+      var ctx = this._getPageDrawContext();
       var canvas = ctx.canvas;
 
       if (img.width <= 2 * canvas.width) {
         ctx.drawImage(img, 0, 0, img.width, img.height,
                       0, 0, canvas.width, canvas.height);
-      } else {
-        // drawImage does an awful job of rescaling the image,
-        // doing it gradually.
-        var MAX_NUM_SCALING_STEPS = 3;
-        var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
-        var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
-        var reducedImage = getTempCanvas(reducedWidth, reducedHeight);
-        var reducedImageCtx = reducedImage.getContext('2d');
-
-        while (reducedWidth > img.width || reducedHeight > img.height) {
-          reducedWidth >>= 1;
-          reducedHeight >>= 1;
-        }
-        reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
-                                  0, 0, reducedWidth, reducedHeight);
-        while (reducedWidth > 2 * canvas.width) {
-          reducedImageCtx.drawImage(reducedImage,
-                                    0, 0, reducedWidth, reducedHeight,
-                                    0, 0,
-                                    reducedWidth >> 1, reducedHeight >> 1);
-          reducedWidth >>= 1;
-          reducedHeight >>= 1;
-        }
-        ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
-                      0, 0, canvas.width, canvas.height);
+        return;
       }
-
-      this.hasImage = true;
+      // drawImage does an awful job of rescaling the image, doing it gradually.
+      var MAX_NUM_SCALING_STEPS = 3;
+      var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
+      var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
+      var reducedImage = getTempCanvas(reducedWidth, reducedHeight);
+      var reducedImageCtx = reducedImage.getContext('2d');
+
+      while (reducedWidth > img.width || reducedHeight > img.height) {
+        reducedWidth >>= 1;
+        reducedHeight >>= 1;
+      }
+      reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
+                                0, 0, reducedWidth, reducedHeight);
+      while (reducedWidth > 2 * canvas.width) {
+        reducedImageCtx.drawImage(reducedImage,
+                                  0, 0, reducedWidth, reducedHeight,
+                                  0, 0, reducedWidth >> 1, reducedHeight >> 1);
+        reducedWidth >>= 1;
+        reducedHeight >>= 1;
+      }
+      ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
+                    0, 0, canvas.width, canvas.height);
     }
   };
 
diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js
index db464fc..170fa19 100644
--- a/web/pdf_thumbnail_viewer.js
+++ b/web/pdf_thumbnail_viewer.js
@@ -104,6 +104,13 @@ var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
     },
 
     cleanup: function PDFThumbnailViewer_cleanup() {
+      var tempCanvas = PDFThumbnailView.tempImageCache;
+      if (tempCanvas) {
+        // Zeroing the width and height causes Firefox to release graphics
+        // resources immediately, which can greatly reduce memory consumption.
+        tempCanvas.width = 0;
+        tempCanvas.height = 0;
+      }
       PDFThumbnailView.tempImageCache = null;
     },
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git



More information about the Pkg-javascript-commits mailing list