From 2ffdfa654d9937dad97107b42af6931a010b51ce Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 3 Aug 2018 00:05:07 +0000 Subject: [PATCH] Bug 1479570. Get Add a getter to get a docshell from nsIWindowlessBrowser. r=kmag Differential Revision: https://phabricator.services.mozilla.com/D2669 --- browser/components/shell/HeadlessShell.jsm | 10 ++--- .../tests/unit/test_console_filtering.js | 3 +- docshell/test/chrome/test_bug565388.xul | 14 +++--- docshell/test/chrome/test_bug846906.xul | 2 +- docshell/test/chrome/test_docRedirect.xul | 5 +-- .../test/unit/test_setUsePrivateBrowsing.js | 5 +-- .../browser_ConsoleAPI_originAttributes.js | 3 +- .../browser_windowless_troubleshoot_crash.js | 3 +- .../unit/test_nuke_sandbox_event_listeners.js | 3 +- .../unit/test_nuke_webextension_wrappers.js | 3 +- .../unit/test_xray_named_element_access.js | 3 +- .../components/extensions/ExtensionParent.jsm | 6 +-- .../extensions/ExtensionXPCShellUtils.jsm | 5 +-- .../extensions/parent/ext-downloads.js | 4 +- .../test/xpcshell/test_ext_downloads_misc.js | 3 +- toolkit/modules/HiddenFrame.jsm | 2 +- widget/headless/tests/test_headless.js | 32 ++++++-------- xpfe/appshell/nsAppShellService.cpp | 44 ++++++++++++------- xpfe/appshell/nsIWindowlessBrowser.idl | 8 ++++ xpfe/appshell/test/test_windowlessBrowser.xul | 3 +- 20 files changed, 80 insertions(+), 81 deletions(-) diff --git a/browser/components/shell/HeadlessShell.jsm b/browser/components/shell/HeadlessShell.jsm index f2bbf60f6f0d..26435ca244d0 100644 --- a/browser/components/shell/HeadlessShell.jsm +++ b/browser/components/shell/HeadlessShell.jsm @@ -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"); @@ -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(); } } } diff --git a/devtools/shared/tests/unit/test_console_filtering.js b/devtools/shared/tests/unit/test_console_filtering.js index 4fdf8ed941a4..2cc695e85d74 100644 --- a/devtools/shared/tests/unit/test_console_filtering.js +++ b/devtools/shared/tests/unit/test_console_filtering.js @@ -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; diff --git a/docshell/test/chrome/test_bug565388.xul b/docshell/test/chrome/test_bug565388.xul index a6e163d80438..9a80f821f52c 100644 --- a/docshell/test/chrome/test_bug565388.xul +++ b/docshell/test/chrome/test_bug565388.xul @@ -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; diff --git a/docshell/test/chrome/test_bug846906.xul b/docshell/test/chrome/test_bug846906.xul index 1f7c86b0a61b..8184fdd312e8 100644 --- a/docshell/test/chrome/test_bug846906.xul +++ b/docshell/test/chrome/test_bug846906.xul @@ -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; diff --git a/docshell/test/chrome/test_docRedirect.xul b/docshell/test/chrome/test_docRedirect.xul index 5ac021942262..a9c2118381e2 100644 --- a/docshell/test/chrome/test_docRedirect.xul +++ b/docshell/test/chrome/test_docRedirect.xul @@ -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(); diff --git a/docshell/test/unit/test_setUsePrivateBrowsing.js b/docshell/test/unit/test_setUsePrivateBrowsing.js index ed12bb1c2053..45f9b2867e49 100644 --- a/docshell/test/unit/test_setUsePrivateBrowsing.js +++ b/docshell/test/unit/test_setUsePrivateBrowsing.js @@ -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"); diff --git a/dom/tests/browser/browser_ConsoleAPI_originAttributes.js b/dom/tests/browser/browser_ConsoleAPI_originAttributes.js index 934796a3eca9..dc85765b30a4 100644 --- a/dom/tests/browser/browser_ConsoleAPI_originAttributes.js +++ b/dom/tests/browser/browser_ConsoleAPI_originAttributes.js @@ -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"); diff --git a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js index 1f86a8a0f4e7..989bfbaa1d34 100644 --- a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js +++ b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js @@ -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 diff --git a/js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js b/js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js index 05804aa169df..dc3b96d9c11e 100644 --- a/js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js +++ b/js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js @@ -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); diff --git a/js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js b/js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js index 03d264712343..a5ab9904e1c3 100644 --- a/js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js +++ b/js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js @@ -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); diff --git a/js/xpconnect/tests/unit/test_xray_named_element_access.js b/js/xpconnect/tests/unit/test_xray_named_element_access.js index ae3bbcfd327d..e67004dddb0a 100644 --- a/js/xpconnect/tests/unit/test_xray_named_element_access.js +++ b/js/xpconnect/tests/unit/test_xray_named_element_access.js @@ -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); diff --git a/toolkit/components/extensions/ExtensionParent.jsm b/toolkit/components/extensions/ExtensionParent.jsm index 5b3bc6cf4fa5..f7defc51d18e 100644 --- a/toolkit/components/extensions/ExtensionParent.jsm +++ b/toolkit/components/extensions/ExtensionParent.jsm @@ -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) { diff --git a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm index e47dff0a4ccd..3d447c8f3c0f 100644 --- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm +++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm @@ -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; diff --git a/toolkit/components/extensions/parent/ext-downloads.js b/toolkit/components/extensions/parent/ext-downloads.js index 5d800eac5799..f25c0b28b586 100644 --- a/toolkit/components/extensions/parent/ext-downloads.js +++ b/toolkit/components/extensions/parent/ext-downloads.js @@ -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"); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js index 2b43190d9039..a70bab749312 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js @@ -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); diff --git a/toolkit/modules/HiddenFrame.jsm b/toolkit/modules/HiddenFrame.jsm index b7ab1a6b732a..da7390b1b0a0 100644 --- a/toolkit/modules/HiddenFrame.jsm +++ b/toolkit/modules/HiddenFrame.jsm @@ -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); diff --git a/widget/headless/tests/test_headless.js b/widget/headless/tests/test_headless.js index b850c7471232..1c3263882ae7 100644 --- a/widget/headless/tests/test_headless.js +++ b/widget/headless/tests/test_headless.js @@ -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 = { @@ -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); @@ -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. @@ -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. @@ -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", () => { @@ -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'); @@ -175,5 +171,5 @@ add_task(async function test_mouse_drag() { ok(true, "Send mouse event didn't crash"); - webNavigation.close(); + windowlessBrowser.close(); }); diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index c4e0d29d50b6..fa2c598bae83 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -452,25 +452,10 @@ public: 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 window = do_QueryInterface(mBrowser); - return window->Destroy(); - } - protected: virtual ~WindowlessBrowser() { @@ -500,6 +485,33 @@ private: 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 window = do_QueryInterface(mBrowser); + return window->Destroy(); +} + +NS_IMETHODIMP +WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell) +{ + nsCOMPtr 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) diff --git a/xpfe/appshell/nsIWindowlessBrowser.idl b/xpfe/appshell/nsIWindowlessBrowser.idl index c959e47a4174..7204a9fc5c38 100644 --- a/xpfe/appshell/nsIWindowlessBrowser.idl +++ b/xpfe/appshell/nsIWindowlessBrowser.idl @@ -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. @@ -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; }; diff --git a/xpfe/appshell/test/test_windowlessBrowser.xul b/xpfe/appshell/test/test_windowlessBrowser.xul index 0b13631b1b05..b0132cfa4367 100644 --- a/xpfe/appshell/test/test_windowlessBrowser.xul +++ b/xpfe/appshell/test/test_windowlessBrowser.xul @@ -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");