Bug 1047603 - [e10s] Make it possible to load new windows from non-remote browsers within an e10s window. r=smaug,billm, feedback=Mossop.

--HG--
extra : rebase_source : 79a033f40e880ef4e8769871e385344d7621c259
This commit is contained in:
Mike Conley 2014-09-12 14:34:28 -04:00
parent 2888b3aba7
commit b4fe79b253
5 changed files with 164 additions and 3 deletions

View File

@ -4132,7 +4132,7 @@ function nsBrowserAccess() { }
nsBrowserAccess.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
_openURIInNewTab: function(aURI, aOpener, aIsExternal) {
_openURIInNewTab: function(aURI, aOpener, aIsExternal, aEnsureNonRemote=false) {
let win, needToFocusWin;
// try the current window. if we're in a popup, fall back on the most recent browser window
@ -4164,6 +4164,15 @@ nsBrowserAccess.prototype = {
inBackground: loadInBackground});
let browser = win.gBrowser.getBrowserForTab(tab);
// It's possible that we've been asked to open a new non-remote
// browser in a window that defaults to having remote browsers -
// this can happen if we're opening the new tab due to a window.open
// or _blank anchor in a non-remote browser. If so, we have to force
// the newly opened browser to also not be remote.
if (win.gMultiProcessBrowser && aEnsureNonRemote) {
win.gBrowser.updateBrowserRemoteness(browser, false);
}
if (needToFocusWin || (!loadInBackground && aIsExternal))
win.focus();
@ -4171,6 +4180,14 @@ nsBrowserAccess.prototype = {
},
openURI: function (aURI, aOpener, aWhere, aContext) {
// This function should only ever be called if we're opening a URI
// from a non-remote browser window (via nsContentTreeOwner).
if (aOpener && Cu.isCrossProcessWrapper(aOpener)) {
Cu.reportError("nsBrowserAccess.openURI was passed a CPOW for aOpener. " +
"openURI should only ever be called from non-remote browsers.");
throw Cr.NS_ERROR_FAILURE;
}
var newWindow = null;
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
@ -4196,7 +4213,7 @@ nsBrowserAccess.prototype = {
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
break;
case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
let browser = this._openURIInNewTab(aURI, aOpener, isExternal);
let browser = this._openURIInNewTab(aURI, aOpener, isExternal, true);
if (browser)
newWindow = browser.contentWindow;
break;

View File

@ -483,3 +483,4 @@ skip-if = e10s
skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
[browser_bug1045809.js]
skip-if = e10s
[browser_bug1047603.js]

View File

@ -0,0 +1,139 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const OPEN_LOCATION_PREF = "browser.link.open_newwindow";
const NON_REMOTE_PAGE = "about:crashes";
const SIMPLE_PAGE_HTML = `
<a href="about:home" target="_blank" id="testAnchor">Open a window</a>
`;
function frame_script() {
addMessageListener("test:click", (message) => {
let element = content.document.getElementById("testAnchor");
element.click();
});
sendAsyncMessage("test:ready");
}
/**
* Returns a Promise that resolves once the frame_script is loaded
* in the browser, and has seen the DOMContentLoaded event.
*/
function waitForFrameScriptReady(mm) {
return new Promise((resolve, reject) => {
mm.addMessageListener("test:ready", function onTestReady() {
mm.removeMessageListener("test:ready", onTestReady);
resolve();
});
});
}
/**
* Takes some browser in some window, and forces that browser
* to become non-remote, and then navigates it to a page that
* we're not supposed to be displaying remotely. Returns a
* Promise that resolves when the browser is no longer remote.
*/
function prepareNonRemoteBrowser(aWindow, browser) {
aWindow.gBrowser.updateBrowserRemoteness(browser, false);
browser.loadURI(NON_REMOTE_PAGE);
return new Promise((resolve, reject) => {
waitForCondition(() => !browser.isRemoteBrowser, () => {
resolve();
}, "Waiting for browser to become non-remote");
})
}
registerCleanupFunction(() => {
Services.prefs.clearUserPref(OPEN_LOCATION_PREF);
});
/**
* Test that if we open a new tab from a link in a non-remote
* browser in an e10s window, that the new tab's browser is also
* not remote. Also tests with a private browsing window.
*/
add_task(function* test_new_tab() {
let normalWindow = yield promiseOpenAndLoadWindow({
remote: true
}, true);
let privateWindow = yield promiseOpenAndLoadWindow({
remote: true,
private: true,
}, true);
for (let testWindow of [normalWindow, privateWindow]) {
let testBrowser = testWindow.gBrowser.selectedBrowser;
yield prepareNonRemoteBrowser(testWindow, testBrowser);
// Get our framescript ready
let mm = testBrowser.messageManager;
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
let readyPromise = waitForFrameScriptReady(mm);
yield readyPromise;
// Inject our test HTML into our non-remote tab.
testBrowser.contentDocument.body.innerHTML = SIMPLE_PAGE_HTML;
// Click on the link in the browser, and wait for the new tab.
mm.sendAsyncMessage("test:click");
let tabOpenEvent = yield waitForNewTab(testWindow.gBrowser);
let newTab = tabOpenEvent.target;
ok(!newTab.linkedBrowser.isRemoteBrowser,
"The opened browser should not be remote.");
testWindow.gBrowser.removeTab(newTab);
}
normalWindow.close();
privateWindow.close();
});
/**
* Test that if we open a new window from a link in a non-remote
* browser in an e10s window, that the new window is not an e10s
* window. Also tests with a private browsing window.
*/
add_task(function* test_new_window() {
let normalWindow = yield promiseOpenAndLoadWindow({
remote: true
}, true);
let privateWindow = yield promiseOpenAndLoadWindow({
remote: true,
private: true,
}, true);
// Fiddle with the prefs so that we open target="_blank" links
// in new windows instead of new tabs.
Services.prefs.setIntPref(OPEN_LOCATION_PREF,
Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW);
for (let testWindow of [normalWindow, privateWindow]) {
let testBrowser = testWindow.gBrowser.selectedBrowser;
yield prepareNonRemoteBrowser(testWindow, testBrowser);
// Get our framescript ready
let mm = testBrowser.messageManager;
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
let readyPromise = waitForFrameScriptReady(mm);
yield readyPromise;
// Inject our test HTML into our non-remote window.
testBrowser.contentDocument.body.innerHTML = SIMPLE_PAGE_HTML;
// Click on the link in the browser, and wait for the new window.
let windowOpenPromise = promiseTopicObserved("browser-delayed-startup-finished");
mm.sendAsyncMessage("test:click");
let [newWindow] = yield windowOpenPromise;
ok(!newWindow.gMultiProcessBrowser,
"The opened window should not be an e10s window.");
newWindow.close();
}
normalWindow.close();
privateWindow.close();
Services.prefs.clearUserPref(OPEN_LOCATION_PREF);
});

View File

@ -665,3 +665,7 @@ function assertWebRTCIndicatorStatus(expected) {
}
}
}
function waitForNewTab(aTabBrowser) {
return promiseWaitForEvent(aTabBrowser.tabContainer, "TabOpen");
}

View File

@ -630,7 +630,7 @@ nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
}
if (parentContext) {
isUsingRemoteTabs = parentContext->UseRemoteTabs();
isUsingRemoteTabs = parentContext->UseRemoteTabs() && aOpeningTab;
}
nsCOMPtr<nsIDOMWindow> newDomWin =