Bug 1383073 - Move speculativeConnectOnTabHover to tabbrowser.xml so we don't have to worry about clearing mouseover listeners from tabs. r=dao, a=lizzard
authorBeekill95 <nnn_bikiu0707@yahoo.com>
Fri, 28 Jul 2017 15:03:30 +0700
changeset 421134 edbb6431090cb9e791750c2c5fee1363a788449c
parent 421133 e3682dd9a9cb9cd02bc3d61770b3bc24d884d0fe
child 421135 7e969755ccb9a97afc81ddbc199fe077e0d75924
push id7608
push userryanvm@gmail.com
push dateMon, 14 Aug 2017 01:26:10 +0000
treeherdermozilla-beta@1ad3a57bcf6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao, lizzard
bugs1383073
milestone56.0
Bug 1383073 - Move speculativeConnectOnTabHover to tabbrowser.xml so we don't have to worry about clearing mouseover listeners from tabs. r=dao, a=lizzard MozReview-Commit-ID: 6Q0EvtJGEIg
browser/base/content/tabbrowser.xml
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/test/browser_speculative_connect.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -7650,16 +7650,19 @@
             }
           }
 
           tabContainer._hoveredTab = this;
           if (this.linkedPanel && !this.selected) {
             this.linkedBrowser.unselectedTabHover(true);
             this.startUnselectedTabHoverTimer();
           }
+
+          // Prepare connection to host beforehand.
+          SessionStore.speculativeConnectOnTabHover(this);
         ]]></body>
       </method>
 
       <method name="_mouseleave">
         <body><![CDATA[
           let tabContainer = this.parentNode;
           if (tabContainer._beforeHoveredTab) {
             tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -351,16 +351,20 @@ this.SessionStore = {
   persistTabAttribute: function ss_persistTabAttribute(aName) {
     SessionStoreInternal.persistTabAttribute(aName);
   },
 
   restoreLastSession: function ss_restoreLastSession() {
     SessionStoreInternal.restoreLastSession();
   },
 
+  speculativeConnectOnTabHover(tab) {
+    SessionStoreInternal.speculativeConnectOnTabHover(tab);
+  },
+
   getCurrentState(aUpdateAll) {
     return SessionStoreInternal.getCurrentState(aUpdateAll);
   },
 
   reviveCrashedTab(aTab) {
     return SessionStoreInternal.reviveCrashedTab(aTab);
   },
 
@@ -715,16 +719,18 @@ var SessionStoreInternal = {
     });
 
     this._max_tabs_undo = this._prefBranch.getIntPref("sessionstore.max_tabs_undo");
     this._prefBranch.addObserver("sessionstore.max_tabs_undo", this, true);
 
     this._max_windows_undo = this._prefBranch.getIntPref("sessionstore.max_windows_undo");
     this._prefBranch.addObserver("sessionstore.max_windows_undo", this, true);
 
+    this._restore_on_demand = this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
+    this._prefBranch.addObserver("sessionstore.restore_on_demand", this, true);
 
     gResistFingerprintingEnabled = Services.prefs.getBoolPref("privacy.resistFingerprinting");
     Services.prefs.addObserver("privacy.resistFingerprinting", this);
   },
 
   /**
    * Called on application shutdown, after notifications:
    * quit-application-granted, quit-application
@@ -1828,16 +1834,19 @@ var SessionStoreInternal = {
         break;
       case "sessionstore.max_windows_undo":
         this._max_windows_undo = this._prefBranch.getIntPref("sessionstore.max_windows_undo");
         this._capClosedWindows();
         break;
       case "privacy.resistFingerprinting":
         gResistFingerprintingEnabled = Services.prefs.getBoolPref("privacy.resistFingerprinting");
         break;
+      case "sessionstore.restore_on_demand":
+        this._restore_on_demand = this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
+        break;
     }
   },
 
   /**
    * save state when new tab is added
    * @param aWindow
    *        Window reference
    */
@@ -3274,18 +3283,17 @@ var SessionStoreInternal = {
     if (overwriteTabs) {
       for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
         if (!tabbrowser.tabs[i].selected) {
           tabbrowser.removeTab(tabbrowser.tabs[i]);
         }
       }
     }
 
-    let restoreOnDemand = this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
-    let restoreTabsLazily = this._prefBranch.getBoolPref("sessionstore.restore_tabs_lazily") && restoreOnDemand;
+    let restoreTabsLazily = this._prefBranch.getBoolPref("sessionstore.restore_tabs_lazily") && this._restore_on_demand;
 
     for (var t = 0; t < newTabCount; t++) {
       let tabData = winData.tabs[t];
 
       let userContextId = tabData.userContextId;
       let select = t == selectTab - 1;
       let tab;
 
@@ -3331,23 +3339,16 @@ var SessionStoreInternal = {
                                   userContextId,
                                   skipBackgroundNotify: true });
 
         if (select) {
           let leftoverTab = tabbrowser.selectedTab;
           tabbrowser.selectedTab = tab;
           tabbrowser.removeTab(leftoverTab);
         }
-
-        // Prepare connection to the host when users hover mouse over this
-        // tab. If we're not restoring on demand, we'll prepare connection
-        // when we're restoring next tab.
-        if (!select && !tabData.pinned && restoreOnDemand) {
-          this.speculativeConnectOnTabHover(tab, url);
-        }
       }
 
       tabs.push(tab);
 
       if (tabData.hidden) {
         tabbrowser.hideTab(tab);
       }
 
@@ -3441,31 +3442,35 @@ var SessionStoreInternal = {
       sc.speculativeConnect(uri, null, null);
       return true;
     }
     return false;
   },
 
   /**
    * Make a connection to a host when users hover mouse on a tab.
+   * This will also set a flag in the tab to prevent us from speculatively
+   * connecting a second time.
    *
    * @param tab
-   *        A tab to set up a hover listener.
-   * @param url
-   *        URL of a host.
+   *        a tab to speculatively connect on mouse hover.
    */
-  speculativeConnectOnTabHover(tab, url) {
-    tab.addEventListener("mouseover", () => {
+  speculativeConnectOnTabHover(tab) {
+    if (this._restore_on_demand && !tab.__SS_connectionPrepared && tab.hasAttribute("pending")) {
+      let url = this.getLazyTabValue(tab, "url");
       let prepared = this.prepareConnectionToHost(url);
       // This is used to test if a connection has been made beforehand.
       if (gDebuggingEnabled) {
         tab.__test_connection_prepared = prepared;
         tab.__test_connection_url = url;
       }
-    }, {once: true});
+      // A flag indicate that we've prepared a connection for this tab and
+      // if is called again, we shouldn't prepare another connection.
+      tab.__SS_connectionPrepared = true;
+    }
   },
 
   /**
    * Restore multiple windows using the provided state.
    * @param aWindow
    *        Window reference to the first window to use for restoration.
    *        Additionally required windows will be opened.
    * @param aState
--- a/browser/components/sessionstore/test/browser_speculative_connect.js
+++ b/browser/components/sessionstore/test/browser_speculative_connect.js
@@ -32,30 +32,33 @@ add_task(async function speculative_conn
   await BrowserTestUtils.waitForEvent(newWin, "load");
   await BrowserTestUtils.waitForEvent(newWin.gBrowser.tabContainer, "SSTabRestored");
 
   let tabs = newWin.gBrowser.tabs;
   is(tabs.length, TEST_URLS.length + 1, "Restored right number of tabs");
 
   let e = new MouseEvent("mouseover");
 
-  // First tab should be ignore, since it's the default blank tab when we open a new window.
+  // First tab should be ignored, since it's the default blank tab when we open a new window.
 
   // Trigger a mouse enter on second tab.
   tabs[1].dispatchEvent(e);
   is(tabs[1].__test_connection_prepared, false, "Second tab doesn't have a connection prepared");
   is(tabs[1].__test_connection_url, TEST_URLS[0], "Second tab has correct url");
+  is(tabs[1].__SS_connectionPrepared, true, "Second tab should have __SS_connectionPrepared flag after hovered");
 
   // Trigger a mouse enter on third tab.
   tabs[2].dispatchEvent(e);
   is(tabs[2].__test_connection_prepared, true, "Third tab has a connection prepared");
   is(tabs[2].__test_connection_url, TEST_URLS[1], "Third tab has correct url");
+  is(tabs[2].__SS_connectionPrepared, true, "Third tab should have __SS_connectionPrepared flag after hovered");
 
   // Last tab is the previously selected tab.
   tabs[3].dispatchEvent(e);
+  is(tabs[3].__SS_connectionPrepared, undefined, "Previous selected tab shouldn't have __SS_connectionPrepared flag");
   is(tabs[3].__test_connection_prepared, undefined, "Previous selected tab should not have a connection prepared");
   is(tabs[3].__test_connection_url, undefined, "Previous selected tab should not have a connection prepared");
 
   await BrowserTestUtils.closeWindow(newWin);
 });
 
 add_task(async function speculative_connect_restore_automatically() {
   Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
@@ -73,17 +76,17 @@ add_task(async function speculative_conn
   let newWin = undoCloseWindow(0);
   // Make sure we wait until this window is restored.
   await BrowserTestUtils.waitForEvent(newWin, "load");
   await BrowserTestUtils.waitForEvent(newWin.gBrowser.tabContainer, "SSTabRestored");
 
   let tabs = newWin.gBrowser.tabs;
   is(tabs.length, TEST_URLS.length + 1, "Restored right number of tabs");
 
-  // First tab is ignore, since it's the default tab open when we open new window
+  // First tab is ignored, since it's the default tab open when we open new window
 
   // Second tab.
   is(tabs[1].__test_connection_prepared, false, "Second tab doesn't have a connection prepared");
   is(tabs[1].__test_connection_url, TEST_URLS[0], "Second tab has correct host url");
 
   // Third tab.
   is(tabs[2].__test_connection_prepared, true, "Third tab has a connection prepared");
   is(tabs[2].__test_connection_url, TEST_URLS[1], "Third tab has correct host url");