Bug 622601 - Just before the new page is getting loaded, the old page is scrolled to the top and zoom reset [r=mfinkle]
authorVivien Nicolas <21@vingtetun.org>
Wed, 02 Mar 2011 00:18:46 +0100
changeset 67449 1cc782b4095cc4d6c68dfabe12bbe7c2372d6c0d
parent 67448 4ea3fa2f0947cd46beb424de1200e11082bd785c
child 67450 d62c1de9a231160f1673d4e4a4009e07886f8d41
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs622601
Bug 622601 - Just before the new page is getting loaded, the old page is scrolled to the top and zoom reset [r=mfinkle]
mobile/chrome/content/bindings/browser.js
mobile/chrome/content/bindings/browser.xml
mobile/chrome/content/browser.js
--- a/mobile/chrome/content/bindings/browser.js
+++ b/mobile/chrome/content/bindings/browser.js
@@ -49,16 +49,22 @@ let WebProgressListener = {
       charset:         charset.toString()
     };
 
     sendAsyncMessage("Content:LocationChange", json);
 
     // Keep track of hash changes
     this.hashChanged = (location == this._lastLocation);
     this._lastLocation = location;
+
+    // When a new page is loaded fire a message for the first paint
+    addEventListener("MozAfterPaint", function(aEvent) {
+      removeEventListener("MozAfterPaint", arguments.callee, true);
+      sendAsyncMessage("Browser:FirstPaint", {});
+    }, true);
   },
 
   onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
   },
 
   onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
     if (content != aWebProgress.DOMWindow)
       return;
--- a/mobile/chrome/content/bindings/browser.xml
+++ b/mobile/chrome/content/bindings/browser.xml
@@ -137,21 +137,16 @@
 
               case "MozScrolledAreaChanged":
                 self._contentDocumentWidth = aMessage.json.width;
                 self._contentDocumentHeight = aMessage.json.height;
 
                 // Recalculate whether the visible area is actually in bounds
                 let view = self.getRootView();
                 view.scrollBy(0, 0);
-
-                // XXX Actually this fire a SetCacheViewport event as well as the
-                // scrolledAreaChanged handler in content/chrome/browser.js. So
-                // we ended up doing twice the work for the same area
-                view._updateCacheViewport();
                 break;
             }
           }
         })
       ]]></field>
 
       <method name="loadFavicon">
         <parameter name="aURL"/>
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -1340,25 +1340,18 @@ Browser.WebProgress.prototype = {
           tab.hostChanged = true;
           tab.browser.lastLocation = location;
           tab.browser.userTypedValue = "";
 
 #ifdef MOZ_CRASH_REPORTER
           if (CrashReporter.enabled)
             CrashReporter.annotateCrashReport("URL", spec);
 #endif
-          if (tab == Browser.selectedTab) {
-            // We're about to have new page content, so scroll the content area
-            // to the top so the new paints will draw correctly.
-            // (background tabs are delayed scrolled to top in _documentStop)
-            Browser.scrollContentToTop({ x: 0 });
-          }
-
+          this._waitForLoad(tab);
           tab.useFallbackWidth = false;
-          tab.updateViewportSize();
         }
 
         let event = document.createEvent("UIEvents");
         event.initUIEvent("URLChanged", true, false, window, locationHasChanged);
         tab.browser.dispatchEvent(event);
         break;
       }
 
@@ -1397,18 +1390,38 @@ Browser.WebProgress.prototype = {
       BrowserUI.update(TOOLBARSTATE_LOADED);
 
     if (aTab.browser.currentURI.spec != "about:blank")
       aTab.updateThumbnail();
   },
 
   _documentStop: function _documentStop(aTab) {
     // Make sure the URLbar is in view. If this were the selected tab,
-    // onLocationChange would scroll to top.
+    // _waitForLoad would scroll to top.
     aTab.pageScrollOffset = { x: 0, y: 0 };
+  },
+
+  _waitForLoad: function _waitForLoad(aTab) {
+    let browser = aTab.browser;
+    browser.messageManager.removeMessageListener("MozScrolledAreaChanged", aTab.scrolledAreaChanged);
+
+    browser.messageManager.addMessageListener("Browser:FirstPaint", function(aMessage) {
+      browser.messageManager.removeMessageListener(aMessage.name, arguments.callee);
+
+      // We're about to have new page content, so scroll the content area
+      // to the top so the new paints will draw correctly.
+      // Background tabs are delayed scrolled to top in _documentStop
+      if (getBrowser() == browser) {
+        browser.getRootView().scrollTo(0, 0);
+        Browser.pageScrollboxScroller.scrollTo(0, 0);
+      }
+
+      aTab.scrolledAreaChanged();
+      browser.messageManager.addMessageListener("MozScrolledAreaChanged", aTab.scrolledAreaChanged);
+    });
   }
 };
 
 
 function nsBrowserAccess() { }
 
 nsBrowserAccess.prototype = {
   QueryInterface: function(aIID) {
@@ -2349,16 +2362,18 @@ function Tab(aURI, aParams) {
   this.lastSelected = 0;
 
   // aParams is an object that contains some properties for the initial tab
   // loading like flags, a referrerURI, a charset or even a postData.
   this.create(aURI, aParams || {});
 
   // default tabs to inactive (i.e. no display port)
   this.active = false;
+
+  this.scrolledAreaChanged = this.scrolledAreaChanged.bind(this);
 }
 
 Tab.prototype = {
   get browser() {
     return this._browser;
   },
 
   get notification() {
@@ -2546,21 +2561,16 @@ Tab.prototype = {
     // stop about:blank from loading
     browser.stop();
 
     const i = Ci.nsIFrameLoader_MOZILLA_2_0_BRANCH;
     let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
     let enabler = fl.QueryInterface(i);
     enabler.renderMode = i.RENDER_MODE_ASYNC_SCROLL;
 
-    browser.messageManager.addMessageListener("MozScrolledAreaChanged", (function() {
-      // ensure that the browser's contentDocumentWidth property adjusts first
-      setTimeout(this.scrolledAreaChanged.bind(this), 0);
-    }).bind(this));
-
     return browser;
   },
 
   _destroyBrowser: function _destroyBrowser() {
     if (this._browser) {
       let notification = this._notification;
       let browser = this._browser;
       browser.active = false;
@@ -2612,18 +2622,30 @@ Tab.prototype = {
    */
   updateDefaultZoomLevel: function updateDefaultZoomLevel() {
     let browser = this._browser;
     if (!browser)
       return;
 
     let isDefault = this.isDefaultZoomLevel();
     this._defaultZoomLevel = this.getDefaultZoomLevel();
-    if (isDefault)
-      browser.scale = this._defaultZoomLevel;
+    if (isDefault) {
+      if (browser.scale != this._defaultZoomLevel) {
+        browser.scale = this._defaultZoomLevel;
+      }
+      else {
+        // If the scale level has not changed we want to be sure the content
+        // render correctly since the page refresh process could have been
+        // stalled during page load. In this case if the page has the exact
+        // same width (like the same page, so by doing 'refresh') and the 
+        // page was scrolled the content is just checkerboard at this point
+        // and this call ensure we render it correctly.
+        browser.getRootView()._updateCacheViewport();
+      }
+    }
   },
 
   isDefaultZoomLevel: function isDefaultZoomLevel() {
     return this._browser.scale == this._defaultZoomLevel;
   },
 
   getDefaultZoomLevel: function getDefaultZoomLevel() {
     let md = this.metadata;