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 101936 3411e98278d67e024c848d8e360f991d45b5fc4a
parent 101935 0c3dd2229961e79beda648fb8191f7a530b12a1a
child 101937 c7bc29d4de78aeaf4237d38896ca61d898f9909d
push id23256
push userttaubert@mozilla.com
push dateThu, 09 Aug 2012 18:49:22 +0000
treeherdermozilla-central@4770bca01046 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs779618
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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();
 }
 
 /**