Bug 1432509 - Allow async tab switcher to load requested tabs that are still warming. r?Gijs
This patch makes the following changes:
1. When layers are ready for a tab, we remove it from the warming list. We used to
do this once a tab was requested, but it actually makes more sense to keep the
"warming" state for the tab around until the layers have arrived.
2. In postActions, when choosing which tab to try to load layers for next,
allow for the possibility that the requested tab is being warmed (and
therefore in STATE_LOADING). If the tab is warming, loadRequestedTab
won't re-request layers, but will at least create the loadTimer which
is necessary so that updateDisplay knows that we're _trying_ to load
the warmed tab, and that we should at least wait for the loadTimer to
finish before showing the tab switch spinner.
MozReview-Commit-ID: WdYRTdzAoz
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4405,43 +4405,53 @@
},
clearTimer(timer) {
timer.cancel();
},
getTabState(tab) {
let state = this.tabState.get(tab);
+
+ // As an optimization, we lazily evaluate the state of tabs
+ // that we've never seen before. Once we've figured it out,
+ // we stash it in our state map.
if (state === undefined) {
state = this.STATE_UNLOADED;
if (tab && tab.linkedPanel) {
let b = tab.linkedBrowser;
if (b.renderLayers && b.hasLayers) {
state = this.STATE_LOADED;
} else if (b.renderLayers && !b.hasLayers) {
state = this.STATE_LOADING;
} else if (!b.renderLayers && b.hasLayers) {
state = this.STATE_UNLOADING;
}
}
+
+ this.setTabStateNoAction(tab, state);
}
return state;
},
setTabStateNoAction(tab, state) {
if (state == this.STATE_UNLOADED) {
this.tabState.delete(tab);
} else {
this.tabState.set(tab, state);
}
},
setTabState(tab, state) {
+ if (state == this.getTabState(tab)) {
+ return;
+ }
+
this.setTabStateNoAction(tab, state);
let browser = tab.linkedBrowser;
let {tabParent} = browser.frameLoader;
if (state == this.STATE_LOADING) {
this.assert(!this.minimizedOrFullyOccluded);
if (!this.tabbrowser.tabWarmingEnabled) {
@@ -4805,20 +4815,22 @@
this.loadingTab = null;
if (this.loadTimer) {
this.clearTimer(this.loadTimer);
this.loadTimer = null;
}
}
// If we're not loading anything, try loading the requested tab.
- let requestedState = this.getTabState(this.requestedTab);
+ let stateOfRequestedTab = this.getTabState(this.requestedTab);
if (!this.loadTimer && !this.minimizedOrFullyOccluded &&
- (requestedState == this.STATE_UNLOADED ||
- requestedState == this.STATE_UNLOADING)) {
+ (stateOfRequestedTab == this.STATE_UNLOADED ||
+ stateOfRequestedTab == this.STATE_UNLOADING ||
+ this.warmingTabs.has(this.requestedTab))) {
+ this.assert(stateOfRequestedTab != this.STATE_LOADED);
this.loadRequestedTab();
}
// See how many tabs still have work to do.
let numPending = 0;
let numWarming = 0;
for (let [tab, state] of this.tabState) {
// Skip print preview browsers since they shouldn't affect tab switching.
@@ -4927,16 +4939,17 @@
return;
}
this.logState(`onLayersReady(${tab._tPos}, ${browser.isRemoteBrowser})`);
this.assert(this.getTabState(tab) == this.STATE_LOADING ||
this.getTabState(tab) == this.STATE_LOADED);
this.setTabState(tab, this.STATE_LOADED);
+ this.unwarmTab(tab);
if (this.loadingTab === tab) {
this.clearTimer(this.loadTimer);
this.loadTimer = null;
this.loadingTab = null;
}
},
@@ -5148,18 +5161,16 @@
}
} else if (this.canWarmTab(tab)) {
warmingState = "notWarmed";
}
Services.telemetry
.getHistogramById("FX_TAB_SWITCH_REQUEST_TAB_WARMING_STATE")
.add(warmingState);
-
- this.unwarmTab(tab);
}
this._requestingTab = true;
this.logState("requestTab " + this.tinfo(tab));
this.startTabSwitch();
this.requestedTab = tab;