зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1385453 - Add API to tabbrowser to speculatively warm-up tabs for tab switching. r=billm
MozReview-Commit-ID: FIVx5d6ZOqq --HG-- extra : rebase_source : 81749fb1c5ae398b7ff28ce5bcd4761b7d458a93
This commit is contained in:
Родитель
d9fd1ad2a1
Коммит
415debd9d4
|
@ -1547,6 +1547,11 @@ pref("browser.tabs.remote.autostart.1", false);
|
||||||
pref("browser.tabs.remote.autostart.2", true);
|
pref("browser.tabs.remote.autostart.2", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// For speculatively warming up tabs to improve perceived
|
||||||
|
// performance while using the async tab switcher.
|
||||||
|
pref("browser.tabs.remote.maxWarmingTabs", 3);
|
||||||
|
pref("browser.tabs.remote.warmingUnloadDelayMs", 2000);
|
||||||
|
|
||||||
// For the about:tabcrashed page
|
// For the about:tabcrashed page
|
||||||
pref("browser.tabs.crashReporting.sendReport", true);
|
pref("browser.tabs.crashReporting.sendReport", true);
|
||||||
pref("browser.tabs.crashReporting.includeURL", false);
|
pref("browser.tabs.crashReporting.includeURL", false);
|
||||||
|
|
|
@ -4086,6 +4086,12 @@
|
||||||
// removed from the set upon MozAfterPaint.
|
// removed from the set upon MozAfterPaint.
|
||||||
maybeVisibleTabs: new Set([this.selectedTab]),
|
maybeVisibleTabs: new Set([this.selectedTab]),
|
||||||
|
|
||||||
|
// This holds onto the set of tabs that we've been asked to warm up.
|
||||||
|
// This is used only for Telemetry and logging, and (in order to not
|
||||||
|
// over-complicate the async tab switcher any further) has nothing to do
|
||||||
|
// with how warmed tabs are loaded and unloaded.
|
||||||
|
warmingTabs: new WeakSet(),
|
||||||
|
|
||||||
STATE_UNLOADED: 0,
|
STATE_UNLOADED: 0,
|
||||||
STATE_LOADING: 1,
|
STATE_LOADING: 1,
|
||||||
STATE_LOADED: 2,
|
STATE_LOADED: 2,
|
||||||
|
@ -4140,6 +4146,7 @@
|
||||||
this.onLayersReady(browser);
|
this.onLayersReady(browser);
|
||||||
}
|
}
|
||||||
} else if (state == this.STATE_UNLOADING) {
|
} else if (state == this.STATE_UNLOADING) {
|
||||||
|
this.unwarmTab(tab);
|
||||||
browser.docShellIsActive = false;
|
browser.docShellIsActive = false;
|
||||||
if (!tabParent) {
|
if (!tabParent) {
|
||||||
this.onLayersCleared(browser);
|
this.onLayersCleared(browser);
|
||||||
|
@ -4168,6 +4175,11 @@
|
||||||
init() {
|
init() {
|
||||||
this.log("START");
|
this.log("START");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(this, "MAX_WARMING_TABS",
|
||||||
|
"browser.tabs.remote.maxWarmingTabs", 3);
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(this, "WARMING_UNLOAD_DELAY" /* ms */,
|
||||||
|
"browser.tabs.remote.warmingUnloadDelayMs", 2000);
|
||||||
|
|
||||||
// If we minimized the window before the switcher was activated,
|
// If we minimized the window before the switcher was activated,
|
||||||
// we might have set the preserveLayers flag for the current
|
// we might have set the preserveLayers flag for the current
|
||||||
// browser. Let's clear it.
|
// browser. Let's clear it.
|
||||||
|
@ -4417,6 +4429,7 @@
|
||||||
for (let [tab, ] of this.tabState) {
|
for (let [tab, ] of this.tabState) {
|
||||||
if (!tab.linkedBrowser) {
|
if (!tab.linkedBrowser) {
|
||||||
this.tabState.delete(tab);
|
this.tabState.delete(tab);
|
||||||
|
this.unwarmTab(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4474,6 +4487,7 @@
|
||||||
|
|
||||||
// See how many tabs still have work to do.
|
// See how many tabs still have work to do.
|
||||||
let numPending = 0;
|
let numPending = 0;
|
||||||
|
let numWarming = 0;
|
||||||
for (let [tab, state] of this.tabState) {
|
for (let [tab, state] of this.tabState) {
|
||||||
// Skip print preview browsers since they shouldn't affect tab switching.
|
// Skip print preview browsers since they shouldn't affect tab switching.
|
||||||
if (this.tabbrowser._printPreviewBrowsers.has(tab.linkedBrowser)) {
|
if (this.tabbrowser._printPreviewBrowsers.has(tab.linkedBrowser)) {
|
||||||
|
@ -4482,6 +4496,10 @@
|
||||||
|
|
||||||
if (state == this.STATE_LOADED && tab !== this.requestedTab) {
|
if (state == this.STATE_LOADED && tab !== this.requestedTab) {
|
||||||
numPending++;
|
numPending++;
|
||||||
|
|
||||||
|
if (tab !== this.visibleTab) {
|
||||||
|
numWarming++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (state == this.STATE_LOADING || state == this.STATE_UNLOADING) {
|
if (state == this.STATE_LOADING || state == this.STATE_UNLOADING) {
|
||||||
numPending++;
|
numPending++;
|
||||||
|
@ -4497,8 +4515,14 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.blankTab) {
|
this.maybeFinishTabSwitch();
|
||||||
this.maybeFinishTabSwitch();
|
|
||||||
|
if (numWarming > this.MAX_WARMING_TABS) {
|
||||||
|
this.logState("Hit MAX_WARMING_TABS");
|
||||||
|
if (this.unloadTimer) {
|
||||||
|
this.clearTimer(this.unloadTimer);
|
||||||
|
}
|
||||||
|
this.onUnloadTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numPending == 0) {
|
if (numPending == 0) {
|
||||||
|
@ -4512,6 +4536,7 @@
|
||||||
onUnloadTimeout() {
|
onUnloadTimeout() {
|
||||||
this.logState("onUnloadTimeout");
|
this.logState("onUnloadTimeout");
|
||||||
this.unloadTimer = null;
|
this.unloadTimer = null;
|
||||||
|
this.warmingTabs = new WeakSet();
|
||||||
this.preActions();
|
this.preActions();
|
||||||
|
|
||||||
let numPending = 0;
|
let numPending = 0;
|
||||||
|
@ -4561,8 +4586,6 @@
|
||||||
this.getTabState(tab) == this.STATE_LOADED);
|
this.getTabState(tab) == this.STATE_LOADED);
|
||||||
this.setTabState(tab, this.STATE_LOADED);
|
this.setTabState(tab, this.STATE_LOADED);
|
||||||
|
|
||||||
this.maybeFinishTabSwitch();
|
|
||||||
|
|
||||||
if (this.loadingTab === tab) {
|
if (this.loadingTab === tab) {
|
||||||
this.clearTimer(this.loadTimer);
|
this.clearTimer(this.loadTimer);
|
||||||
this.loadTimer = null;
|
this.loadTimer = null;
|
||||||
|
@ -4575,7 +4598,6 @@
|
||||||
// around.
|
// around.
|
||||||
onPaint() {
|
onPaint() {
|
||||||
this.maybeVisibleTabs.clear();
|
this.maybeVisibleTabs.clear();
|
||||||
this.maybeFinishTabSwitch();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called when we're done clearing the layers for a tab.
|
// Called when we're done clearing the layers for a tab.
|
||||||
|
@ -4706,19 +4728,66 @@
|
||||||
this.setTabState(tab, this.STATE_LOADING);
|
this.setTabState(tab, this.STATE_LOADING);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
canWarmTab(tab) {
|
||||||
|
// If the tab is not yet inserted, closing, not remote,
|
||||||
|
// crashed, already visible, or already requested, warming
|
||||||
|
// up the tab makes no sense.
|
||||||
|
if (this.minimizedOrFullyOccluded ||
|
||||||
|
!tab.linkedPanel ||
|
||||||
|
tab.closing ||
|
||||||
|
!tab.linkedBrowser.isRemoteBrowser ||
|
||||||
|
!tab.linkedBrowser.frameLoader.tabParent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, if the tab is already in STATE_LOADING or
|
||||||
|
// STATE_LOADED somehow, there's no point in trying to
|
||||||
|
// warm it up.
|
||||||
|
let state = this.getTabState(tab);
|
||||||
|
if (state === this.STATE_LOADING ||
|
||||||
|
state === this.STATE_LOADED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
unwarmTab(tab) {
|
||||||
|
this.warmingTabs.delete(tab);
|
||||||
|
},
|
||||||
|
|
||||||
|
warmupTab(tab) {
|
||||||
|
if (!this.canWarmTab(tab)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logState("warmupTab " + this.tinfo(tab));
|
||||||
|
|
||||||
|
this.warmingTabs.add(tab);
|
||||||
|
this.setTabState(tab, this.STATE_LOADING);
|
||||||
|
this.suppressDisplayPortAndQueueUnload(tab, this.WARMING_UNLOAD_DELAY);
|
||||||
|
},
|
||||||
|
|
||||||
// Called when the user asks to switch to a given tab.
|
// Called when the user asks to switch to a given tab.
|
||||||
requestTab(tab) {
|
requestTab(tab) {
|
||||||
if (tab === this.requestedTab) {
|
if (tab === this.requestedTab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.unwarmTab(tab);
|
||||||
|
|
||||||
this._requestingTab = true;
|
this._requestingTab = true;
|
||||||
this.logState("requestTab " + this.tinfo(tab));
|
this.logState("requestTab " + this.tinfo(tab));
|
||||||
this.startTabSwitch();
|
this.startTabSwitch();
|
||||||
|
|
||||||
this.requestedTab = tab;
|
this.requestedTab = tab;
|
||||||
|
|
||||||
let browser = this.requestedTab.linkedBrowser;
|
this.suppressDisplayPortAndQueueUnload(this.requestedTab, this.UNLOAD_DELAY);
|
||||||
|
this._requestingTab = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
suppressDisplayPortAndQueueUnload(tab, unloadTimeout) {
|
||||||
|
let browser = tab.linkedBrowser;
|
||||||
let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||||
|
|
||||||
if (fl && fl.tabParent && !this.activeSuppressDisplayport.has(fl.tabParent)) {
|
if (fl && fl.tabParent && !this.activeSuppressDisplayport.has(fl.tabParent)) {
|
||||||
|
@ -4731,10 +4800,9 @@
|
||||||
if (this.unloadTimer) {
|
if (this.unloadTimer) {
|
||||||
this.clearTimer(this.unloadTimer);
|
this.clearTimer(this.unloadTimer);
|
||||||
}
|
}
|
||||||
this.unloadTimer = this.setTimer(() => this.onUnloadTimeout(), this.UNLOAD_DELAY);
|
this.unloadTimer = this.setTimer(() => this.onUnloadTimeout(), unloadTimeout);
|
||||||
|
|
||||||
this.postActions();
|
this.postActions();
|
||||||
this._requestingTab = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEvent(event, delayed = false) {
|
handleEvent(event, delayed = false) {
|
||||||
|
@ -4824,7 +4892,6 @@
|
||||||
TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS", window);
|
TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS", window);
|
||||||
this.addMarker("AsyncTabSwitch:SpinnerHidden");
|
this.addMarker("AsyncTabSwitch:SpinnerHidden");
|
||||||
// we do not get a onPaint after displaying the spinner
|
// we do not get a onPaint after displaying the spinner
|
||||||
this.maybeFinishTabSwitch();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addMarker(marker) {
|
addMarker(marker) {
|
||||||
|
@ -4876,12 +4943,14 @@
|
||||||
for (let i = 0; i < this.tabbrowser.tabs.length; i++) {
|
for (let i = 0; i < this.tabbrowser.tabs.length; i++) {
|
||||||
let tab = this.tabbrowser.tabs[i];
|
let tab = this.tabbrowser.tabs[i];
|
||||||
let state = this.getTabState(tab);
|
let state = this.getTabState(tab);
|
||||||
|
let isWarming = this.warmingTabs.has(tab);
|
||||||
|
|
||||||
accum += i + ":";
|
accum += i + ":";
|
||||||
if (tab === this.lastVisibleTab) accum += "V";
|
if (tab === this.lastVisibleTab) accum += "V";
|
||||||
if (tab === this.loadingTab) accum += "L";
|
if (tab === this.loadingTab) accum += "L";
|
||||||
if (tab === this.requestedTab) accum += "R";
|
if (tab === this.requestedTab) accum += "R";
|
||||||
if (tab === this.blankTab) accum += "B";
|
if (tab === this.blankTab) accum += "B";
|
||||||
|
if (isWarming) accum += "(W)";
|
||||||
if (state == this.STATE_LOADED) accum += "(+)";
|
if (state == this.STATE_LOADED) accum += "(+)";
|
||||||
if (state == this.STATE_LOADING) accum += "(+?)";
|
if (state == this.STATE_LOADING) accum += "(+?)";
|
||||||
if (state == this.STATE_UNLOADED) accum += "(-)";
|
if (state == this.STATE_UNLOADED) accum += "(-)";
|
||||||
|
@ -4901,6 +4970,15 @@
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<method name="warmupTab">
|
||||||
|
<parameter name="aTab"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
this._getSwitcher().warmupTab(aTab);
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<!-- BEGIN FORWARDED BROWSER PROPERTIES. IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
|
<!-- BEGIN FORWARDED BROWSER PROPERTIES. IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
|
||||||
MAKE SURE TO ADD IT HERE AS WELL. -->
|
MAKE SURE TO ADD IT HERE AS WELL. -->
|
||||||
<property name="canGoBack"
|
<property name="canGoBack"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче