Bug 1351677 - When restoring a window, swap the initially selected tab with the desired selected tab instead of tab switching. r?mikedeboer
When restoring a window, it's cheaper if we move the initially selected tab to the
index of the tab that's supposed to be selected in the restored state, rather than
switching to that tab.
If it turns out that moving that tab is not possible (if, for example, the user
context IDs of the two tabs to swap don't match, since the userContextIds are
set at tab construction time), then we fall back to tab switching.
MozReview-Commit-ID: L3qP40K5DaJ
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -3199,16 +3199,19 @@ var SessionStoreInternal = {
* {firstWindow: true} if this is the first non-private window we're
* restoring in this session, that might open an
* external link as well
*/
restoreWindow: function ssi_restoreWindow(aWindow, winData, aOptions = {}) {
let overwriteTabs = aOptions && aOptions.overwriteTabs;
let isFollowUp = aOptions && aOptions.isFollowUp;
let firstWindow = aOptions && aOptions.firstWindow;
+ // See SessionStoreInternal.restoreTabs for a description of what
+ // selectTab represents.
+ let selectTab = (overwriteTabs ? parseInt(winData.selected || 1, 10) : 0);
if (isFollowUp) {
this.windowToFocus = aWindow;
}
// initialize window if necessary
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
this.onLoad(aWindow);
@@ -3275,31 +3278,76 @@ var SessionStoreInternal = {
// and put the newly added tab in its place.
if (!reuseExisting && t < openTabCount) {
tabbrowser.removeTab(tabbrowser.tabs[t]);
tabbrowser.moveTabTo(tab, t);
}
tabs.push(tab);
- if (winData.tabs[t].pinned)
- tabbrowser.pinTab(tabs[t]);
-
if (winData.tabs[t].hidden) {
tabbrowser.hideTab(tabs[t]);
} else {
tabbrowser.showTab(tabs[t]);
numVisibleTabs++;
}
if (!!winData.tabs[t].muted != tabs[t].linkedBrowser.audioMuted) {
tabs[t].toggleMuteAudio(winData.tabs[t].muteReason);
}
}
+ if (selectTab > 0) {
+ // The state we're restoring wants to select a particular tab. This
+ // implies that we're overwriting tabs.
+ let currentIndex = tabbrowser.tabContainer.selectedIndex;
+ let targetIndex = selectTab - 1;
+
+ if (currentIndex != targetIndex) {
+ // We need to change the selected tab. There are two ways of doing this:
+ //
+ // 1) The fast path: swap the currently selected tab with the one in the
+ // position of the selected tab in the restored state. Note that this
+ // can only work if the user contexts between the two tabs being swapped
+ // match. This should be the common case.
+ //
+ // 2) The slow path: switch to the selected tab.
+ //
+ // We'll try to do (1), and then fallback to (2).
+
+ let selectedTab = tabbrowser.selectedTab;
+ let tabAtTargetIndex = tabs[targetIndex];
+ let userContextsMatch = selectedTab.userContextId == tabAtTargetIndex.userContextId;
+
+ if (userContextsMatch) {
+ tabbrowser.moveTabTo(selectedTab, targetIndex);
+ tabbrowser.moveTabTo(tabAtTargetIndex, currentIndex);
+ // We also have to do a similar "move" in the aTabs Array to
+ // make sure that the restored content shows up in the right
+ // order.
+ tabs[targetIndex] = tabs[currentIndex];
+ tabs[currentIndex] = tabAtTargetIndex;
+ } else {
+ // Otherwise, go the slow path, and switch to the target tab.
+ tabbrowser.selectedTab = tabs[targetIndex];
+ }
+ }
+ }
+
+ for (let i = 0; i < newTabCount; ++i) {
+ if (winData.tabs[i].pinned) {
+ tabbrowser.pinTab(tabs[i]);
+ } else {
+ // Pinned tabs are clustered at the start of the tab strip. As
+ // soon as we reach a tab that isn't pinned, we know there aren't
+ // any more for this window.
+ break;
+ }
+ }
+
if (!overwriteTabs && firstWindow) {
// Move the originally open tabs to the end
let endPosition = tabbrowser.tabs.length - 1;
for (let i = 0; i < initialTabs.length; i++) {
tabbrowser.moveTabTo(initialTabs[i], endPosition);
}
}
@@ -3366,18 +3414,17 @@ var SessionStoreInternal = {
// ... and make sure that we don't exceed the max number of closed tabs
// we can restore.
this._windows[aWindow.__SSi]._closedTabs =
newClosedTabsData.slice(0, this._max_tabs_undo);
}
// Restore tabs, if any.
if (winData.tabs.length) {
- this.restoreTabs(aWindow, tabs, winData.tabs,
- (overwriteTabs ? (parseInt(winData.selected || "1")) : 0));
+ this.restoreTabs(aWindow, tabs, winData.tabs, selectTab);
}
// set smoothScroll back to the original value
tabstrip.smoothScroll = smoothScroll;
TelemetryStopwatch.finish("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
this._setWindowStateReady(aWindow);
@@ -3494,20 +3541,17 @@ var SessionStoreInternal = {
} else {
// Remove all previous tab data except tabs that should not be overriden.
tabsDataArray.splice(numTabsInWindow - numTabsToRestore);
}
// Let the tab data array have the right number of slots.
tabsDataArray.length = numTabsInWindow;
- // If provided, set the selected tab.
if (aSelectTab > 0 && aSelectTab <= aTabs.length) {
- tabbrowser.selectedTab = aTabs[aSelectTab - 1];
-
// Update the window state in case we shut down without being notified.
this._windows[aWindow.__SSi].selected = aSelectTab;
}
// If we restore the selected tab, make sure it goes first.
let selectedIndex = aTabs.indexOf(tabbrowser.selectedTab);
if (selectedIndex > -1) {
this.restoreTab(tabbrowser.selectedTab, aTabData[selectedIndex]);