Bug 831440 - Switch back to static thumbnails for the tab bar
authorRodrigo Silveira <rsilveira@mozilla.com>
Wed, 07 Aug 2013 10:51:43 -0700
changeset 154753 a009409e3ab28026aac19ccd6061a5abb1ce20a7
parent 154752 503c914e9ffea950839afbdc1403ef9310ae3b82
child 154754 2f24ae3aaa4ed5d27c547b2fd978b86879b977cd
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs831440
milestone26.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 831440 - Switch back to static thumbnails for the tab bar
browser/metro/base/content/WebProgress.js
browser/metro/base/content/bindings/tabs.xml
browser/metro/base/content/browser.js
browser/metro/theme/browser.css
--- a/browser/metro/base/content/WebProgress.js
+++ b/browser/metro/base/content/WebProgress.js
@@ -129,17 +129,16 @@ const WebProgress = {
     let browser = aTab.browser;
 
     aTab._firstPaint = false;
 
     browser.messageManager.addMessageListener("Browser:FirstPaint", function firstPaintListener(aMessage) {
       browser.messageManager.removeMessageListener(aMessage.name, arguments.callee);
       aTab._firstPaint = true;
       aTab.scrolledAreaChanged(true);
-      aTab.updateThumbnailSource();
     });
   },
 
   _networkStart: function _networkStart(aJson, aTab) {
     aTab.startLoading();
 
     if (aTab == Browser.selectedTab) {
       // NO_STARTUI_VISIBILITY since the current uri for the tab has not
--- a/browser/metro/base/content/bindings/tabs.xml
+++ b/browser/metro/base/content/bindings/tabs.xml
@@ -12,17 +12,17 @@
     xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:html="http://www.w3.org/1999/xhtml"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="documenttab">
     <content observes="bcast_urlbarState">
       <xul:stack class="documenttab-container">
-        <xul:box anonid="thumbnail" class="documenttab-thumbnail" />
+        <html:canvas anonid="thumbnail-canvas" class="documenttab-thumbnail" />
         <xul:image anonid="favicon" class="documenttab-favicon"
                    observes="bcast_urlbarState" width="26" height="26"/>
 
         <xul:label anonid="title" class="documenttab-title" bottom="0" start="0" end="0" crop="end"/>
         <xul:box anonid="selection" class="documenttab-crop"/>
         <xul:box anonid="selection" class="documenttab-selection"/>
         <xul:button anonid="close" class="documenttab-close" observes="bcast_urlbarState" end="0" top="0"
                     onclick="event.stopPropagation(); document.getBindingParent(this)._onClose()"
@@ -31,22 +31,29 @@
     </content>
 
     <handlers>
       <handler event="click" clickcount="1" action="this._onClick()"/>
       <handler event="dblclick" action="this._onDoubleClick(); event.stopPropagation();"/>
     </handlers>
 
     <implementation>
-      <field name="_thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
+      <field name="thumbnailCanvas" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail-canvas");</field>
       <field name="_close" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close");</field>
       <field name="_title" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "title");</field>
       <field name="_favicon" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "favicon");</field>
       <field name="_container" readonly="true">this.parentNode;</field>
 
+      <constructor>
+        <![CDATA[
+          this.thumbnailCanvas.mozOpaque = true;
+          this.thumbnailCanvas.mozImageSmoothingEnabled = true;
+        ]]>
+      </constructor>
+
       <method name="_onClick">
         <body>
           <![CDATA[
             this._container.selectedTab = this;
             let selectFn = new Function("event", this._container.parentNode.getAttribute("onselect"));
             selectFn.call(this);
           ]]>
         </body>
@@ -85,24 +92,16 @@
         <parameter name="src"/>
         <body>
           <![CDATA[
             this._favicon.src = src;
           ]]>
         </body>
       </method>
 
-      <method name="updateThumbnailSource">
-        <parameter name="browser"/>
-        <body>
-          <![CDATA[
-            this._thumbnail.style.backgroundImage = "-moz-element(#" + browser.id + ")";
-          ]]>
-        </body>
-      </method>
     </implementation>
   </binding>
 
   <binding id="tablist">
     <content>
       <xul:arrowscrollbox anonid="tabs-scrollbox" class="tabs-scrollbox" flex="1" orient="horizontal"
         clicktoscroll="true" />
     </content>
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -3,24 +3,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 let Cr = Components.results;
 
+Cu.import("resource://gre/modules/PageThumbs.jsm");
+
 const kBrowserViewZoomLevelPrecision = 10000;
 
 // allow panning after this timeout on pages with registered touch listeners
 const kTouchTimeout = 300;
 const kSetInactiveStateTimeout = 100;
 
 const kDefaultMetadata = { autoSize: false, allowZoom: true, autoScale: true };
 
+const kTabThumbnailDelayCapture = 500;
+
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 // Override sizeToContent in the main window. It breaks things (bug 565887)
 window.sizeToContent = function() {
   Cu.reportError("window.sizeToContent is not allowed in this window");
 }
 
 function getTabModalPromptBox(aWindow) {
@@ -1449,16 +1453,17 @@ function showDownloadManager(aWindowCont
 function Tab(aURI, aParams, aOwner) {
   this._id = null;
   this._browser = null;
   this._notification = null;
   this._loading = false;
   this._chromeTab = null;
   this._metadata = null;
   this._eventDeferred = null;
+  this._updateThumbnailTimeout = null;
 
   this.owner = aOwner || null;
 
   // Set to 0 since new tabs that have not been viewed yet are good tabs to
   // toss if app needs more memory.
   this.lastSelected = 0;
 
   // aParams is an object that contains some properties for the initial tab
@@ -1598,23 +1603,55 @@ Tab.prototype = {
     function onPageShowEvent(aEvent) {
       browser.removeEventListener("pageshow", onPageShowEvent);
       if (self._eventDeferred) {
         self._eventDeferred.resolve(self);
       }
       self._eventDeferred = null;
     }
     browser.addEventListener("pageshow", onPageShowEvent, true);
+    browser.messageManager.addMessageListener("Content:StateChange", this);
+    Services.obs.addObserver(this, "metro_viewstate_changed", false);
 
     if (aOwner)
       this._copyHistoryFrom(aOwner);
     this._loadUsingParams(browser, aURI, aParams);
   },
 
+  receiveMessage: function(aMessage) {
+    switch (aMessage.name) {
+      case "Content:StateChange":
+        // update the thumbnail now...
+        this.updateThumbnail();
+        // ...and in a little while to capture page after load.
+        if (aMessage.json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
+          clearTimeout(this._updateThumbnailTimeout);
+          this._updateThumbnailTimeout = setTimeout(() => {
+            this.updateThumbnail();
+          }, kTabThumbnailDelayCapture);
+        }
+        break;
+    }
+  },
+
+  observe: function BrowserUI_observe(aSubject, aTopic, aData) {
+    switch (aTopic) {
+      case "metro_viewstate_changed":
+        if (aData !== "snapped") {
+          this.updateThumbnail();
+        }
+        break;
+    }
+  },
+
   destroy: function destroy() {
+    this._browser.messageManager.removeMessageListener("Content:StateChange", this);
+    Services.obs.removeObserver(this, "metro_viewstate_changed", false);
+    clearTimeout(this._updateThumbnailTimeout);
+
     Elements.tabList.removeTab(this._chromeTab);
     this._chromeTab = null;
     this._destroyBrowser();
   },
 
   resurrect: function resurrect() {
     let dead = this._browser;
     let active = this.active;
@@ -1813,18 +1850,18 @@ Tab.prototype = {
     let screenW = aScreenWidth || this._browser.getBoundingClientRect().width;
     return screenW / browserW;
   },
 
   get allowZoom() {
     return this.metadata.allowZoom && !Util.isURLEmpty(this.browser.currentURI.spec);
   },
 
-  updateThumbnailSource: function updateThumbnailSource() {
-    this._chromeTab.updateThumbnailSource(this._browser);
+  updateThumbnail: function updateThumbnail() {
+    PageThumbs.captureToCanvas(this.browser.contentWindow, this._chromeTab.thumbnailCanvas);
   },
 
   updateFavicon: function updateFavicon() {
     this._chromeTab.updateFavicon(this._browser.mIconURL);
   },
 
   set active(aActive) {
     if (!this._browser)
--- a/browser/metro/theme/browser.css
+++ b/browser/metro/theme/browser.css
@@ -122,16 +122,17 @@ documenttab[closing] > .documenttab-cont
 .documenttab-favicon {
   visibility: collapse;
 }
 
 .documenttab-thumbnail {
   margin: @metro_spacing_normal@ @metro_spacing_snormal@;
   background: white none center top no-repeat;
   background-size: cover;
+  min-width: @thumbnail_width@;
   width: @thumbnail_width@;
   height: @thumbnail_height@;
 }
 #tray:not([expanded]) .documenttab-thumbnail {
   background-image: none!important;
 }
 
 .documenttab-title {