Bug 1372518 - the identity block shouldn't flicker when loading a secure internal page in a new window, r=johannh.
authorFlorian Quèze <florian@queze.net>
Fri, 11 Aug 2017 10:19:48 +0200
changeset 374275 3a7bd8419732cb5a944b331d168729b9c9e6e8de
parent 374274 806a941c858051eceb8076b056fb278dcc259647
child 374276 c4eb424ae51815c00c532dfb550d463b29dcd63a
push id32318
push userkwierso@gmail.com
push dateFri, 11 Aug 2017 20:16:01 +0000
treeherdermozilla-central@80ff3f300e05 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1372518
milestone57.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 1372518 - the identity block shouldn't flicker when loading a secure internal page in a new window, r=johannh.
browser/base/content/browser.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1359,29 +1359,32 @@ var gBrowserInit = {
         document.documentElement.setAttribute("darkwindowframe", "true");
       }
     }
 
     ToolbarIconColor.init();
 
     gRemoteControl.updateVisualCue(Marionette.running);
 
+    let uriToLoad = this._getUriToLoad();
+    gIdentityHandler.initIdentityBlock(uriToLoad);
+
     // Wait until chrome is painted before executing code not critical to making the window visible
-    this._boundDelayedStartup = this._delayedStartup.bind(this);
+    this._boundDelayedStartup = this._delayedStartup.bind(this, uriToLoad);
     window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
 
     this._loadHandled = true;
   },
 
   _cancelDelayedStartup() {
     window.removeEventListener("MozAfterPaint", this._boundDelayedStartup);
     this._boundDelayedStartup = null;
   },
 
-  _delayedStartup() {
+  _delayedStartup(uriToLoad) {
     let tmp = {};
     Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
     let TelemetryTimestamps = tmp.TelemetryTimestamps;
     TelemetryTimestamps.add("delayedStartupStarted");
 
     this._cancelDelayedStartup();
 
     // We need to set the OfflineApps message listeners up before we
@@ -1417,17 +1420,16 @@ var gBrowserInit = {
       gIdentityHandler.refreshIdentityBlock();
     });
 
     // Get the service so that it initializes and registers listeners for new
     // tab pages in order to be ready for any early-loading about:newtab pages,
     // e.g., start/home page, command line / startup uris to load, sessionstore
     gAboutNewTabService.QueryInterface(Ci.nsISupports);
 
-    let uriToLoad = this._getUriToLoad();
     if (uriToLoad && uriToLoad != "about:blank") {
       if (uriToLoad instanceof Ci.nsIArray) {
         let count = uriToLoad.length;
         let specs = [];
         for (let i = 0; i < count; i++) {
           let urisstring = uriToLoad.queryElementAt(i, Ci.nsISupportsString);
           specs.push(urisstring.data);
         }
@@ -7008,16 +7010,22 @@ var gIdentityHandler = {
   _state: 0,
 
   /**
    * This flag gets set if the identity popup was opened by a keypress,
    * to be able to focus it on the popupshown event.
    */
   _popupTriggeredByKeyboard: false,
 
+  /**
+   * RegExp used to decide if an about url should be shown as being part of
+   * the browser UI.
+   */
+  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
+
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
     // document. In this case, don't upgrade the security state in the UI
@@ -7636,27 +7644,35 @@ var gIdentityHandler = {
     this._identityPopupContentSupp.textContent = supplemental;
     this._identityPopupContentVerif.textContent = verifier;
 
     // Update per-site permissions section.
     this.updateSitePermissions();
   },
 
   setURI(uri) {
+    // Ignore about:blank loads until the window's initial URL has loaded,
+    // to avoid hiding the UI that initIdentityBlock could have prepared.
+    if (this._ignoreAboutBlankUntilFirstLoad) {
+      if (uri.spec == "about:blank")
+        return;
+      this._ignoreAboutBlankUntilFirstLoad = false;
+    }
+
     this._uri = uri;
 
     try {
       this._uri.host;
       this._uriHasHost = true;
     } catch (ex) {
       this._uriHasHost = false;
     }
 
-    let whitelist = /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i;
-    this._isSecureInternalUI = uri.schemeIs("about") && whitelist.test(uri.pathQueryRef);
+    this._isSecureInternalUI = uri.schemeIs("about") &&
+      this._secureInternalUIWhitelist.test(uri.pathQueryRef);
 
     this._isExtensionPage = uri.schemeIs("moz-extension");
 
     // Create a channel for the sole purpose of getting the resolved URI
     // of the request to determine if it's loaded from the file system.
     this._isURILoadedFromFile = false;
     let chanOptions = {uri: this._uri, loadUsingSystemPrincipal: true};
     let resolvedURI;
@@ -7670,16 +7686,35 @@ var gIdentityHandler = {
       // Check the URI again after resolving.
       this._isURILoadedFromFile = resolvedURI.schemeIs("file");
     } catch (ex) {
       // NetUtil's methods will throw for malformed URIs and the like
     }
   },
 
   /**
+   * Used to initialize the identity block before first paint to avoid
+   * flickering when opening a new window showing a secure internal page
+   * (eg. about:home)
+   */
+  initIdentityBlock(initialURI) {
+    if ((typeof initialURI != "string") || !initialURI.startsWith("about:"))
+      return;
+
+    let uri = Services.io.newURI(initialURI);
+    if (this._secureInternalUIWhitelist.test(uri.pathQueryRef)) {
+      this._isSecureInternalUI = true;
+      this._ignoreAboutBlankUntilFirstLoad = true;
+      this.refreshIdentityBlock();
+      // The identity label won't be visible without setting this.
+      gURLBar.setAttribute("pageproxystate", "valid");
+    }
+  },
+
+  /**
    * Click handler for the identity-box element in primary chrome.
    */
   handleIdentityButtonEvent(event) {
     event.stopPropagation();
 
     if ((event.type == "click" && event.button != 0) ||
         (event.type == "keypress" && event.charCode != KeyEvent.DOM_VK_SPACE &&
          event.keyCode != KeyEvent.DOM_VK_RETURN)) {