Backed out changeset 434ffe0d33b2 (bug 1003096) on a CLOSED TREE r=bustage
authorTim Taubert <ttaubert@mozilla.com>
Tue, 29 Apr 2014 22:03:02 +0200
changeset 181252 83c3a747105114dce8ebc0ca6674819583ba47ef
parent 181251 24cf989be9e3eec106d0e40fc3e5c321444e97e2
child 181253 e79ce804e9ec42cbf0bf8f3092db6bdf4105836b
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbustage
bugs1003096
milestone32.0a1
backs out434ffe0d33b2ecd8f0de9998a171ce03711557f8
Backed out changeset 434ffe0d33b2 (bug 1003096) on a CLOSED TREE r=bustage
browser/components/sessionstore/src/SessionStore.jsm
browser/components/sessionstore/test/browser.ini
browser/components/sessionstore/test/browser_480148.js
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2396,27 +2396,105 @@ let SessionStoreInternal = {
     tabstrip.smoothScroll = smoothScroll;
 
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
 
     this._sendRestoreCompletedNotifications();
   },
 
   /**
+   * Sets the tabs restoring order with the following priority:
+   * Selected tab, pinned tabs, optimized visible tabs, other visible tabs and
+   * hidden tabs.
+   * @param aTabBrowser
+   *        Tab browser object
+   * @param aTabs
+   *        Array of tab references
+   * @param aTabData
+   *        Array of tab data
+   * @param aSelectedTab
+   *        Index of selected tab (1 is first tab, 0 no selected tab)
+   */
+  _setTabsRestoringOrder : function ssi__setTabsRestoringOrder(
+    aTabBrowser, aTabs, aTabData, aSelectedTab) {
+
+    // Store the selected tab. Need to substract one to get the index in aTabs.
+    let selectedTab;
+    if (aSelectedTab > 0 && aTabs[aSelectedTab - 1]) {
+      selectedTab = aTabs[aSelectedTab - 1];
+    }
+
+    // Store the pinned tabs and hidden tabs.
+    let pinnedTabs = [];
+    let pinnedTabsData = [];
+    let hiddenTabs = [];
+    let hiddenTabsData = [];
+    if (aTabs.length > 1) {
+      for (let t = aTabs.length - 1; t >= 0; t--) {
+        if (aTabData[t].pinned) {
+          pinnedTabs.unshift(aTabs.splice(t, 1)[0]);
+          pinnedTabsData.unshift(aTabData.splice(t, 1)[0]);
+        } else if (aTabData[t].hidden) {
+          hiddenTabs.unshift(aTabs.splice(t, 1)[0]);
+          hiddenTabsData.unshift(aTabData.splice(t, 1)[0]);
+        }
+      }
+    }
+
+    // Optimize the visible tabs only if there is a selected tab.
+    if (selectedTab) {
+      let selectedTabIndex = aTabs.indexOf(selectedTab);
+      if (selectedTabIndex > 0) {
+        let scrollSize = aTabBrowser.tabContainer.mTabstrip.scrollClientSize;
+        let tabWidth = aTabs[0].getBoundingClientRect().width;
+        let maxVisibleTabs = Math.ceil(scrollSize / tabWidth);
+        if (maxVisibleTabs < aTabs.length) {
+          let firstVisibleTab = 0;
+          let nonVisibleTabsCount = aTabs.length - maxVisibleTabs;
+          if (nonVisibleTabsCount >= selectedTabIndex) {
+            // Selected tab is leftmost since we scroll to it when possible.
+            firstVisibleTab = selectedTabIndex;
+          } else {
+            // Selected tab is rightmost or no more room to scroll right.
+            firstVisibleTab = nonVisibleTabsCount;
+          }
+          aTabs = aTabs.splice(firstVisibleTab, maxVisibleTabs).concat(aTabs);
+          aTabData =
+            aTabData.splice(firstVisibleTab, maxVisibleTabs).concat(aTabData);
+        }
+      }
+    }
+
+    // Merge the stored tabs in order.
+    aTabs = pinnedTabs.concat(aTabs, hiddenTabs);
+    aTabData = pinnedTabsData.concat(aTabData, hiddenTabsData);
+
+    // Load the selected tab to the first position and select it.
+    if (selectedTab) {
+      let selectedTabIndex = aTabs.indexOf(selectedTab);
+      if (selectedTabIndex > 0) {
+        aTabs = aTabs.splice(selectedTabIndex, 1).concat(aTabs);
+        aTabData = aTabData.splice(selectedTabIndex, 1).concat(aTabData);
+      }
+      aTabBrowser.selectedTab = selectedTab;
+    }
+
+    return [aTabs, aTabData];
+  },
+
+  /**
    * Manage history restoration for a window
    * @param aWindow
    *        Window to restore the tabs into
    * @param aTabs
    *        Array of tab references
    * @param aTabData
    *        Array of tab data
    * @param aSelectTab
-   *        Index of the tab to select. This is a 1-based index where "1"
-   *        indicates the first tab should be selected, and "0" indicates that
-   *        the currently selected tab will not be changed.
+   *        Index of selected tab
    * @param aRestoreImmediately
    *        Flag to indicate whether the given set of tabs aTabs should be
    *        restored/loaded immediately even if restore_on_demand = true
    */
   restoreTabs: function (aWindow, aTabs, aTabData, aSelectTab,
                          aRestoreImmediately = false)
   {
 
@@ -2442,20 +2520,19 @@ let SessionStoreInternal = {
 
     if (aTabs.length == 0) {
       // This is normally done later, but as we're returning early
       // here we need to take care of it.
       this._setWindowStateReady(aWindow);
       return;
     }
 
-    // If provided, set the selected tab.
-    if (aSelectTab > 0 && aSelectTab <= aTabs.length) {
-      tabbrowser.selectedTab = aTabs[aSelectTab - 1];
-    }
+    // Sets the tabs restoring order.
+    [aTabs, aTabData] =
+      this._setTabsRestoringOrder(tabbrowser, aTabs, aTabData, aSelectTab);
 
     // Prepare the tabs so that they can be properly restored. We'll pin/unpin
     // and show/hide tabs as necessary. We'll also set the labels, user typed
     // value, and attach a copy of the tab's data in case we close it before
     // it's been restored.
     for (let t = 0; t < aTabs.length; t++) {
       let tab = aTabs[t];
       let browser = tabbrowser.getBrowserForTab(tab);
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -106,16 +106,17 @@ skip-if = true
 [browser_463205.js]
 [browser_463206.js]
 [browser_464199.js]
 [browser_465215.js]
 [browser_465223.js]
 [browser_466937.js]
 [browser_467409-backslashplosion.js]
 [browser_477657.js]
+[browser_480148.js]
 [browser_480893.js]
 [browser_485482.js]
 [browser_485563.js]
 [browser_490040.js]
 [browser_491168.js]
 # Disabled for too many intermittent failures.
 # Can be re-enabled once bug 930202 lands.
 skip-if = true
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_480148.js
@@ -0,0 +1,216 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+function test() {
+  /** Test for Bug 484108 **/
+  waitForExplicitFinish();
+  requestLongerTimeout(5);
+
+  // builds the tests state based on a few parameters
+  function buildTestState(num, selected, hidden, pinned) {
+    let state = { windows: [ { "tabs": [], "selected": selected + 1 } ] };
+    while (num--) {
+      state.windows[0].tabs.push({
+        entries: [
+          { url: "http://example.com/?t=" + state.windows[0].tabs.length }
+        ]
+      });
+      let i = state.windows[0].tabs.length - 1;
+      if (hidden.length > 0 && i == hidden[0]) {
+        state.windows[0].tabs[i].hidden = true;
+        hidden.splice(0, 1);
+      }
+      if (pinned.length > 0 && i == pinned[0]) {
+        state.windows[0].tabs[i].pinned = true;
+        pinned.splice(0, 1);
+      }
+    }
+    return state;
+  }
+
+  let tests = [
+    { testNum: 1,
+      totalTabs: 13,
+      selectedTab: 0,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [],
+      order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    },
+    { testNum: 2,
+      totalTabs: 13,
+      selectedTab: 12,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [],
+      order: [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]
+    },
+    { testNum: 3,
+      totalTabs: 13,
+      selectedTab: 3,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [],
+      order: [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]
+    },
+    { testNum: 4,
+      totalTabs: 13,
+      selectedTab: 10,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [],
+      order: [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]
+    },
+    { testNum: 5,
+      totalTabs: 13,
+      selectedTab: 12,
+      shownTabs: 6,
+      hiddenTabs: [0, 4, 9],
+      pinnedTabs: [],
+      order: [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]
+    },
+    { testNum: 6,
+      totalTabs: 13,
+      selectedTab: 3,
+      shownTabs: 6,
+      hiddenTabs: [1, 7, 12],
+      pinnedTabs: [],
+      order: [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]
+    },
+    { testNum: 7,
+      totalTabs: 13,
+      selectedTab: 3,
+      shownTabs: 6,
+      hiddenTabs: [0, 1, 2],
+      pinnedTabs: [],
+      order: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]
+    },
+    { testNum: 8,
+      totalTabs: 13,
+      selectedTab: 0,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [0],
+      order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    },
+    { testNum: 9,
+      totalTabs: 13,
+      selectedTab: 1,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [0],
+      order: [1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    },
+    { testNum: 10,
+      totalTabs: 13,
+      selectedTab: 3,
+      shownTabs: 6,
+      hiddenTabs: [2],
+      pinnedTabs: [0,1],
+      order: [3, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 2]
+    },
+    { testNum: 11,
+      totalTabs: 13,
+      selectedTab: 12,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [0,1,2],
+      order: [12, 0, 1, 2, 7, 8, 9, 10, 11, 3, 4, 5, 6]
+    },
+    { testNum: 12,
+      totalTabs: 13,
+      selectedTab: 6,
+      shownTabs: 6,
+      hiddenTabs: [3,4,5],
+      pinnedTabs: [0,1,2],
+      order: [6, 0, 1, 2, 7, 8, 9, 10, 11, 12, 3, 4, 5]
+    },
+    { testNum: 13,
+      totalTabs: 13,
+      selectedTab: 1,
+      shownTabs: 6,
+      hiddenTabs: [3,4,5],
+      pinnedTabs: [0,1,2],
+      order: [1, 0, 2, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5]
+    },
+    { testNum: 14,
+      totalTabs: 13,
+      selectedTab: 2,
+      shownTabs: 6,
+      hiddenTabs: [],
+      pinnedTabs: [0,1,2],
+      order: [2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    },
+    { testNum: 15,
+      totalTabs: 13,
+      selectedTab: 3,
+      shownTabs: 6,
+      hiddenTabs: [1,4],
+      pinnedTabs: [0,1,2],
+      order: [3, 0, 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 4]
+    }
+  ];
+
+  let tabMinWidth =
+    parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
+  let testIndex = 0;
+
+  function runNextTest() {
+    if (tests.length == 0) {
+      finish();
+      return;
+    }
+
+    let wu = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    wu.garbageCollect();
+
+    setTimeout(function() {
+      info ("Starting test " + (++testIndex));
+      let test = tests.shift();
+      let state = buildTestState(test.totalTabs, test.selectedTab,
+                                 test.hiddenTabs, test.pinnedTabs);
+      let tabbarWidth = Math.floor((test.shownTabs - 0.5) * tabMinWidth);
+      let win = openDialog(location, "_blank", "chrome,all,dialog=no");
+      let tabsRestored = [];
+
+      win.addEventListener("SSTabRestoring", function onSSTabRestoring(aEvent) {
+        let tab = aEvent.originalTarget;
+        let tabLink = tab.linkedBrowser.currentURI.spec;
+        let tabIndex =
+          tabLink.substring(tabLink.indexOf("?t=") + 3, tabLink.length);
+
+        // we need to compare with the tab's restoring index, no with the
+        // position index, since the pinned tabs change the positions in the
+        // tabbar. 
+        tabsRestored.push(tabIndex);
+
+        if (tabsRestored.length < state.windows[0].tabs.length)
+          return;
+
+        // all of the tabs should be restoring or restored by now
+        is(tabsRestored.length, state.windows[0].tabs.length,
+           "Test #" + testIndex + ": Number of restored tabs is as expected");
+
+        is(tabsRestored.join(" "), test.order.join(" "),
+           "Test #" + testIndex + ": 'visible' tabs restored first");
+
+        // cleanup
+        win.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
+        win.close();
+        executeSoon(runNextTest);
+      }, false);
+
+      whenWindowLoaded(win, function(aEvent) {
+        let extent =
+          win.outerWidth - win.gBrowser.tabContainer.mTabstrip.scrollClientSize;
+        let windowWidth = tabbarWidth + extent;
+        win.resizeTo(windowWidth, win.outerHeight);
+        ss.setWindowState(win, JSON.stringify(state), true);
+      });
+    }, 1000);
+  };
+
+  runNextTest();
+}