зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
2bd748f3ca
|
@ -1540,14 +1540,6 @@ pref("browser.tabs.remote.warmup.enabled", true);
|
|||
pref("browser.tabs.remote.warmup.enabled", false);
|
||||
#endif
|
||||
|
||||
// Caches tab layers to improve perceived performance
|
||||
// of tab switches.
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("browser.tabs.remote.tabCacheSize", 5);
|
||||
#else
|
||||
pref("browser.tabs.remote.tabCacheSize", 0);
|
||||
#endif
|
||||
|
||||
pref("browser.tabs.remote.warmup.maxTabs", 3);
|
||||
pref("browser.tabs.remote.warmup.unloadDelayMs", 2000);
|
||||
|
||||
|
|
|
@ -195,12 +195,6 @@ We use a few tricks and optimizations to help improve the perceived performance
|
|||
|
||||
4. On platforms that support ``occlusionstatechange`` events (as of this writing, only macOS) and ``sizemodechange`` events (Windows, macOS and Linux), we stop rendering the layers for the currently selected tab when the window is minimized or fully occluded by another window.
|
||||
|
||||
5. Based on the browser.tabs.remote.tabCacheSize pref, we keep recently used tabs'
|
||||
layers around to speed up tab switches by avoiding the round trip to the content
|
||||
process. This uses a simple array (``_tabLayerCache``) inside tabbrowser.js, which
|
||||
we examine when determining if we want to unload a tab's layers or not. This is still
|
||||
experimental as of Nightly 62.
|
||||
|
||||
.. _async-tab-switcher.warming:
|
||||
|
||||
Warming
|
||||
|
|
|
@ -97,8 +97,6 @@ window._gBrowser = {
|
|||
|
||||
_contentWaitingCount: 0,
|
||||
|
||||
_tabLayerCache: [],
|
||||
|
||||
tabAnimationsInProgress: 0,
|
||||
|
||||
_XUL_NS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||
|
@ -2758,13 +2756,6 @@ window._gBrowser = {
|
|||
}
|
||||
}
|
||||
|
||||
// this._switcher would normally cover removing a tab from this
|
||||
// cache, but we may not have one at this time.
|
||||
let tabCacheIndex = this._tabLayerCache.indexOf(aTab);
|
||||
if (tabCacheIndex != -1) {
|
||||
this._tabLayerCache.splice(tabCacheIndex, 1);
|
||||
}
|
||||
|
||||
this._blurTab(aTab);
|
||||
|
||||
var closeWindow = false;
|
||||
|
|
|
@ -20,8 +20,6 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingMax",
|
|||
"browser.tabs.remote.warmup.maxTabs");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingUnloadDelayMs",
|
||||
"browser.tabs.remote.warmup.unloadDelayMs");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gTabCacheSize",
|
||||
"browser.tabs.remote.tabCacheSize");
|
||||
|
||||
/**
|
||||
* The tab switcher is responsible for asynchronously switching
|
||||
|
@ -293,10 +291,6 @@ class AsyncTabSwitcher {
|
|||
this.window.isFullyOccluded;
|
||||
}
|
||||
|
||||
get tabLayerCache() {
|
||||
return this.tabbrowser._tabLayerCache;
|
||||
}
|
||||
|
||||
finish() {
|
||||
this.log("FINISH");
|
||||
|
||||
|
@ -514,15 +508,6 @@ class AsyncTabSwitcher {
|
|||
this.assert(this.tabbrowser._switcher);
|
||||
this.assert(this.tabbrowser._switcher === this);
|
||||
|
||||
for (let i = 0; i < this.tabLayerCache.length; i++) {
|
||||
let tab = this.tabLayerCache[i];
|
||||
if (!tab.linkedBrowser) {
|
||||
this.tabState.delete(tab);
|
||||
this.tabLayerCache.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
for (let [tab, ] of this.tabState) {
|
||||
if (!tab.linkedBrowser) {
|
||||
this.tabState.delete(tab);
|
||||
|
@ -581,13 +566,6 @@ class AsyncTabSwitcher {
|
|||
this.loadRequestedTab();
|
||||
}
|
||||
|
||||
let numBackgroundCached = 0;
|
||||
for (let tab of this.tabLayerCache) {
|
||||
if (tab !== this.requestedTab) {
|
||||
numBackgroundCached++;
|
||||
}
|
||||
}
|
||||
|
||||
// See how many tabs still have work to do.
|
||||
let numPending = 0;
|
||||
let numWarming = 0;
|
||||
|
@ -597,9 +575,7 @@ class AsyncTabSwitcher {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (state == this.STATE_LOADED &&
|
||||
tab !== this.requestedTab &&
|
||||
!this.tabLayerCache.includes(tab)) {
|
||||
if (state == this.STATE_LOADED && tab !== this.requestedTab) {
|
||||
numPending++;
|
||||
|
||||
if (tab !== this.visibleTab) {
|
||||
|
@ -622,10 +598,8 @@ class AsyncTabSwitcher {
|
|||
|
||||
this.maybeFinishTabSwitch();
|
||||
|
||||
if (numWarming > gTabWarmingMax || numBackgroundCached > 0) {
|
||||
if (numWarming > gTabWarmingMax) {
|
||||
this.logState("Hit tabWarmingMax");
|
||||
}
|
||||
if (numWarming > gTabWarmingMax) {
|
||||
this.logState("Hit tabWarmingMax");
|
||||
if (this.unloadTimer) {
|
||||
this.clearTimer(this.unloadTimer);
|
||||
}
|
||||
|
@ -658,34 +632,21 @@ class AsyncTabSwitcher {
|
|||
this.warmingTabs = new WeakSet();
|
||||
let numPending = 0;
|
||||
|
||||
for (let tab of this.tabLayerCache) {
|
||||
if (tab !== this.requestedTab) {
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.preserveLayers(true);
|
||||
browser.docShellIsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unload any tabs that can be unloaded.
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (this.tabbrowser._printPreviewBrowsers.has(tab.linkedBrowser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let isInLayerCache = this.tabLayerCache.includes(tab);
|
||||
|
||||
if (state == this.STATE_LOADED &&
|
||||
!this.maybeVisibleTabs.has(tab) &&
|
||||
tab !== this.lastVisibleTab &&
|
||||
tab !== this.loadingTab &&
|
||||
tab !== this.requestedTab &&
|
||||
!isInLayerCache) {
|
||||
tab !== this.requestedTab) {
|
||||
this.setTabState(tab, this.STATE_UNLOADING);
|
||||
}
|
||||
|
||||
if (state != this.STATE_UNLOADED &&
|
||||
tab !== this.requestedTab &&
|
||||
!isInLayerCache) {
|
||||
if (state != this.STATE_UNLOADED && tab !== this.requestedTab) {
|
||||
numPending++;
|
||||
}
|
||||
}
|
||||
|
@ -909,49 +870,17 @@ class AsyncTabSwitcher {
|
|||
this.queueUnload(gTabWarmingUnloadDelayMs);
|
||||
}
|
||||
|
||||
cleanUpTabAfterEviction(tab) {
|
||||
this.assert(tab !== this.requestedTab);
|
||||
let browser = tab.linkedBrowser;
|
||||
if (browser) {
|
||||
browser.preserveLayers(false);
|
||||
}
|
||||
this.setTabState(tab, this.STATE_UNLOADING);
|
||||
}
|
||||
|
||||
evictOldestTabFromCache() {
|
||||
let tab = this.tabLayerCache.shift();
|
||||
this.cleanUpTabAfterEviction(tab);
|
||||
}
|
||||
|
||||
maybePromoteTabInLayerCache(tab) {
|
||||
if (gTabCacheSize > 1 &&
|
||||
tab.linkedBrowser.isRemoteBrowser &&
|
||||
tab.linkedBrowser.currentURI.spec != "about:blank") {
|
||||
let tabIndex = this.tabLayerCache.indexOf(tab);
|
||||
|
||||
if (tabIndex != -1) {
|
||||
this.tabLayerCache.splice(tabIndex, 1);
|
||||
}
|
||||
|
||||
this.tabLayerCache.push(tab);
|
||||
|
||||
if (this.tabLayerCache.length > gTabCacheSize) {
|
||||
this.evictOldestTabFromCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the user asks to switch to a given tab.
|
||||
requestTab(tab) {
|
||||
if (tab === this.requestedTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tabState = this.getTabState(tab);
|
||||
if (gTabWarmingEnabled) {
|
||||
let warmingState = "disqualified";
|
||||
|
||||
if (this.canWarmTab(tab)) {
|
||||
let tabState = this.getTabState(tab);
|
||||
if (tabState == this.STATE_LOADING) {
|
||||
warmingState = "stillLoading";
|
||||
} else if (tabState == this.STATE_LOADED) {
|
||||
|
@ -977,9 +906,6 @@ class AsyncTabSwitcher {
|
|||
this.startTabSwitch();
|
||||
|
||||
this.requestedTab = tab;
|
||||
if (tabState == this.STATE_LOADED) {
|
||||
this.maybeVisibleTabs.clear();
|
||||
}
|
||||
|
||||
tab.linkedBrowser.setAttribute("primary", "true");
|
||||
if (this.lastPrimaryTab && this.lastPrimaryTab != tab) {
|
||||
|
@ -1066,10 +992,6 @@ class AsyncTabSwitcher {
|
|||
if (this.switchInProgress && this.requestedTab &&
|
||||
(this.getTabState(this.requestedTab) == this.STATE_LOADED ||
|
||||
this.requestedTab === this.blankTab)) {
|
||||
if (this.requestedTab !== this.blankTab) {
|
||||
this.maybePromoteTabInLayerCache(this.requestedTab);
|
||||
}
|
||||
|
||||
// After this point the tab has switched from the content thread's point of view.
|
||||
// The changes will be visible after the next refresh driver tick + composite.
|
||||
let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", this.window);
|
||||
|
@ -1156,37 +1078,19 @@ class AsyncTabSwitcher {
|
|||
let tab = this.tabbrowser.tabs[i];
|
||||
let state = this.getTabState(tab);
|
||||
let isWarming = this.warmingTabs.has(tab);
|
||||
let isCached = this.tabLayerCache.includes(tab);
|
||||
let isClosing = tab.closing;
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
let isActive = linkedBrowser && linkedBrowser.docShellIsActive;
|
||||
let isRendered = linkedBrowser && linkedBrowser.renderLayers;
|
||||
|
||||
accum += i + ":";
|
||||
if (tab === this.lastVisibleTab) accum += "V";
|
||||
if (tab === this.loadingTab) accum += "L";
|
||||
if (tab === this.requestedTab) accum += "R";
|
||||
if (tab === this.blankTab) accum += "B";
|
||||
|
||||
let extraStates = "";
|
||||
if (isWarming) extraStates += "W";
|
||||
if (isCached) extraStates += "C";
|
||||
if (isClosing) extraStates += "X";
|
||||
if (isActive) extraStates += "A";
|
||||
if (isRendered) extraStates += "R";
|
||||
if (extraStates != "") {
|
||||
accum += `(${extraStates})`;
|
||||
}
|
||||
|
||||
if (isWarming) accum += "(W)";
|
||||
if (state == this.STATE_LOADED) accum += "(+)";
|
||||
if (state == this.STATE_LOADING) accum += "(+?)";
|
||||
if (state == this.STATE_UNLOADED) accum += "(-)";
|
||||
if (state == this.STATE_UNLOADING) accum += "(-?)";
|
||||
accum += " ";
|
||||
}
|
||||
|
||||
accum += "cached: " + this.tabLayerCache.length;
|
||||
|
||||
if (this._useDumpForLogging) {
|
||||
dump(accum + "\n");
|
||||
} else {
|
||||
|
|
|
@ -14,10 +14,6 @@ const kMaxPaints = 10;
|
|||
add_task(async function() {
|
||||
let result, tabSwitchedPromise;
|
||||
|
||||
// We want to make sure that we will paint in cases where we need to. The
|
||||
// tab layer cache just gets in the way of measuring that.
|
||||
await SpecialPowers.pushPrefEnv({set: [["browser.tabs.remote.tabCacheSize", 0]]});
|
||||
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
|
||||
let testTab = gBrowser.selectedTab;
|
||||
|
|
|
@ -1,33 +1,5 @@
|
|||
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
|
||||
function waitForPluginVisibility(browser, shouldBeVisible, errorMessage) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let lastTransactionId = windowUtils.lastTransactionId;
|
||||
let listener = async (event) => {
|
||||
let visibility = await ContentTask.spawn(browser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
|
||||
if (visibility == shouldBeVisible) {
|
||||
window.removeEventListener("MozAfterPaint", listener);
|
||||
resolve();
|
||||
} else if (event && event.transactionId > lastTransactionId) {
|
||||
// We want to allow for one failed check since we call listener
|
||||
// directly, but if we get a MozAfterPaint notification and we
|
||||
// still don't have the correct visibility, that's likely a
|
||||
// problem.
|
||||
reject(new Error("MozAfterPaint had a mismatched plugin visibility"));
|
||||
}
|
||||
};
|
||||
window.addEventListener("MozAfterPaint", listener);
|
||||
listener(null);
|
||||
});
|
||||
}
|
||||
|
||||
// tests that we get plugin updates when we flip between tabs that
|
||||
// have the same plugin in the same position in the page.
|
||||
|
||||
|
@ -57,44 +29,76 @@ add_task(async function() {
|
|||
// plugin tab 2 should be selected
|
||||
is(gBrowser.selectedTab == pluginTab2, true, "plugin2 is selected");
|
||||
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
true, "plugin2 should be visible");
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin2 is visible");
|
||||
|
||||
// select plugin1 tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = pluginTab1;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
true, "plugin1 should be visible");
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin1 is visible");
|
||||
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
false, "plugin2 should be hidden");
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin2 is hidden");
|
||||
|
||||
// select plugin2 tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = pluginTab2;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
true, "plugin2 should be visible");
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, true, "plugin2 is visible");
|
||||
|
||||
// select test tab
|
||||
tabSwitchedPromise = waitTabSwitched();
|
||||
gBrowser.selectedTab = testTab;
|
||||
await tabSwitchedPromise;
|
||||
|
||||
await waitForPluginVisibility(pluginTab1.linkedBrowser,
|
||||
false, "plugin1 should be hidden");
|
||||
result = await ContentTask.spawn(pluginTab1.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin1 is hidden");
|
||||
|
||||
await waitForPluginVisibility(pluginTab2.linkedBrowser,
|
||||
false, "plugin2 should be hidden");
|
||||
result = await ContentTask.spawn(pluginTab2.linkedBrowser, null, async function() {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("testplugin");
|
||||
return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
|
||||
});
|
||||
is(result, false, "plugin2 is hidden");
|
||||
|
||||
gBrowser.removeTab(pluginTab1);
|
||||
gBrowser.removeTab(pluginTab2);
|
||||
|
|
Загрузка…
Ссылка в новой задаче