Skip to content

Commit

Permalink
Bug 1580811 - Make the ContentPage browser work with out-of-process f…
Browse files Browse the repository at this point in the history
…rames, r=nika,zombie

Differential Revision: https://phabricator.services.mozilla.com/D80084
  • Loading branch information
Kashav Madan committed Jul 10, 2020
1 parent 3ddcbc3 commit 6d5f104
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 11 deletions.
7 changes: 5 additions & 2 deletions toolkit/components/extensions/ExtensionPolicyService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,11 @@ void ExtensionPolicyService::CheckDocument(Document* aDocument) {
if ((!mm || !mMessageManagers.Contains(mm)) &&
// With Fission, OOP iframes don't have a frame message manager, so we
// use the browser's MessageManagerGroup attribute to decide if content
// scripts should run. The "browsers" group includes iframes from tabs.
!group.EqualsLiteral("browsers")) {
// scripts should run. The "browsers" group includes iframes from tabs,
// and the "webext-browsers" group includes custom browsers for
// extension popups/sidebars and xpcshell tests.
!group.EqualsLiteral("browsers") &&
!group.EqualsLiteral("webext-browsers")) {
return;
}

Expand Down
47 changes: 41 additions & 6 deletions toolkit/components/extensions/ExtensionXPCShellUtils.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ var REMOTE_CONTENT_SCRIPTS = Services.prefs.getBoolPref(
false
);

const REMOTE_CONTENT_SUBFRAMES = Services.prefs.getBoolPref(
"fission.autostart",
false
);

let BASE_MANIFEST = Object.freeze({
applications: Object.freeze({
gecko: Object.freeze({
Expand Down Expand Up @@ -181,11 +186,13 @@ function promiseBrowserLoaded(browser, url, redirectUrl) {
class ContentPage {
constructor(
remote = REMOTE_CONTENT_SCRIPTS,
remoteSubframes = REMOTE_CONTENT_SUBFRAMES,
extension = null,
privateBrowsing = false,
userContextId = undefined
) {
this.remote = remote;
this.remoteSubframes = remote && remoteSubframes;
this.extension = extension;
this.privateBrowsing = privateBrowsing;
this.userContextId = userContextId;
Expand All @@ -194,14 +201,20 @@ class ContentPage {
}

async _initBrowser() {
this.windowlessBrowser = Services.appShell.createWindowlessBrowser(true);

let chromeFlags = 0;
if (this.remote) {
chromeFlags |= Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW;
}
if (this.remoteSubframes) {
chromeFlags |= Ci.nsIWebBrowserChrome.CHROME_FISSION_WINDOW;
}
if (this.privateBrowsing) {
let loadContext = this.windowlessBrowser.docShell.QueryInterface(
Ci.nsILoadContext
);
loadContext.usePrivateBrowsing = true;
chromeFlags |= Ci.nsIWebBrowserChrome.CHROME_PRIVATE_WINDOW;
}
this.windowlessBrowser = Services.appShell.createWindowlessBrowser(
true,
chromeFlags
);

let system = Services.scriptSecurityManager.getSystemPrincipal();

Expand Down Expand Up @@ -229,6 +242,7 @@ class ContentPage {
let browser = chromeDoc.createXULElement("browser");
browser.setAttribute("type", "content");
browser.setAttribute("disableglobalhistory", "true");
browser.setAttribute("messagemanagergroup", "webext-browsers");
if (this.userContextId) {
browser.setAttribute("usercontextid", this.userContextId);
}
Expand All @@ -244,6 +258,12 @@ class ContentPage {
if (this.remote) {
awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
browser.setAttribute("remote", "true");

browser.setAttribute("maychangeremoteness", "true");
browser.addEventListener(
"DidChangeBrowserRemoteness",
this.didChangeBrowserRemoteness.bind(this)
);
}

chromeDoc.documentElement.appendChild(browser);
Expand Down Expand Up @@ -275,6 +295,12 @@ class ContentPage {
this.browser.messageManager.loadFrameScript(frameScript, false, true);
}

didChangeBrowserRemoteness(event) {
// XXX: Tests can load their own additional frame scripts, so we may need to
// track all scripts that have been loaded, and reload them here?
this.loadFrameScript(frameScript);
}

async loadURL(url, redirectUrl = undefined) {
await this.browserReady;

Expand All @@ -297,6 +323,10 @@ class ContentPage {

let { messageManager } = this.browser;

this.browser.removeEventListener(
"DidChangeBrowserRemoteness",
this.didChangeBrowserRemoteness.bind(this)
);
this.browser = null;

this.windowlessBrowser.close();
Expand Down Expand Up @@ -1024,6 +1054,9 @@ var ExtensionTestUtils = {
* @param {boolean} [options.remote]
* If true, load the URL in a content process. If false, load
* it in the parent process.
* @param {boolean} [options.remoteSubframes]
* If true, load cross-origin frames in separate content processes.
* This is ignored if |options.remote| is false.
* @param {string} [options.redirectUrl]
* An optional URL that the initial page is expected to
* redirect to.
Expand All @@ -1035,6 +1068,7 @@ var ExtensionTestUtils = {
{
extension = undefined,
remote = undefined,
remoteSubframes = undefined,
redirectUrl = undefined,
privateBrowsing = false,
userContextId = undefined,
Expand All @@ -1044,6 +1078,7 @@ var ExtensionTestUtils = {

let contentPage = new ContentPage(
remote,
remoteSubframes,
extension && extension.extension,
privateBrowsing,
userContextId
Expand Down
22 changes: 21 additions & 1 deletion xpfe/appshell/nsAppShellService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,18 @@ WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell) {
}

NS_IMETHODIMP
nsAppShellService::CreateWindowlessBrowser(bool aIsChrome,
nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, uint32_t aChromeMask,
nsIWindowlessBrowser** aResult) {
if (aChromeMask) {
MOZ_DIAGNOSTIC_ASSERT(aIsChrome, "Got chrome flags for non-chrome browser");
if (aChromeMask & ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW |
nsIWebBrowserChrome::CHROME_FISSION_WINDOW |
nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
NS_ERROR("Received unexpected chrome flags");
return NS_ERROR_FAILURE;
}
}

/* First, we set the container window for our instance of nsWebBrowser. Since
* we don't actually have a window, we instead set the container window to be
* an instance of WebBrowserChrome2Stub, which provides a stub implementation
Expand Down Expand Up @@ -462,6 +472,16 @@ nsAppShellService::CreateWindowlessBrowser(bool aIsChrome,
aIsChrome ? BrowsingContext::Type::Chrome
: BrowsingContext::Type::Content);

if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
browsingContext->SetRemoteTabs(true);
}
if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) {
browsingContext->SetRemoteSubframes(true);
}
if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
browsingContext->SetPrivateBrowsing(true);
}

/* Next, we create an instance of nsWebBrowser. Instances of this class have
* an associated doc shell, which is what we're interested in.
*/
Expand Down
7 changes: 5 additions & 2 deletions xpfe/appshell/nsIAppShellService.idl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface nsIAppShellService : nsISupports
* @param aParent the parent window. Can be null.
* @param aUrl the contents of the new window.
* @param aChromeMask chrome flags affecting the kind of OS border
* given to the window. see nsIBrowserWindow for
* given to the window. see nsIWebBrowserChrome for
* bit/flag definitions.
* @param aCallbacks interface providing C++ hooks for window initialization
* before the window is made visible. Can be null.
Expand All @@ -49,8 +49,11 @@ interface nsIAppShellService : nsISupports
* It is used to simulate DOM windows without an actual physical
* representation.
* @param aIsChrome Set true if you want to use it for chrome content.
* @param aChromeMask Used to specify chrome flags that should be set on the
* window. See nsIWebBrowserChrome for flag definitions.
*/
nsIWindowlessBrowser createWindowlessBrowser([optional] in bool aIsChrome);
nsIWindowlessBrowser createWindowlessBrowser([optional] in bool aIsChrome,
[optional] in uint32_t aChromeMask);

[noscript]
void createHiddenWindow();
Expand Down

0 comments on commit 6d5f104

Please sign in to comment.