diff --git a/toolkit/components/extensions/ExtensionPolicyService.cpp b/toolkit/components/extensions/ExtensionPolicyService.cpp index 8138694674da..c0f1fa4bf87f 100644 --- a/toolkit/components/extensions/ExtensionPolicyService.cpp +++ b/toolkit/components/extensions/ExtensionPolicyService.cpp @@ -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; } diff --git a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm index 68da673fa9ab..08163a4827e4 100644 --- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm +++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm @@ -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({ @@ -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; @@ -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(); @@ -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); } @@ -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); @@ -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; @@ -297,6 +323,10 @@ class ContentPage { let { messageManager } = this.browser; + this.browser.removeEventListener( + "DidChangeBrowserRemoteness", + this.didChangeBrowserRemoteness.bind(this) + ); this.browser = null; this.windowlessBrowser.close(); @@ -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. @@ -1035,6 +1068,7 @@ var ExtensionTestUtils = { { extension = undefined, remote = undefined, + remoteSubframes = undefined, redirectUrl = undefined, privateBrowsing = false, userContextId = undefined, @@ -1044,6 +1078,7 @@ var ExtensionTestUtils = { let contentPage = new ContentPage( remote, + remoteSubframes, extension && extension.extension, privateBrowsing, userContextId diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 8c57902a7f86..8e225eb3a5c1 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -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 @@ -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. */ diff --git a/xpfe/appshell/nsIAppShellService.idl b/xpfe/appshell/nsIAppShellService.idl index ac3129305fd8..d8de8ae14933 100644 --- a/xpfe/appshell/nsIAppShellService.idl +++ b/xpfe/appshell/nsIAppShellService.idl @@ -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. @@ -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();