Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Fri, 16 Feb 2018 12:20:10 +0200
changeset 404204 c76cfa405b0e4b96e290d440cecdae8691f077de
parent 404203 e78ab9a72984a252764331675cf1afed7347020c (current diff)
parent 404143 f01d1def46fb53a6523768c6e9188e66b89e664e (diff)
child 404205 48056396963a0eaa51a2e7698dcf6be60eb1392a
push id99968
push userrgurzau@mozilla.com
push dateFri, 16 Feb 2018 22:14:56 +0000
treeherdermozilla-inbound@2e16779c96cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.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
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1249,28 +1249,16 @@ var gBrowserInit = {
       remoteType, sameProcessAsFrameLoader
     });
 
     gUIDensity.init();
 
     if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
       gDragSpaceObserver.init();
     }
-
-    // Hack to ensure that the about:home favicon is loaded
-    // instantaneously, to avoid flickering and improve perceived performance.
-    this._callWithURIToLoad(uriToLoad => {
-      if (uriToLoad == "about:home") {
-        gBrowser.setIcon(gBrowser.selectedTab, "chrome://branding/content/icon32.png");
-      } else if (uriToLoad == "about:privatebrowsing") {
-        gBrowser.setIcon(gBrowser.selectedTab, "chrome://browser/skin/privatebrowsing/favicon.svg");
-      }
-    });
-
-    this._setInitialFocus();
   },
 
   onLoad() {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver);
 
     Services.obs.addObserver(gPluginHandler.NPAPIPluginCrashed, "plugin-crashed");
 
     window.addEventListener("AppCommand", HandleAppCommandEvent, true);
@@ -1361,16 +1349,28 @@ var gBrowserInit = {
 
       try {
         gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
       } catch (e) {
         Cu.reportError(e);
       }
     }
 
+    this._setInitialFocus();
+
+    // Hack to ensure that the about:home favicon is loaded
+    // instantaneously, to avoid flickering and improve perceived performance.
+    this._uriToLoadPromise.then(uriToLoad => {
+      if (uriToLoad == "about:home") {
+        gBrowser.setIcon(gBrowser.selectedTab, "chrome://branding/content/icon32.png");
+      } else if (uriToLoad == "about:privatebrowsing") {
+        gBrowser.setIcon(gBrowser.selectedTab, "chrome://browser/skin/privatebrowsing/favicon.svg");
+      }
+    });
+
     // Wait until chrome is painted before executing code not critical to making the window visible
     this._boundDelayedStartup = this._delayedStartup.bind(this);
     window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
 
     this._loadHandled = true;
   },
 
   _cancelDelayedStartup() {
@@ -1587,25 +1587,19 @@ var gBrowserInit = {
 
     let initialBrowser = gBrowser.selectedBrowser;
     mm.addMessageListener("Browser:FirstNonBlankPaint",
                           function onFirstNonBlankPaint() {
       mm.removeMessageListener("Browser:FirstNonBlankPaint", onFirstNonBlankPaint);
       initialBrowser.removeAttribute("blank");
     });
 
-    // To prevent flickering of the urlbar-history-dropmarker in the general
-    // case, the urlbar has the 'focused' attribute set by default.
-    // If we are not fully sure the urlbar will be focused in this window,
-    // we should remove the attribute before first paint.
-    let shouldRemoveFocusedAttribute = true;
-    this._callWithURIToLoad(uriToLoad => {
+    this._uriToLoadPromise.then(uriToLoad => {
       if ((isBlankPageURL(uriToLoad) || uriToLoad == "about:privatebrowsing") &&
           focusAndSelectUrlBar()) {
-        shouldRemoveFocusedAttribute = false;
         return;
       }
 
       if (gBrowser.selectedBrowser.isRemoteBrowser) {
         // If the initial browser is remote, in order to optimize for first paint,
         // we'll defer switching focus to that browser until it has painted.
         firstBrowserPaintDeferred.promise.then(() => {
           // If focus didn't move while we were waiting for first paint, we're okay
@@ -1615,22 +1609,20 @@ var gBrowserInit = {
           }
         });
       } else {
         // If the initial browser is not remote, we can focus the browser
         // immediately with no paint performance impact.
         gBrowser.selectedBrowser.focus();
       }
     });
-    if (shouldRemoveFocusedAttribute)
-      gURLBar.removeAttribute("focused");
   },
 
   _handleURIToLoad() {
-    this._callWithURIToLoad(uriToLoad => {
+    this._uriToLoadPromise.then(uriToLoad => {
       if (!uriToLoad || uriToLoad == "about:blank") {
         return;
       }
 
       // We don't check if uriToLoad is a XULElement because this case has
       // already been handled before first paint, and the argument cleared.
       if (uriToLoad instanceof Ci.nsIArray) {
         let count = uriToLoad.length;
@@ -1739,59 +1731,47 @@ var gBrowserInit = {
         ChromeUtils.import("resource:///modules/DownloadsTaskbar.jsm", {})
           .DownloadsTaskbar.registerIndicator(window);
       } catch (ex) {
         Cu.reportError(ex);
       }
     }, {timeout: 10000});
   },
 
-  // Returns the URI(s) to load at startup if it is immediately known, or a
-  // promise resolving to the URI to load.
+  // Returns the URI(s) to load at startup.
   get _uriToLoadPromise() {
     delete this._uriToLoadPromise;
-    return this._uriToLoadPromise = function() {
+    return this._uriToLoadPromise = new Promise(resolve => {
       // window.arguments[0]: URI to load (string), or an nsIArray of
       //                      nsISupportsStrings to load, or a xul:tab of
       //                      a tabbrowser, which will be replaced by this
       //                      window (for this case, all other arguments are
       //                      ignored).
       if (!window.arguments || !window.arguments[0]) {
-        return null;
+        resolve(null);
+        return;
       }
 
       let uri = window.arguments[0];
       let defaultArgs = Cc["@mozilla.org/browser/clh;1"]
                           .getService(Ci.nsIBrowserHandler)
                           .defaultArgs;
 
       // If the given URI is different from the homepage, we want to load it.
       if (uri != defaultArgs) {
-        return uri;
+        resolve(uri);
+        return;
       }
 
       // The URI appears to be the the homepage. We want to load it only if
       // session restore isn't about to override the homepage.
-      let willOverride = SessionStartup.willOverrideHomepage;
-      if (!(willOverride instanceof Promise)) {
-        return willOverride ? null : uri;
-      }
-      return willOverride.then(willOverrideHomepage =>
-                                 willOverrideHomepage ? null : uri);
-    }();
-  },
-
-  // Calls the given callback with the URI to load at startup.
-  // Synchronously if possible, or after _uriToLoadPromise resolves otherwise.
-  _callWithURIToLoad(callback) {
-    let uriToLoad = this._uriToLoadPromise;
-    if (uriToLoad instanceof Promise)
-      uriToLoad.then(callback);
-    else
-      callback(uriToLoad);
+      SessionStartup.willOverrideHomepagePromise.then(willOverrideHomepage => {
+        resolve(willOverrideHomepage ? null : uri);
+      });
+    });
   },
 
   onUnload() {
     gUIDensity.uninit();
 
     if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
       gDragSpaceObserver.uninit();
     }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -768,17 +768,16 @@
                        cui-areatype="toolbar"
                        aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
         <toolbarspring cui-areatype="toolbar" class="chromeclass-toolbar-additional"/>
         <toolbaritem id="urlbar-container" flex="400" persist="width"
                      removable="false"
                      class="chromeclass-location" overflows="false">
             <textbox id="urlbar" flex="1"
                      placeholder="&urlbar.placeholder2;"
-                     focused="true"
                      type="autocomplete"
                      autocompletesearch="unifiedcomplete"
                      autocompletesearchparam="enable-actions"
                      autocompletepopup="PopupAutoCompleteRichResult"
                      completeselectedindex="true"
                      shrinkdelay="250"
                      tabscrolling="true"
                      newlines="stripsurroundingwhitespace"
--- a/browser/base/content/test/performance/browser_startup_flicker.js
+++ b/browser/base/content/test/performance/browser_startup_flicker.js
@@ -31,22 +31,35 @@ add_task(async function() {
       alreadyFocused = true;
       // This is likely an issue caused by the test harness, but log it anyway.
       todo(false,
            "the window should be focused at first paint, " + rects.toSource());
       continue;
     }
 
     rects = rects.filter(rect => {
+      let inRange = (val, min, max) => min <= val && val <= max;
       let width = frame.width;
 
       let exceptions = [
-        /**
-         * Nothing here! Please don't add anything new!
-         */
+        {name: "bug 1403648 - urlbar down arrow shouldn't flicker",
+         condition: r => // 5x9px area, sometimes less at the end of the opacity transition
+                         inRange(r.h, 3, 5) && inRange(r.w, 7, 9) &&
+                         inRange(r.y1, 40, 80) && // in the toolbar
+                         // at ~80% of the window width
+                         inRange(r.x1, width * .75, width * .9)
+        },
+
+        {name: "bug 1403648 - urlbar should be focused at first paint",
+         condition: r => inRange(r.y2, 60, 80) && // in the toolbar
+                         // taking 50% to 75% of the window width
+                         inRange(r.w, width * .5, width * .75) &&
+                         // starting at 15 to 25% of the window width
+                         inRange(r.x1, width * .15, width * .25)
+        },
       ];
 
       let rectText = `${rect.toSource()}, window width: ${width}`;
       for (let e of exceptions) {
         if (e.condition(rect)) {
           todo(false, e.name + ", " + rectText);
           return false;
         }
--- a/browser/base/content/test/performance/browser_windowopen_flicker.js
+++ b/browser/base/content/test/performance/browser_windowopen_flicker.js
@@ -80,26 +80,54 @@ add_task(async function() {
       continue;
     }
 
     ignoreTinyPaint = false;
     let rects = compareFrames(frame, previousFrame).filter(rect => {
       let inRange = (val, min, max) => min <= val && val <= max;
       let width = frame.width;
 
+      const spaceBeforeFirstTab = AppConstants.platform == "macosx" ? 100 : 0;
+      let inFirstTab = r =>
+        inRange(r.x1, spaceBeforeFirstTab, spaceBeforeFirstTab + 50) && r.y1 < 30;
+
       let exceptions = [
+        {name: "bug 1403648 - urlbar down arrow shouldn't flicker",
+         condition: r => // 5x9px area, sometimes less at the end of the opacity transition
+                         inRange(r.h, 3, 5) && inRange(r.w, 7, 9) &&
+                         inRange(r.y1, 40, 80) && // in the toolbar
+                         // at ~80% of the window width
+                         inRange(r.x1, width * .75, width * .9)
+        },
+
+        {name: "bug 1403648 - urlbar should be focused at first paint",
+         condition: r => inRange(r.y2, 60, 80) && // in the toolbar
+                         // taking 50% to 75% of the window width
+                         inRange(r.w, width * .5, width * .75) &&
+                         // starting at 15 to 25% of the window width
+                         inRange(r.x1, width * .15, width * .25)
+        },
+
         {name: "bug 1421463 - reload toolbar icon shouldn't flicker",
          condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
                          inRange(r.y1, 40, 80) && // in the toolbar
                          // near the left side of the screen
                          // The reload icon is shifted on devedition builds
                          // where there's an additional devtools toolbar icon.
                          AppConstants.MOZ_DEV_EDITION ? inRange(r.x1, 100, 120) :
                                                         inRange(r.x1, 65, 100)
         },
+
+        {name: "bug 1401955 - about:home favicon should be visible at first paint",
+         condition: r => inFirstTab(r) && inRange(r.h, 14, 15) && inRange(r.w, 14, 15)
+        },
+
+        {name: "bug 1401955 - space for about:home favicon should be there at first paint",
+         condition: r => inFirstTab(r) && inRange(r.w, 60, 80) && inRange(r.h, 8, 15)
+        },
       ];
 
       let rectText = `${rect.toSource()}, window width: ${width}`;
       for (let e of exceptions) {
         if (e.condition(rect)) {
           todo(false, e.name + ", " + rectText);
           return false;
         }
--- a/browser/base/content/test/performance/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen_reflows.js
@@ -31,16 +31,22 @@ if (Services.appinfo.OS == "WINNT") {
     },
   );
 }
 
 if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
   EXPECTED_REFLOWS.push(
     {
       stack: [
+        "select@chrome://global/content/bindings/textbox.xml",
+        "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+      ],
+    },
+    {
+      stack: [
         "rect@chrome://browser/content/browser-tabsintitlebar.js",
         "_update@chrome://browser/content/browser-tabsintitlebar.js",
         "init@chrome://browser/content/browser-tabsintitlebar.js",
         "handleEvent@chrome://browser/content/tabbrowser.xml",
       ],
       // These numbers should only ever go down - never up.
       times: Services.appinfo.OS == "WINNT" ? 5 : 4,
     },
--- a/browser/components/sessionstore/nsISessionStartup.idl
+++ b/browser/components/sessionstore/nsISessionStartup.idl
@@ -31,24 +31,23 @@ interface nsISessionStartup: nsISupports
   /**
    * Determines whether automatic session restoration is enabled for this
    * launch of the browser. This does not include crash restoration, and will
    * return false if restoration will only be caused by a crash.
    */
   boolean isAutomaticRestoreEnabled();
 
   /**
-   * Returns a boolean or a promise that resolves to a boolean, indicating
-   * whether we will restore a session that ends up replacing the homepage.
-   * True guarantees that we'll restore a session; false means that we
-   * /probably/ won't do so.
+   * Returns a promise that resolves to a boolean, indicating whether we will
+   * restore a session that ends up replacing the homepage. True guarantees
+   * that we'll restore a session; false means that we /probably/ won't do so.
    * The browser uses this to avoid unnecessarily loading the homepage when
    * restoring a session.
    */
-  readonly attribute jsval willOverrideHomepage;
+  readonly attribute jsval willOverrideHomepagePromise;
 
   /**
    * What type of session we're restoring.
    * NO_SESSION       There is no data available from the previous session
    * RECOVER_SESSION  The last session crashed. It will either be restored or
    *                  about:sessionrestore will be shown.
    * RESUME_SESSION   The previous session should be restored at startup
    * DEFER_SESSION    The previous session is fine, but it shouldn't be restored
--- a/browser/components/sessionstore/nsSessionStartup.js
+++ b/browser/components/sessionstore/nsSessionStartup.js
@@ -305,31 +305,30 @@ SessionStartup.prototype = {
    * @returns bool
    */
   _willRestore() {
     return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
            this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
   },
 
   /**
-   * Returns a boolean or a promise that resolves to a boolean, indicating
-   * whether we will restore a session that ends up replacing the homepage.
-   * True guarantees that we'll restore a session; false means that we
-   * /probably/ won't do so.
+   * Returns a promise that resolves to a boolean, indicating whether we will
+   * restore a session that ends up replacing the homepage. True guarantees
+   * that we'll restore a session; false means that we /probably/ won't do so.
    * The browser uses this to avoid unnecessarily loading the homepage when
    * restoring a session.
    */
-  get willOverrideHomepage() {
+  get willOverrideHomepagePromise() {
     // If the session file hasn't been read yet and resuming the session isn't
     // enabled via prefs, go ahead and load the homepage. We may still replace
     // it when recovering from a crash, which we'll only know after reading the
     // session file, but waiting for that would delay loading the homepage in
     // the non-crash case.
     if (!this._initialState && !this._resumeSessionEnabled) {
-      return false;
+      return Promise.resolve(false);
     }
 
     return new Promise(resolve => {
       this.onceInitialized.then(() => {
         // If there are valid windows with not only pinned tabs, signal that we
         // will override the default homepage by restoring a session.
         resolve(this._willRestore() &&
                 this._initialState &&