Bug 779618 - [Page Thumbnails] make tabbrowser use the thumbnail service; r=jaws
authorTim Taubert <ttaubert@mozilla.com>
Thu, 09 Aug 2012 08:46:17 +0200
changeset 101663 3411e98278d67e024c848d8e360f991d45b5fc4a
parent 101662 0c3dd2229961e79beda648fb8191f7a530b12a1a
child 101664 c7bc29d4de78aeaf4237d38896ca61d898f9909d
push id991
push userttaubert@mozilla.com
push dateThu, 09 Aug 2012 06:46:39 +0000
treeherderfx-team@3411e98278d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs779618
milestone17.0a1
Bug 779618 - [Page Thumbnails] make tabbrowser use the thumbnail service; r=jaws
browser/base/content/browser-thumbnails.js
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/components/thumbnails/PageThumbs.jsm
browser/components/thumbnails/test/head.js
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -21,21 +21,16 @@ let gBrowserThumbnails = {
   _sslDiskCacheEnabled: null,
 
   /**
    * Map of capture() timeouts assigned to their browsers.
    */
   _timeouts: null,
 
   /**
-   * Cache for the PageThumbs module.
-   */
-  _pageThumbs: null,
-
-  /**
    * List of tab events we want to listen for.
    */
   _tabEvents: ["TabClose", "TabSelect"],
 
   init: function Thumbnails_init() {
     try {
       if (Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled"))
         return;
@@ -47,19 +42,16 @@ let gBrowserThumbnails = {
     this._sslDiskCacheEnabled =
       Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.addEventListener(aEvent, this, false);
     }, this);
 
     this._timeouts = new WeakMap();
-
-    XPCOMUtils.defineLazyModuleGetter(this, "_pageThumbs",
-      "resource:///modules/PageThumbs.jsm", "PageThumbs");
   },
 
   uninit: function Thumbnails_uninit() {
     gBrowser.removeTabsProgressListener(this);
     Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.removeEventListener(aEvent, this, false);
@@ -95,17 +87,17 @@ let gBrowserThumbnails = {
                                                    aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
       this._delayedCapture(aBrowser);
   },
 
   _capture: function Thumbnails_capture(aBrowser) {
     if (this._shouldCapture(aBrowser))
-      this._pageThumbs.captureAndStore(aBrowser);
+      PageThumbs.captureAndStore(aBrowser);
   },
 
   _delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
     if (this._timeouts.has(aBrowser))
       clearTimeout(this._timeouts.get(aBrowser));
     else
       aBrowser.addEventListener("scroll", this, true);
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -135,16 +135,19 @@ XPCOMUtils.defineLazyGetter(this, "Tilt"
 });
 
 XPCOMUtils.defineLazyGetter(this, "Social", function() {
   let tmp = {};
   Cu.import("resource:///modules/Social.jsm", tmp);
   return tmp.Social;
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
+  "resource:///modules/PageThumbs.jsm");
+
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
   let tmp = {};
   Cu.import("resource://gre/modules/SafeBrowsing.jsm", tmp);
   return tmp.SafeBrowsing;
 });
 #endif
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3402,17 +3402,30 @@
         // We must not set text/x-moz-url or text/plain data here,
         // otherwise trying to deatch the tab by dropping it on the desktop
         // may result in an "internet shortcut"
         dt.mozSetDataAt("text/x-moz-text-internal", spec, 0);
 
         // Set the cursor to an arrow during tab drags.
         dt.mozCursor = "default";
 
-        let canvas = tabPreviews.capture(tab, false);
+        // Create a canvas to which we capture the current tab.
+        let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+        canvas.mozOpaque = true;
+
+        // We want drag images to be about 1/6th of the available screen width.
+        const widthFactor = 0.1739; // 1:5.75 inverse
+        canvas.width = Math.ceil(screen.availWidth * widthFactor);
+
+        // Maintain a 16:9 aspect ratio for drag images.
+        const aspectRatio = 0.5625; // 16:9 inverse
+        canvas.height = Math.round(canvas.width * aspectRatio);
+
+        let browser = tab.linkedBrowser;
+        PageThumbs.captureToCanvas(browser.contentWindow, canvas);
         dt.setDragImage(canvas, 0, 0);
 
         // _dragOffsetX/Y give the coordinates that the mouse should be
         // positioned relative to the corner of the new window created upon
         // dragend such that the mouse appears to have the same position
         // relative to the corner of the dragged tab.
         function clientX(ele) ele.getBoundingClientRect().left;
         let tabOffsetX = clientX(tab) -
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -111,43 +111,53 @@ let PageThumbs = {
    *                  captured. The first argument will be the data stream
    *                  containing the image data.
    */
   capture: function PageThumbs_capture(aWindow, aCallback) {
     if (!this._prefEnabled()) {
       return;
     }
 
-    let telemetryCaptureTime = new Date();
-    let [sw, sh, scale] = this._determineCropSize(aWindow);
+    let canvas = this._createCanvas();
+    this.captureToCanvas(aWindow, canvas);
 
-    let canvas = this._createCanvas();
-    let ctx = canvas.getContext("2d");
+    // Fetch the canvas data on the next event loop tick so that we allow
+    // some event processing in between drawing to the canvas and encoding
+    // its data. We want to block the UI as short as possible. See bug 744100.
+    Services.tm.currentThread.dispatch(function () {
+      canvas.mozFetchAsStream(aCallback, this.contentType);
+    }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
+  /**
+   * Captures a thumbnail from a given window and draws it to the given canvas.
+   * @param aWindow The DOM window to capture a thumbnail from.
+   * @param aCanvas The canvas to draw to.
+   */
+  captureToCanvas: function PageThumbs_captureToCanvas(aWindow, aCanvas) {
+    let telemetryCaptureTime = new Date();
+    let [sw, sh, scale] = this._determineCropSize(aWindow, aCanvas);
+    let ctx = aCanvas.getContext("2d");
 
     // Scale the canvas accordingly.
     ctx.scale(scale, scale);
 
     try {
       // Draw the window contents to the canvas.
       ctx.drawWindow(aWindow, 0, 0, sw, sh, THUMBNAIL_BG_COLOR,
                      ctx.DRAWWINDOW_DO_NOT_FLUSH);
     } catch (e) {
       // We couldn't draw to the canvas for some reason.
     }
 
     let telemetry = Services.telemetry;
     telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
       .add(new Date() - telemetryCaptureTime);
 
-    // Fetch the canvas data on the next event loop tick so that we allow
-    // some event processing in between drawing to the canvas and encoding
-    // its data. We want to block the UI as short as possible. See bug 744100.
-    Services.tm.currentThread.dispatch(function () {
-      canvas.mozFetchAsStream(aCallback, this.contentType);
-    }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
+    return aCanvas;
   },
 
   /**
    * Captures a thumbnail for the given browser and stores it to the cache.
    * @param aBrowser The browser to capture a thumbnail for.
    * @param aCallback The function to be called when finished (optional).
    */
   captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
@@ -188,23 +198,24 @@ let PageThumbs = {
 
       PageThumbsStorage.write(url, aInputStream, finish);
     });
   },
 
   /**
    * Determines the crop size for a given content window.
    * @param aWindow The content window.
+   * @param aCanvas The target canvas.
    * @return An array containing width, height and scale.
    */
-  _determineCropSize: function PageThumbs_determineCropSize(aWindow) {
+  _determineCropSize: function PageThumbs_determineCropSize(aWindow, aCanvas) {
     let sw = aWindow.innerWidth;
     let sh = aWindow.innerHeight;
 
-    let [thumbnailWidth, thumbnailHeight] = this._getThumbnailSize();
+    let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas;
     let scale = Math.max(thumbnailWidth / sw, thumbnailHeight / sh);
     let scaledWidth = sw * scale;
     let scaledHeight = sh * scale;
 
     if (scaledHeight > thumbnailHeight)
       sh -= Math.floor(Math.abs(scaledHeight - thumbnailHeight) * scale);
 
     if (scaledWidth > thumbnailWidth)
--- a/browser/components/thumbnails/test/head.js
+++ b/browser/components/thumbnails/test/head.js
@@ -6,18 +6,16 @@ Cu.import("resource:///modules/PageThumb
 let PageThumbs = tmp.PageThumbs;
 let PageThumbsStorage = tmp.PageThumbsStorage;
 
 registerCleanupFunction(function () {
   while (gBrowser.tabs.length > 1)
     gBrowser.removeTab(gBrowser.tabs[1]);
 });
 
-let cachedXULDocument;
-
 /**
  * Provide the default test function to start our test runner.
  */
 function test() {
   TestRunner.run();
 }
 
 /**