Bug 1391704 - Avoid flickering while moving tabs across windows, r=mconley.

This commit is contained in:
Florian Quèze 2017-09-01 00:42:31 +02:00
Родитель 0c9a3b08ee
Коммит 48761699cf
5 изменённых файлов: 74 добавлений и 44 удалений

Просмотреть файл

@ -1379,6 +1379,25 @@ var gBrowserInit = {
gRemoteControl.updateVisualCue(Marionette.running);
// If we are given a tab to swap in, take care of it before first paint to
// avoid an about:blank flash.
let tabToOpen = window.arguments && window.arguments[0];
if (tabToOpen instanceof XULElement) {
// Clear the reference to the tab from the arguments array.
window.arguments[0] = null;
// Stop the about:blank load
gBrowser.stop();
// make sure it has a docshell
gBrowser.docShell;
try {
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
} catch (e) {
Cu.reportError(e);
}
}
// Wait until chrome is painted before executing code not critical to making the window visible
this._boundDelayedStartup = this._delayedStartup.bind(this);
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
@ -1605,6 +1624,8 @@ var gBrowserInit = {
return;
}
// We don't check if uriToLoad is a XULElement because this case has
// already been handled before first paint, and the argument cleared.
if (uriToLoad instanceof Ci.nsIArray) {
let count = uriToLoad.length;
let specs = [];
@ -1622,39 +1643,6 @@ var gBrowserInit = {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
} catch (e) {}
} else if (uriToLoad instanceof XULElement) {
// swap the given tab with the default about:blank tab and then close
// the original tab in the other window.
let tabToOpen = uriToLoad;
// If this tab was passed as a window argument, clear the
// reference to it from the arguments array.
if (window.arguments[0] == tabToOpen) {
window.arguments[0] = null;
}
// Stop the about:blank load
gBrowser.stop();
// make sure it has a docshell
gBrowser.docShell;
// We must set usercontextid before updateBrowserRemoteness()
// so that the newly created remote tab child has correct usercontextid
if (tabToOpen.hasAttribute("usercontextid")) {
let usercontextid = tabToOpen.getAttribute("usercontextid");
gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
}
try {
// Make sure selectedBrowser has the same remote settings as the one
// we are swapping in.
gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
tabToOpen.linkedBrowser.isRemoteBrowser,
{ remoteType: tabToOpen.linkedBrowser.remoteType });
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
} catch (e) {
Cu.reportError(e);
}
} else if (window.arguments.length >= 3) {
// window.arguments[2]: referrer (nsIURI | string)
// [3]: postData (nsIInputStream)

Просмотреть файл

@ -3009,6 +3009,16 @@
newTab = true;
}
aTab._endRemoveArgs = [closeWindow, newTab];
// swapBrowsersAndCloseOther will take care of closing the window without animation.
if (closeWindow && aAdoptedByTab) {
// Remove the tab's filter to avoid leaking.
if (aTab.linkedPanel) {
this._tabFilters.delete(aTab);
}
return true;
}
if (!aTab._fullyOpen) {
// If the opening tab animation hasn't finished before we start closing the
@ -3079,7 +3089,6 @@
tab.owner = null;
}
aTab._endRemoveArgs = [closeWindow, newTab];
return true;
]]>
</body>
@ -3297,6 +3306,25 @@
if (!remoteBrowser._beginRemoveTab(aOtherTab, aOurTab, true))
return;
// If this is the last tab of the window, hide the window
// immediately without animation before the docshell swap, to avoid
// about:blank being painted.
let [closeWindow] = aOtherTab._endRemoveArgs;
if (closeWindow) {
let win = aOtherTab.ownerGlobal;
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
dwu.suppressAnimation(true);
// Only suppressing window animations isn't enough to avoid
// an empty content area being painted.
let baseWin = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIBaseWindow);
baseWin.visibility = false;
}
let modifiedAttrs = [];
if (aOtherTab.hasAttribute("muted")) {
aOurTab.setAttribute("muted", "true");
@ -3363,7 +3391,11 @@
}
// Finish tearing down the tab that's going away.
remoteBrowser._endRemoveTab(aOtherTab);
if (closeWindow) {
aOtherTab.ownerGlobal.close();
} else {
remoteBrowser._endRemoveTab(aOtherTab);
}
this.setTabTitle(aOurTab);
@ -3729,6 +3761,14 @@
for (var name in aOptions)
options += "," + name + "=" + aOptions[name];
// Play the tab closing animation to give immediate feedback while
// waiting for the new window to appear.
// content area when the docshells are swapped.
if (this.animationsEnabled) {
aTab.style.maxWidth = ""; // ensure that fade-out transition happens
aTab.removeAttribute("fadein");
}
// tell a new window to take the "dropped" tab
return window.openDialog(getBrowserURL(), "_blank", options, aTab);
]]>
@ -3851,7 +3891,8 @@
let linkedBrowser = aTab.linkedBrowser;
let params = { eventDetail: { adoptedTab: aTab },
preferredRemoteType: linkedBrowser.remoteType,
sameProcessAsFrameLoader: linkedBrowser.frameLoader };
sameProcessAsFrameLoader: linkedBrowser.frameLoader,
skipAnimation: true };
if (aTab.hasAttribute("usercontextid")) {
// new tab must have the same usercontextid as the old one
params.userContextId = aTab.getAttribute("usercontextid");
@ -7407,7 +7448,7 @@
window.moveTo(left, top);
window.focus();
} else {
let props = { screenX: left, screenY: top };
let props = { screenX: left, screenY: top, suppressanimation: 1 };
if (AppConstants.platform != "win") {
props.outerWidth = winWidth;
props.outerHeight = winHeight;

Просмотреть файл

@ -318,15 +318,15 @@ const PanelUI = {
*
* @return a Promise that resolves once the panel is ready to roll.
*/
ensureReady() {
if (this._readyPromise) {
return this._readyPromise;
async ensureReady() {
if (this._isReady) {
return;
}
await window.delayedStartupPromise;
this._ensureEventListenersAdded();
this.panel.hidden = false;
this._readyPromise = Promise.resolve();
this._isReady = true;
return this._readyPromise;
},
/**

Просмотреть файл

@ -26,8 +26,9 @@ add_task(function* () {
// Detach the tab with RDM open.
let newWindow = gBrowser.replaceTabWithWindow(tab);
// Waiting the tab is detached.
// Wait until the tab is detached and the new window is fully initialized.
yield waitTabIsDetached;
yield newWindow.delayedStartupPromise;
// Get the new tab instance.
tab = newWindow.gBrowser.tabs[0];

Просмотреть файл

@ -69,7 +69,7 @@ add_task(async function test_swap_frameloader_pagevisibility_events() {
// We have to wait for the window to load so we can get the selected browser
// to listen to.
await BrowserTestUtils.waitForEvent(newWindow, "load");
await BrowserTestUtils.waitForEvent(newWindow, "DOMContentLoaded");
let newWindowBrowser = newWindow.gBrowser.selectedBrowser;
// Wait for the expected pagehide and pageshow events on the initial browser