Skip to content

Commit

Permalink
Bug 1479570. Get Add a getter to get a docshell from nsIWindowlessBro…
Browse files Browse the repository at this point in the history
…wser. r=kmag

Differential Revision: https://phabricator.services.mozilla.com/D2669

--HG--
extra : moz-landing-system : lando
  • Loading branch information
bzbarsky committed Aug 3, 2018
1 parent 9987b54 commit 357b6b1
Show file tree
Hide file tree
Showing 20 changed files with 80 additions and 81 deletions.
10 changes: 5 additions & 5 deletions browser/components/shell/HeadlessShell.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ function loadContentWindow(webNavigation, uri) {

async function takeScreenshot(fullWidth, fullHeight, contentWidth, contentHeight, path, url) {
try {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
var webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, url);
var windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
// nsIWindowlessBrowser inherits from nsIWebNavigation.
let contentWindow = await loadContentWindow(windowlessBrowser, url);
contentWindow.resizeTo(contentWidth, contentHeight);

let canvas = contentWindow.document.createElementNS("http://www.w3.org/1999/xhtml", "html:canvas");
Expand Down Expand Up @@ -82,8 +82,8 @@ async function takeScreenshot(fullWidth, fullHeight, contentWidth, contentHeight
} catch (e) {
dump("Failure taking screenshot: " + e + "\n");
} finally {
if (webNavigation) {
webNavigation.close();
if (windowlessBrowser) {
windowlessBrowser.close();
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions devtools/shared/tests/unit/test_console_filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ function createFakeAddonWindow({addonId} = {}) {
const principal = Services.scriptSecurityManager
.createCodebasePrincipal(baseURI, {});
const chromeWebNav = Services.appShell.createWindowlessBrowser(true);
const docShell = chromeWebNav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
const { docShell } = chromeWebNav;
docShell.createAboutBlankContentViewer(principal);
const addonWindow = docShell.contentViewer.DOMDocument.defaultView;

Expand Down
14 changes: 6 additions & 8 deletions docshell/test/chrome/test_bug565388.xul
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,12 @@ function test() {
}
}
var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].
createInstance(Ci.nsIPrincipal);
var webNav = Cc["@mozilla.org/appshell/appShellService;1"].
getService(Ci.nsIAppShellService).
createWindowlessBrowser(true);
var docShell = webNav.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDocShell);
var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
.getService(Ci.nsIPrincipal);
var webNav = Cc["@mozilla.org/appshell/appShellService;1"]
.getService(Ci.nsIAppShellService)
.createWindowlessBrowser(true);
var docShell = webNav.docShell;
docShell.createAboutBlankContentViewer(systemPrincipal);
var win = docShell.contentViewer.DOMDocument.defaultView;
Expand Down
2 changes: 1 addition & 1 deletion docshell/test/chrome/test_bug846906.xul
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=846906
var interfaceRequestor = windowlessBrowser.QueryInterface(Ci.nsIInterfaceRequestor);
ok(interfaceRequestor, "Should be able to query interface requestor interface");
var docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
var docShell = windowlessBrowser.docShell;
ok(docShell, "Should be able to get doc shell interface");
var document = webNavigation.document;
Expand Down
5 changes: 2 additions & 3 deletions docshell/test/chrome/test_docRedirect.xul
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1342989
var webNav = Cc["@mozilla.org/appshell/appShellService;1"].
getService(Ci.nsIAppShellService).createWindowlessBrowser(true);
let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDocShell);
let docShell = webNav.docShell;
docShell.createAboutBlankContentViewer(
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal));
Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal));
progressListener.add(docShell, function(success) {
webNav.close();
Expand Down
5 changes: 2 additions & 3 deletions docshell/test/unit/test_setUsePrivateBrowsing.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(async function() {
let webNav = Services.appShell.createWindowlessBrowser(false);

let loadContext = webNav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsILoadContext);
let docShell = webNav.docShell;

let docShell = webNav.getInterface(Ci.nsIDocShell);
let loadContext = docShell.QueryInterface(Ci.nsILoadContext);

equal(loadContext.usePrivateBrowsing, false, "Should start out in non-private mode");

Expand Down
3 changes: 1 addition & 2 deletions dom/tests/browser/browser_ConsoleAPI_originAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ function test()
.createCodebasePrincipal(baseURI, {});

let chromeWebNav = Services.appShell.createWindowlessBrowser(true);
let interfaceRequestor = chromeWebNav.QueryInterface(Ci.nsIInterfaceRequestor);
let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
let docShell = chromeWebNav.docShell;
docShell.createAboutBlankContentViewer(principal);

info("fake webextension docShell created");
Expand Down
3 changes: 1 addition & 2 deletions gfx/tests/browser/browser_windowless_troubleshoot_crash.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() {
let webNav = Services.appShell.createWindowlessBrowser(false);

let onLoaded = new Promise((resolve, reject) => {
let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let docShell = webNav.docShell;
let listener = {
observe(contentWindow, topic, data) {
let observedDocShell = contentWindow.docShell
Expand Down
3 changes: 1 addition & 2 deletions js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ add_task(async function() {

let webnav = Services.appShell.createWindowlessBrowser(false);

let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let docShell = webnav.docShell;

docShell.createAboutBlankContentViewer(principal);

Expand Down
3 changes: 1 addition & 2 deletions js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ function getWindowlessBrowser(url) {

let webnav = Services.appShell.createWindowlessBrowser(false);

let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let docShell = webnav.docShell;

docShell.createAboutBlankContentViewer(principal);

Expand Down
3 changes: 1 addition & 2 deletions js/xpconnect/tests/unit/test_xray_named_element_access.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(async function() {
let webnav = Services.appShell.createWindowlessBrowser(false);

let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let docShell = webnav.docShell;

docShell.createAboutBlankContentViewer(null);

Expand Down
6 changes: 2 additions & 4 deletions toolkit/components/extensions/ExtensionParent.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -1077,14 +1077,12 @@ class HiddenXULWindow {
// The windowless browser is a thin wrapper around a docShell that keeps
// its related resources alive. It implements nsIWebNavigation and
// forwards its methods to the underlying docShell, but cannot act as a
// docShell itself. Calling `getInterface(nsIDocShell)` gives us the
// docShell itself. Getting .docShell gives us the
// underlying docShell, and `QueryInterface(nsIWebNavigation)` gives us
// access to the webNav methods that are already available on the
// windowless browser, but contrary to appearances, they are not the same
// object.
this.chromeShell = this._windowlessBrowser
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
this.chromeShell = this._windowlessBrowser.docShell
.QueryInterface(Ci.nsIWebNavigation);

if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
Expand Down
5 changes: 2 additions & 3 deletions toolkit/components/extensions/ExtensionXPCShellUtils.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,8 @@ class ContentPage {

let system = Services.scriptSecurityManager.getSystemPrincipal();

let chromeShell = this.windowlessBrowser.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIWebNavigation);
let chromeShell = this.windowlessBrowser.docShell
.QueryInterface(Ci.nsIWebNavigation);

chromeShell.createAboutBlankContentViewer(system);
chromeShell.useGlobalHistory = false;
Expand Down
4 changes: 1 addition & 3 deletions toolkit/components/extensions/parent/ext-downloads.js
Original file line number Diff line number Diff line change
Expand Up @@ -708,9 +708,7 @@ this.downloads = class extends ExtensionAPI {

return new Promise((resolve, reject) => {
let chromeWebNav = Services.appShell.createWindowlessBrowser(true);
chromeWebNav
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
chromeWebNav.docShell
.createAboutBlankContentViewer(Services.scriptSecurityManager.getSystemPrincipal());

let img = chromeWebNav.document.createElement("img");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,7 @@ function loadImage(img, data) {

add_task(async function test_getFileIcon() {
let webNav = Services.appShell.createWindowlessBrowser(false);
let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let docShell = webNav.docShell;

let system = Services.scriptSecurityManager.getSystemPrincipal();
docShell.createAboutBlankContentViewer(system);
Expand Down
2 changes: 1 addition & 1 deletion toolkit/modules/HiddenFrame.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ HiddenFrame.prototype = {
}
};
this._webProgress.addProgressListener(this._listener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
let docShell = this._browser.getInterface(Ci.nsIDocShell);
let docShell = this._browser.docShell;
docShell.createAboutBlankContentViewer(Services.scriptSecurityManager.getSystemPrincipal());
docShell.useGlobalHistory = false;
this._browser.loadURI(XUL_PAGE, 0, null, null, null);
Expand Down
32 changes: 14 additions & 18 deletions widget/headless/tests/test_headless.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ registerCleanupFunction(() => { server.stop(() => {})});
// before they are called.
const progressListeners = new Map();

function loadContentWindow(webNavigation, uri) {
function loadContentWindow(windowlessBrowser, uri) {
return new Promise((resolve, reject) => {
webNavigation.loadURI(uri, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
let docShell = webNavigation.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
windowlessBrowser.loadURI(uri, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
let docShell = windowlessBrowser.docShell;
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
let progressListener = {
Expand All @@ -35,8 +34,6 @@ function loadContentWindow(webNavigation, uri) {
if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
return;
}
let docShell = webNavigation.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let contentWindow = docShell.domWindow;
webProgress.removeProgressListener(progressListener);
progressListeners.delete(progressListener);
Expand All @@ -55,8 +52,7 @@ function loadContentWindow(webNavigation, uri) {

add_task(async function test_snapshot() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, HEADLESS_URL);
let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL);
const contentWidth = 400;
const contentHeight = 300;
// Verify dimensions.
Expand Down Expand Up @@ -93,13 +89,13 @@ add_task(async function test_snapshot() {
}
ok(found, "Found blue text on page.");

webNavigation.close();
windowlessBrowser.close();
});

add_task(async function test_snapshot_widget_layers() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, HEADLESS_URL);
// nsIWindowlessBrowser inherits from nsIWebNavigation.
let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL);
const contentWidth = 1;
const contentHeight = 2;
// Verify dimensions.
Expand All @@ -125,14 +121,14 @@ add_task(async function test_snapshot_widget_layers() {
);
ok(true, "Snapshot with widget layers didn't crash.");

webNavigation.close();
windowlessBrowser.close();
});

// Ensure keydown events are triggered on the windowless browser.
add_task(async function test_keydown() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, HEADLESS_URL);
// nsIWindowlessBrowser inherits from nsIWebNavigation.
let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL);

let keydown = new Promise((resolve) => {
contentWindow.addEventListener("keydown", () => {
Expand All @@ -149,15 +145,15 @@ add_task(async function test_keydown() {
await keydown;
ok(true, "Send keydown didn't crash");

webNavigation.close();
windowlessBrowser.close();
});

// Test dragging the mouse on a button to ensure the creation of the drag
// service doesn't crash in headless.
add_task(async function test_mouse_drag() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = await loadContentWindow(webNavigation, HEADLESS_BUTTON_URL);
// nsIWindowlessBrowser inherits from nsIWebNavigation.
let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_BUTTON_URL);
contentWindow.resizeTo(400, 400);

let target = contentWindow.document.getElementById('btn');
Expand All @@ -175,5 +171,5 @@ add_task(async function test_mouse_drag() {

ok(true, "Send mouse event didn't crash");

webNavigation.close();
windowlessBrowser.close();
});
44 changes: 28 additions & 16 deletions xpfe/appshell/nsAppShellService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,25 +452,10 @@ class WindowlessBrowser final : public nsIWindowlessBrowser,
mInterfaceRequestor = do_QueryInterface(aBrowser);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIWINDOWLESSBROWSER
NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation)
NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)

NS_IMETHOD
Close() override
{
NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"WindowlessBrowser::Close called when not safe to run scripts");

mClosed = true;

mWebNavigation = nullptr;
mInterfaceRequestor = nullptr;

nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
return window->Destroy();
}

protected:
virtual ~WindowlessBrowser()
{
Expand Down Expand Up @@ -500,6 +485,33 @@ class WindowlessBrowser final : public nsIWindowlessBrowser,

NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation, nsIInterfaceRequestor)

NS_IMETHODIMP
WindowlessBrowser::Close()
{
NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"WindowlessBrowser::Close called when not safe to run scripts");

mClosed = true;

mWebNavigation = nullptr;
mInterfaceRequestor = nullptr;

nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
return window->Destroy();
}

NS_IMETHODIMP
WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell)
{
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mInterfaceRequestor);
if (!docShell) {
return NS_ERROR_NOT_INITIALIZED;
}
docShell.forget(aDocShell);
return NS_OK;
}


NS_IMETHODIMP
nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWindowlessBrowser **aResult)
Expand Down
8 changes: 8 additions & 0 deletions xpfe/appshell/nsIWindowlessBrowser.idl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "nsIWebNavigation.idl"

interface nsIDocShell;

/**
* This interface represents a nsIWebBrowser instance with no associated OS
* window. Its main function is to manage the lifetimes of those windows.
Expand All @@ -23,5 +25,11 @@ interface nsIWindowlessBrowser : nsIWebNavigation
* reference is released.
*/
void close();

/**
* Get the docshell for this browser. This is the docshell that gets
* navigated when the browser's nsIWebNavigation interface is used.
*/
readonly attribute nsIDocShell docShell;
};

3 changes: 1 addition & 2 deletions xpfe/appshell/test/test_windowlessBrowser.xul
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ function testWindowlessBrowser(chromePrivileged) {
ok(webNav, "createWindowlessBrowser should return a wevNav");
let interfaceRequestor = webNav.QueryInterface(Ci.nsIInterfaceRequestor);
let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
let docShell = webNav.docShell;
ok(docShell, "docShell should be defined");
ok(docShell.contentViewer.DOMDocument.defaultView, "docShell defaultView should be defined");
Expand Down

0 comments on commit 357b6b1

Please sign in to comment.