Bug 1463016: Part 5 - Add domWindow property to DocShellTreeItem and update callers to use it. r?nika draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 20 May 2018 18:10:16 -0700
changeset 797629 2d6bbf5a4b3e24733ca9547aff852974aaff92d3
parent 797628 a48b502edb6d62e28579a41ae921ec72eef81a53
child 797630 826ba2f7c7df1f70f014090ed08b68a1db970355
push id110518
push usermaglione.k@gmail.com
push dateMon, 21 May 2018 02:57:23 +0000
reviewersnika
bugs1463016
milestone62.0a1
Bug 1463016: Part 5 - Add domWindow property to DocShellTreeItem and update callers to use it. r?nika MozReview-Commit-ID: FRRAdxLHRtG
accessible/tests/mochitest/common.js
browser/base/content/browser.js
browser/base/content/test/general/browser_bug676619.js
browser/base/content/test/general/browser_fullscreen-window-open.js
browser/components/feeds/WebContentConverter.js
browser/components/nsBrowserContentHandler.js
browser/components/search/content/searchReset.js
browser/components/search/test/browser_webapi.js
browser/components/sessionstore/ContentRestore.jsm
browser/components/sessionstore/SessionStorage.jsm
browser/components/sessionstore/content/aboutSessionRestore.js
browser/components/shell/HeadlessShell.jsm
browser/components/syncedtabs/util.js
browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
devtools/client/debugger/test/mochitest/head.js
devtools/client/framework/devtools-browser.js
devtools/client/responsive.html/utils/window.js
devtools/client/webide/modules/runtimes.js
devtools/server/actors/tab.js
devtools/server/actors/webbrowser.js
devtools/server/actors/webextension-inspected-window.js
devtools/server/actors/webextension.js
devtools/shared/security/prompt.js
docshell/base/nsDocShell.cpp
docshell/base/nsIDocShellTreeItem.idl
docshell/test/chrome/test_private_hidden_window.html
dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul
dom/security/test/general/browser_test_data_download.js
dom/security/test/general/browser_test_data_text_csv.js
dom/serviceworkers/test/test_privateBrowsing.html
dom/tests/mochitest/beacon/test_beaconCookies.html
dom/tests/mochitest/chrome/window_focus.xul
dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
dom/url/tests/browser_download_after_revoke.js
dom/workers/test/test_sharedWorker_privateBrowsing.html
editor/spellchecker/tests/test_bug1209414.html
image/test/mochitest/test_bug1132427.html
js/xpconnect/tests/unit/test_xray_named_element_access.js
layout/forms/test/test_bug536567_perwindowpb.html
layout/tools/reftest/bootstrap.js
mobile/android/chrome/content/aboutAccounts.js
mobile/android/chrome/content/aboutAddons.js
mobile/android/chrome/content/aboutLogins.js
mobile/android/chrome/content/aboutPrivateBrowsing.js
mobile/android/components/ContentPermissionPrompt.js
mobile/android/components/extensions/ext-tabs.js
mobile/android/modules/WebrtcUI.jsm
mobile/android/modules/geckoview/GeckoViewUtils.jsm
mobile/android/tests/browser/chrome/test_awsy_lite.html
mobile/android/tests/browser/robocop/roboextender/bootstrap.js
netwerk/test/browser/browser_NetUtil.js
security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
testing/mochitest/bootstrap.js
testing/specialpowers/content/specialpowersAPI.js
toolkit/components/browser/nsWebBrowser.cpp
toolkit/components/extensions/ExtensionContent.jsm
toolkit/components/extensions/ExtensionParent.jsm
toolkit/components/extensions/extension-process-script.js
toolkit/components/passwordmgr/test/browser/browser_passwordmgr_switchtab.js
toolkit/components/passwordmgr/test/chrome/test_privbrowsing_perwindowpb.html
toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html
toolkit/components/url-classifier/tests/mochitest/test_donottrack.html
toolkit/components/url-classifier/tests/mochitest/test_privatebrowsing_trackingprotection.html
toolkit/components/url-classifier/tests/mochitest/test_reporturl.html
toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1157081.html
toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1312515.html
toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_whitelist.html
toolkit/content/aboutTelemetry.js
toolkit/content/widgets/browser.xml
toolkit/content/widgets/editor.xml
toolkit/content/widgets/general.xml
toolkit/modules/BrowserUtils.jsm
toolkit/modules/Finder.jsm
toolkit/modules/HiddenFrame.jsm
toolkit/modules/addons/WebNavigationContent.js
toolkit/modules/addons/WebNavigationFrames.jsm
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/test/browser/head.js
toolkit/mozapps/extensions/test/xpinstall/head.js
widget/headless/tests/test_headless.js
widget/tests/test_bug593307.xul
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -836,22 +836,17 @@ function shortenString(aString, aMaxLeng
 
 // //////////////////////////////////////////////////////////////////////////////
 // General Utils
 // //////////////////////////////////////////////////////////////////////////////
 /**
  * Return main chrome window (crosses chrome boundary)
  */
 function getMainChromeWindow(aWindow) {
-  return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                .getInterface(Ci.nsIWebNavigation)
-                .QueryInterface(Ci.nsIDocShellTreeItem)
-                .rootTreeItem
-                .QueryInterface(Ci.nsIInterfaceRequestor)
-                .getInterface(Ci.nsIDOMWindow);
+  return aWindow.document.docShell.rootTreeItem.domWindow;
 }
 
 /** Sets the test plugin(s) initially expected enabled state.
  * It will automatically be reset to it's previous value after the test
  * ends.
  * @param aNewEnabledState [in] the enabled state, e.g. SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED
  * @param aPluginName [in, optional] The name of the plugin, defaults to "Test Plug-in"
  */
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7179,22 +7179,18 @@ var MailIntegration = {
 };
 
 function BrowserOpenAddonsMgr(aView) {
   return new Promise(resolve => {
     let emWindow;
     let browserWindow;
 
     var receivePong = function(aSubject, aTopic, aData) {
-      let browserWin = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIWebNavigation)
-                               .QueryInterface(Ci.nsIDocShellTreeItem)
-                               .rootTreeItem
-                               .QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindow);
+      let browserWin = aSubject.document.docShell
+                               .rootTreeItem.domWindow;
       if (!emWindow || browserWin == window /* favor the current window */) {
         emWindow = aSubject;
         browserWindow = browserWin;
       }
     };
     Services.obs.addObserver(receivePong, "EM-pong");
     Services.obs.notifyObservers(null, "EM-ping");
     Services.obs.removeObserver(receivePong, "EM-pong");
--- a/browser/base/content/test/general/browser_bug676619.js
+++ b/browser/base/content/test/general/browser_bug676619.js
@@ -7,18 +7,17 @@ function waitForNewWindow() {
 
         function downloadOnLoad() {
           domwindow.removeEventListener("load", downloadOnLoad, true);
 
           is(domwindow.document.location.href, "chrome://mozapps/content/downloads/unknownContentType.xul", "Download page appeared");
           resolve(domwindow);
         }
 
-        var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                  .getInterface(Ci.nsIDOMWindow);
+        var domwindow = aXULWindow.docShell.domWindow;
         domwindow.addEventListener("load", downloadOnLoad, true);
       },
       onCloseWindow: aXULWindow => {},
     };
 
     Services.wm.addListener(listener);
   });
 }
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -312,18 +312,17 @@ WindowListener.prototype = {
   test_title: null,
   test_url: null,
   callback_onSuccess: null,
   callBack_onFinalize: null,
 
   onOpenWindow(aXULWindow) {
     Services.wm.removeListener(this);
 
-    let domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+    let domwindow = aXULWindow.docShell.domWindow;
     let onLoad = aEvent => {
       is(domwindow.document.location.href, this.test_url,
         "Opened Window is expected: " + this.test_title);
       if (this.callback_onSuccess) {
         this.callback_onSuccess();
       }
 
       domwindow.removeEventListener("load", onLoad, true);
--- a/browser/components/feeds/WebContentConverter.js
+++ b/browser/components/feeds/WebContentConverter.js
@@ -488,22 +488,17 @@ WebContentConverterRegistrar.prototype =
       this._registerContentHandler(contentType, aURIString, aTitle);
     }
   },
 
   /**
    * Returns the browser chrome window in which the content window is in
    */
   _getBrowserWindowForContentWindow(aContentWindow) {
-    return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIWebNavigation)
-                         .QueryInterface(Ci.nsIDocShellTreeItem)
-                         .rootTreeItem
-                         .QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDOMWindow)
+    return aContentWindow.document.docShell.rootTreeItem.domWindow
                          .wrappedJSObject;
   },
 
   /**
    * Returns the <xul:browser> element associated with the given content
    * window.
    *
    * @param aBrowserWindow
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -675,22 +675,17 @@ function handURIToExistingBrowser(uri, l
   var allowPrivate = forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing;
   var navWin = BrowserWindowTracker.getTopWindow({private: allowPrivate});
   if (!navWin) {
     // if we couldn't load it in an existing window, open a new one
     openBrowserWindow(cmdLine, uri.spec, null, forcePrivate);
     return;
   }
 
-  var navNav = navWin.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIWebNavigation);
-  var rootItem = navNav.QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem;
-  var rootWin = rootItem.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDOMWindow);
-  var bwin = rootWin.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow;
+  var bwin = navWin.document.docShell.rootTreeItem.domWindow;
   bwin.openURI(uri, null, location,
                Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL, triggeringPrincipal);
 }
 
 function nsDefaultCommandLineHandler() {
 }
 
 nsDefaultCommandLineHandler.prototype = {
--- a/browser/components/search/content/searchReset.js
+++ b/browser/components/search/content/searchReset.js
@@ -41,22 +41,17 @@ function doSearch() {
     }
   }
 
   let engine = Services.search.currentEngine;
   let submission = engine.getSubmission(queryString, null, purpose);
 
   window.removeEventListener("unload", recordPageClosed);
 
-  let win = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                  .getInterface(Ci.nsIWebNavigation)
-                  .QueryInterface(Ci.nsIDocShellTreeItem)
-                  .rootTreeItem
-                  .QueryInterface(Ci.nsIInterfaceRequestor)
-                  .getInterface(Ci.nsIDOMWindow);
+  let win = window.document.docShell.rootTreeItem.domWindow;
   win.openTrustedLinkIn(submission.uri.spec, "current", {
     allowThirdPartyFixup: false,
     postData: submission.postData,
   });
 }
 
 function openingSettings() {
   record(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
--- a/browser/components/search/test/browser_webapi.js
+++ b/browser/components/search/test/browser_webapi.js
@@ -12,18 +12,17 @@ function AddSearchProvider(...args) {
 }
 
 function promiseDialogOpened() {
   return new Promise((resolve, reject) => {
     Services.wm.addListener({
       onOpenWindow(xulWin) {
         Services.wm.removeListener(this);
 
-        let win = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDOMWindow);
+        let win = xulWin.docShell.domWindow;
         waitForFocus(() => {
           if (win.location == "chrome://global/content/commonDialog.xul")
             resolve(win);
           else
             reject();
         }, win);
       }
     });
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -310,18 +310,17 @@ ContentRestoreInternal.prototype = {
    */
   restoreDocument() {
     if (!this._restoringDocument) {
       return;
     }
     let {formdata, scrollPositions} = this._restoringDocument;
     this._restoringDocument = null;
 
-    let window = this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindow);
+    let window = this.docShell.domWindow;
 
     // Restore form data.
     restoreFrameTreeData(window, formdata, (frame, data) => {
       // restore() will return false, and thus abort restoration for the
       // current |frame| and its descendants, if |data.url| is given but
       // doesn't match the loaded document's URL.
       return FormData.restore(frame, data);
     });
--- a/browser/components/sessionstore/SessionStorage.jsm
+++ b/browser/components/sessionstore/SessionStorage.jsm
@@ -146,17 +146,17 @@ var SessionStorageInternal = {
         let dataPrincipal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
         principal = Services.scriptSecurityManager.createCodebasePrincipal(dataPrincipal.URI, attrs);
       } catch (e) {
         console.error(e);
         continue;
       }
 
       let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
-      let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+      let window = aDocShell.domWindow;
 
       // There is no need to pass documentURI, it's only used to fill documentURI property of
       // domstorage event, which in this case has no consumer. Prevention of events in case
       // of missing documentURI will be solved in a followup bug to bug 600307.
       let storage = storageManager.createStorage(window, principal, "", aDocShell.usePrivateBrowsing);
 
       for (let key of Object.keys(data)) {
         try {
@@ -175,17 +175,17 @@ var SessionStorageInternal = {
    *        That history entry uri
    * @param aDocShell
    *        A tab's docshell (containing the sessionStorage)
    */
   _readEntry(aPrincipal, aDocShell) {
     let hostData = {};
     let storage;
 
-    let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    let window = aDocShell.domWindow;
 
     try {
       let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
       storage = storageManager.getStorage(window, aPrincipal);
       storage.length; // XXX: Bug 1232955 - storage.length can throw, catch that failure
     } catch (e) {
       // sessionStorage might throw if it's turned off, see bug 458954
       storage = null;
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -220,19 +220,17 @@ function onListKeyDown(aEvent) {
       restoreSingleTab(ix, aEvent.shiftKey);
     break;
   }
 }
 
 // Helper functions
 
 function getBrowserWindow() {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation)
-               .QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem
-               .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+  return window.document.docShell.rootTreeItem.domWindow;
 }
 
 function toggleRowChecked(aIx) {
   function isChecked(aItem) {
     return aItem.checked;
   }
 
   var item = gTreeData[aIx];
--- a/browser/components/shell/HeadlessShell.jsm
+++ b/browser/components/shell/HeadlessShell.jsm
@@ -26,18 +26,17 @@ function loadContentWindow(webNavigation
         // Ignore inner-frame events
         if (progress != webProgress) {
           return;
         }
         // Ignore events that don't change the document
         if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
           return;
         }
-        let contentWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                                    .getInterface(Ci.nsIDOMWindow);
+        let contentWindow = docShell.domWindow;
         progressListeners.delete(progressListener);
         webProgress.removeProgressListener(progressListener);
         contentWindow.addEventListener("load", (event) => {
           resolve(contentWindow);
         }, { once: true });
       },
       QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
                                               "nsISupportsWeakReference"])
--- a/browser/components/syncedtabs/util.js
+++ b/browser/components/syncedtabs/util.js
@@ -5,17 +5,11 @@
 "use strict";
 
 var EXPORTED_SYMBOLS = [
   "getChromeWindow"
 ];
 
 // Get the chrome (ie, browser) window hosting this content.
 function getChromeWindow(window) {
-  return window
-         .QueryInterface(Ci.nsIInterfaceRequestor)
-         .getInterface(Ci.nsIWebNavigation)
-         .QueryInterface(Ci.nsIDocShellTreeItem)
-         .rootTreeItem
-         .QueryInterface(Ci.nsIInterfaceRequestor)
-         .getInterface(Ci.nsIDOMWindow)
+  return window.document.docShell.rootTreeItem.domWindow
          .wrappedJSObject;
 }
--- a/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
+++ b/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
@@ -42,18 +42,17 @@ function changeMimeHandler(preferredActi
 }
 
 function addWindowListener(aURL, aCallback) {
   Services.wm.addListener({
     onOpenWindow(aXULWindow) {
       info("window opened, waiting for focus");
       Services.wm.removeListener(this);
 
-      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow);
+      var domwindow = aXULWindow.docShell.domWindow;
       waitForFocus(function() {
         is(domwindow.document.location.href, aURL, "should have seen the right window open");
         domwindow.close();
         aCallback();
       }, domwindow);
     },
     onCloseWindow(aXULWindow) { },
   });
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -70,20 +70,17 @@ var helpersjs = testDir + "/../../../com
 Services.scriptloader.loadSubScript(helpersjs, this);
 
 function addWindow(aUrl) {
   info("Adding window: " + aUrl);
   return promise.resolve(getChromeWindow(window.open(aUrl)));
 }
 
 function getChromeWindow(aWindow) {
-  return aWindow
-    .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation)
-    .QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem
-    .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+  return aWindow.document.docShell.rootTreeItem.domWindow;
 }
 
 // Override addTab/removeTab as defined by shared-head, since these have
 // an extra window parameter and add a frame script
 this.addTab = function addTab(aUrl, aWindow) {
   info("Adding tab: " + aUrl);
 
   let deferred = promise.defer();
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -505,23 +505,18 @@ var gDevToolsBrowser = exports.gDevTools
           default:
             throw Error("invalid thread client state in slow script debug handler: " +
                         threadClient.state);
         }
       });
     }
 
     debugService.activationHandler = function(window) {
-      let chromeWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIWebNavigation)
-                                .QueryInterface(Ci.nsIDocShellTreeItem)
-                                .rootTreeItem
-                                .QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow)
-                                .QueryInterface(Ci.nsIDOMChromeWindow);
+      let chromeWindow = window.document.docShell.rootTreeItem.domWindow
+                               .QueryInterface(Ci.nsIDOMChromeWindow);
 
       let setupFinished = false;
       slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab,
         () => {
           setupFinished = true;
         });
 
       // Don't return from the interrupt handler until the debugger is brought
--- a/devtools/client/responsive.html/utils/window.js
+++ b/devtools/client/responsive.html/utils/window.js
@@ -6,22 +6,17 @@
 
 const { Ci } = require("chrome");
 const Services = require("Services");
 
 /**
  * Returns the `nsIDOMWindow` toplevel window for any child/inner window
  */
 function getToplevelWindow(window) {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIWebNavigation)
-               .QueryInterface(Ci.nsIDocShellTreeItem)
-               .rootTreeItem
-               .QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindow);
+  return window.document.docShell.rootTreeItem.domWindow;
 }
 exports.getToplevelWindow = getToplevelWindow;
 
 function getDOMWindowUtils(window) {
   return window.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDOMWindowUtils);
 }
 exports.getDOMWindowUtils = getDOMWindowUtils;
--- a/devtools/client/webide/modules/runtimes.js
+++ b/devtools/client/webide/modules/runtimes.js
@@ -386,18 +386,17 @@ WiFiRuntime.prototype = {
     if (authResult != AuthenticationResult.PENDING) {
       throw new Error("Expected PENDING result, got " + authResult);
     }
 
     // Listen for the window our prompt opens, so we can close it programatically
     let promptWindow;
     let windowListener = {
       onOpenWindow(xulWindow) {
-        let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                           .getInterface(Ci.nsIDOMWindow);
+        let win = xulWindow.docShell.domWindow;
         win.addEventListener("load", function() {
           if (win.document.documentElement.getAttribute("id") != WINDOW_ID) {
             return;
           }
           // Found the window
           promptWindow = win;
           Services.wm.removeListener(windowListener);
         }, {once: true});
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -43,36 +43,34 @@ function getWindowID(window) {
 }
 
 function getDocShellChromeEventHandler(docShell) {
   let handler = docShell.chromeEventHandler;
   if (!handler) {
     try {
       // Toplevel xul window's docshell doesn't have chromeEventHandler
       // attribute. The chrome event handler is just the global window object.
-      handler = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDOMWindow);
+      handler = docShell.domWindow;
     } catch (e) {
       // ignore
     }
   }
   return handler;
 }
 
 function getChildDocShells(parentDocShell) {
   let docShellsEnum = parentDocShell.getDocShellEnumerator(
     Ci.nsIDocShellTreeItem.typeAll,
     Ci.nsIDocShell.ENUMERATE_FORWARDS
   );
 
   let docShells = [];
   while (docShellsEnum.hasMoreElements()) {
     let docShell = docShellsEnum.getNext();
-    docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-            .getInterface(Ci.nsIWebProgress);
+    docShell.QueryInterface(Ci.nsIDocShell);
     docShells.push(docShell);
   }
   return docShells;
 }
 
 exports.getChildDocShells = getChildDocShells;
 
 /**
@@ -321,19 +319,17 @@ TabActor.prototype = {
   },
 
   /**
    * Getter for the tab content's DOM window.
    */
   get window() {
     // On xpcshell, there is no document
     if (this.docShell) {
-      return this.docShell
-        .QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindow);
+      return this.docShell.domWindow;
     }
     return null;
   },
 
   get outerWindowID() {
     if (this.window) {
       return this.window.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIDOMWindowUtils)
@@ -359,18 +355,17 @@ TabActor.prototype = {
   },
 
   /**
    * Getter for the list of all content DOM windows in this tabActor
    * @return {Array}
    */
   get windows() {
     return this.docShells.map(docShell => {
-      return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindow);
+      return docShell.domWindow;
     });
   },
 
   /**
    * Getter for the original docShell the tabActor got attached to in the first
    * place.
    * Note that your actor should normally *not* rely on this top level docShell
    * if you want it to show information relative to the iframe that's currently
@@ -1515,18 +1510,17 @@ DebuggerProgressListener.prototype = {
     this._knownWindowIDs.clear();
     this._knownWindowIDs = null;
   },
 
   watch(docShell) {
     // Add the docshell to the watched set. We're actually adding the window,
     // because docShell objects are not wrappercached and would be rejected
     // by the WeakSet.
-    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIDOMWindow);
+    let docShellWindow = docShell.domWindow;
     this._watchedDocShells.add(docShellWindow);
 
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     webProgress.addProgressListener(this,
                                     Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
                                     Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
 
@@ -1538,18 +1532,17 @@ DebuggerProgressListener.prototype = {
     // Dispatch the _windowReady event on the tabActor for pre-existing windows
     for (let win of this._getWindowsInDocShell(docShell)) {
       this._tabActor._windowReady(win);
       this._knownWindowIDs.set(getWindowID(win), win);
     }
   },
 
   unwatch(docShell) {
-    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIDOMWindow);
+    let docShellWindow = docShell.domWindow;
     if (!this._watchedDocShells.has(docShellWindow)) {
       return;
     }
 
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     // During process shutdown, the docshell may already be cleaned up and throw
     try {
@@ -1566,18 +1559,17 @@ DebuggerProgressListener.prototype = {
 
     for (let win of this._getWindowsInDocShell(docShell)) {
       this._knownWindowIDs.delete(getWindowID(win));
     }
   },
 
   _getWindowsInDocShell(docShell) {
     return getChildDocShells(docShell).map(d => {
-      return d.QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIDOMWindow);
+      return d.domWindow;
     });
   },
 
   onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {
     if (!this._tabActor.attached) {
       return;
     }
 
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -654,18 +654,19 @@ DevToolsUtils.makeInfallible(function(wi
    * nsIWindowMediator enumeration from within listeners (bug 873589).
    */
 
   window.addEventListener("load", handleLoad);
 }, "BrowserTabList.prototype.onOpenWindow");
 
 BrowserTabList.prototype.onCloseWindow =
 DevToolsUtils.makeInfallible(function(window) {
-  window = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                   .getInterface(Ci.nsIDOMWindow);
+  if (window instanceof Ci.nsIXULWindow) {
+    window = window.docShell.domWindow;
+  }
 
   if (appShellDOMWindowType(window) !== DebuggerServer.chromeWindowType) {
     return;
   }
 
   /*
    * nsIWindowMediator deadlocks if you call its GetEnumerator method from
    * a nsIWindowMediatorListener's onCloseWindow hook (bug 873589), so
--- a/devtools/server/actors/webextension-inspected-window.js
+++ b/devtools/server/actors/webextension-inspected-window.js
@@ -179,19 +179,17 @@ CustomizedReload.prototype = {
                                 .QueryInterface(Ci.nsIDocShell);
 
     // Keep track of the set of window objects where we are going to inject
     // the injectedScript: the top level window and all its descendant
     // that are still of type content (filtering out loaded XUL pages, if any).
     if (window == this.window) {
       this.customizedReloadWindows.add(window);
     } else if (subjectDocShell.sameTypeParent) {
-      let parentWindow = subjectDocShell.sameTypeParent
-                                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                                        .getInterface(Ci.nsIDOMWindow);
+      let parentWindow = subjectDocShell.sameTypeParent.domWindow;
       if (parentWindow && this.customizedReloadWindows.has(parentWindow)) {
         this.customizedReloadWindows.add(window);
       }
     }
 
     if (this.customizedReloadWindows.has(window)) {
       const {
         apiErrorResult
--- a/devtools/server/actors/webextension.js
+++ b/devtools/server/actors/webextension.js
@@ -145,18 +145,17 @@ webExtensionChildPrototype._createFallba
   }
 
   // Create an empty hidden window as a fallback (e.g. the background page could be
   // not defined for the target add-on or not yet when the actor instance has been
   // created).
   this.fallbackWebNav = Services.appShell.createWindowlessBrowser(true);
 
   // Save the reference to the fallback DOMWindow.
-  this.fallbackWindow = this.fallbackWebNav.QueryInterface(Ci.nsIInterfaceRequestor)
-                                           .getInterface(Ci.nsIDOMWindow);
+  this.fallbackWindow = this.fallbackWebNav.document.window;
 
   // Insert the fallback doc message.
   this.fallbackWindow.document.body.innerText = FALLBACK_DOC_MESSAGE;
 };
 
 webExtensionChildPrototype._destroyFallbackWindow = function() {
   if (this.fallbackWebNav) {
     // Explicitly close the fallback windowless browser to prevent it to leak
@@ -250,20 +249,17 @@ webExtensionChildPrototype._docShellToWi
 
   let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIWebProgress);
   let window = webProgress.DOMWindow;
 
   // Collect the addonID from the document origin attributes and its sameType top level
   // frame.
   let addonID = window.document.nodePrincipal.addonId;
-  let sameTypeRootAddonID = docShell.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                                    .getInterface(Ci.nsIDOMWindow)
+  let sameTypeRootAddonID = docShell.sameTypeRootTreeItem.domWindow
                                     .document.nodePrincipal.addonId;
 
   return Object.assign(baseWindowDetails, {
     addonID,
     sameTypeRootAddonID,
   });
 };
 
@@ -281,20 +277,17 @@ webExtensionChildPrototype._docShellsToW
 };
 
 webExtensionChildPrototype.isExtensionWindow = function(window) {
   return window.document.nodePrincipal.addonId == this.id;
 };
 
 webExtensionChildPrototype.isExtensionWindowDescendent = function(window) {
   // Check if the source is coming from a descendant docShell of an extension window.
-  let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDocShell);
-  let rootWin = docShell.sameTypeRootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
-                                             .getInterface(Ci.nsIDOMWindow);
+  let rootWin = window.document.docShell.sameTypeRootTreeItem.domWindow;
   return this.isExtensionWindow(rootWin);
 };
 
 /**
  * Return true if the given source is associated with this addon and should be
  * added to the visible sources (retrieved and used by the webbrowser actor module).
  */
 webExtensionChildPrototype._allowSource = function(source) {
--- a/devtools/shared/security/prompt.js
+++ b/devtools/shared/security/prompt.js
@@ -55,18 +55,17 @@ Client.defaultSendOOB = ({ authResult, o
   let msg = `${header}\n\n${hashMsg}\n${tokenMsg}`;
   let prompt = Services.prompt;
   let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_CANCEL;
 
   // Listen for the window our prompt opens, so we can close it programatically
   let promptWindow;
   let windowListener = {
     onOpenWindow(xulWindow) {
-      let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDOMWindow);
+      let win = xulWindow.docShell.domWindow;
       win.addEventListener("load", function() {
         if (win.document.documentElement.getAttribute("id") != "commonDialog") {
           return;
         }
         // Found the window
         promptWindow = win;
         Services.wm.removeListener(windowListener);
       }, {once: true});
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4070,16 +4070,29 @@ nsDocShell::GetWindow()
 {
   if (NS_FAILED(EnsureScriptEnvironment())) {
     return nullptr;
   }
   return mScriptGlobal->AsOuter();
 }
 
 NS_IMETHODIMP
+nsDocShell::GetDomWindow(nsPIDOMWindowOuter** aWindow)
+{
+  NS_ENSURE_ARG_POINTER(aWindow);
+
+  nsresult rv = EnsureScriptEnvironment();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsPIDOMWindowOuter> window = mScriptGlobal->AsOuter();
+  window.forget(aWindow);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
 {
   if (mDeviceSizeIsPageSize != aValue) {
     mDeviceSizeIsPageSize = aValue;
     RefPtr<nsPresContext> presContext;
     GetPresContext(getter_AddRefs(presContext));
     if (presContext) {
       presContext->MediaFeatureValuesChanged({
--- a/docshell/base/nsIDocShellTreeItem.idl
+++ b/docshell/base/nsIDocShellTreeItem.idl
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDocShellTreeOwner;
 interface nsIDocument;
 interface nsPIDOMWindowOuter;
 
+webidl WindowProxy;
 
 /**
  * The nsIDocShellTreeItem supplies the methods that are required of any item
  * that wishes to be able to live within the docshell tree either as a middle
  * node or a leaf. 
  */
 
 [scriptable, uuid(9b7c586f-9214-480c-a2c4-49b526fff1a6)]
@@ -174,12 +175,17 @@ interface nsIDocShellTreeItem : nsISuppo
 	Note the search is depth first when recursing.
 	*/
 	nsIDocShellTreeItem findChildWithName(in AString aName,
 	                                      in boolean aRecurse,
 	                                      in boolean aSameType,
 	                                      in nsIDocShellTreeItem aRequestor,
 	                                      in nsIDocShellTreeItem aOriginalRequestor);
 
+  /**
+   * Returns the DOM outer window for the content viewer.
+   */
+  readonly attribute WindowProxy domWindow;
+
   [noscript,nostdcall,notxpcom] nsIDocument getDocument();
   [noscript,nostdcall,notxpcom] nsPIDOMWindowOuter getWindow();
 };
 
--- a/docshell/test/chrome/test_private_hidden_window.html
+++ b/docshell/test/chrome/test_private_hidden_window.html
@@ -13,22 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   <iframe name="target"></iframe>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIWebNavigation)
-                       .QueryInterface(Ci.nsIDocShellTreeItem)
-                       .rootTreeItem
-                       .QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
 // We need to wait for the hidden window to load, but can't access
 // an event target for a regular event listener.
 var hidden = mainWindow.Services.appShell.hiddenPrivateDOMWindow;
 
 function isNotLoaded() {
   return !["complete", "interactive"].includes(hidden.document.readyState);
 }
--- a/dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul
+++ b/dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul
@@ -46,22 +46,17 @@ function runTestsCallback() {
   } catch (e) {
     exceptionThrown = true;
   }
   is(exceptionThrown, false, "Exception thrown getting private mode state.");
   is(state1, false, "Browser returned incorrect private mode state.");
   is(state2, false, "Browser returned incorrect private mode state.");
 
   // open a window with private mode and get the references of the elements.
-  var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+  var mainWindow = window.document.docShell.rootTreeItem.domWindow;
   var contentPage = getRootDirectory(window.location.href) + "privatemode_perwindowpb.xul";
 
   function testOnWindow(aIsPrivate, aCallback) {
     var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
     whenDelayedStartupFinished(win, function () {
       win.addEventListener("DOMContentLoaded", function onInnerLoad() {
         if (win.content.location.href == "about:privatebrowsing") {
           win.gBrowser.loadURI(contentPage);
--- a/dom/security/test/general/browser_test_data_download.js
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -4,18 +4,17 @@ const kTestPath = getRootDirectory(gTest
                   .replace("chrome://mochitests/content", "http://example.com")
 const kTestURI = kTestPath + "file_data_download.html";
 
 function addWindowListener(aURL, aCallback) {
   Services.wm.addListener({
     onOpenWindow(aXULWindow) {
       info("window opened, waiting for focus");
       Services.wm.removeListener(this);
-      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow);
+      var domwindow = aXULWindow.docShell.domWindow;
       waitForFocus(function() {
         is(domwindow.document.location.href, aURL, "should have seen the right window open");
         aCallback(domwindow);
       }, domwindow);
     },
     onCloseWindow(aXULWindow) { },
   });
 }
--- a/dom/security/test/general/browser_test_data_text_csv.js
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -4,18 +4,17 @@ const kTestPath = getRootDirectory(gTest
                   .replace("chrome://mochitests/content", "http://example.com")
 const kTestURI = kTestPath + "file_data_text_csv.html";
 
 function addWindowListener(aURL, aCallback) {
   Services.wm.addListener({
     onOpenWindow(aXULWindow) {
       info("window opened, waiting for focus");
       Services.wm.removeListener(this);
-      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindow);
+      var domwindow = aXULWindow.docShell.domWindow;
       waitForFocus(function() {
         is(domwindow.document.location.href, aURL, "should have seen the right window open");
         aCallback(domwindow);
       }, domwindow);
     },
     onCloseWindow(aXULWindow) { },
   });
 }
--- a/dom/serviceworkers/test/test_privateBrowsing.html
+++ b/dom/serviceworkers/test/test_privateBrowsing.html
@@ -29,22 +29,17 @@ function testOnWindow(aIsPrivate, aCallb
 
     if (!aIsPrivate) {
       win.gBrowser.loadURI(contentPage);
     }
   }, {capture: true, once: true});
 }
 
 function setupWindow() {
-  mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIWebNavigation)
-                     .QueryInterface(Ci.nsIDocShellTreeItem)
-                     .rootTreeItem
-                     .QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindow);
+  mainWindow = window.document.docShell.rootTreeItem.domWindow;
   runTest();
 }
 
 var wN;
 var registration;
 var wP;
 
 function testPrivateWindow() {
--- a/dom/tests/mochitest/beacon/test_beaconCookies.html
+++ b/dom/tests/mochitest/beacon/test_beaconCookies.html
@@ -30,22 +30,17 @@ function whenDelayedStartupFinished(aWin
     if (aWindow == aSubject) {
       Services.obs.removeObserver(observer, aTopic);
       setTimeout(aCallback, 0);
     }
   }, "browser-delayed-startup-finished");
 }
 
 function testOnWindow(options, callback) {
-  var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIWebNavigation)
-                         .QueryInterface(Ci.nsIDocShellTreeItem)
-                         .rootTreeItem
-                         .QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDOMWindow);
+  var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
   var win = mainWindow.OpenBrowserWindow(options);
   windowsToClose.push(win);
   whenDelayedStartupFinished(win, function() {
     callback(win);
   });
 };
 
--- a/dom/tests/mochitest/chrome/window_focus.xul
+++ b/dom/tests/mochitest/chrome/window_focus.xul
@@ -269,21 +269,17 @@ function checkSelection(node, testid)
   is(selection.focusNode, range.startContainer, testid + " selection focusNode");
   is(selection.focusOffset, range.startOffset, testid + " selection focusOffset");
   is(selection.anchorNode, range.endContainer, testid + " selection anchorNode");
   is(selection.anchorOffset, range.endOffset, testid + " selection anchorOffset");
 }
 
 function getTopWindow(win)
 {
-  return win.QueryInterface(Ci.nsIInterfaceRequestor).
-             getInterface(Ci.nsIWebNavigation).
-             QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem.
-             QueryInterface(Ci.nsIInterfaceRequestor).
-             getInterface(Ci.nsIDOMWindow);
+  return win.document.docShell.rootTreeItem.domWindow;
 }
 
 function mouseWillTriggerFocus(element)
 {
   if (!element) {
     return false;
   }
 
--- a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
@@ -10,22 +10,17 @@
 var mainWindow;
 
 var prefBranch = Cc["@mozilla.org/preferences-service;1"]
                    .getService(Ci.nsIPrefBranch);
 prefBranch.setIntPref("browser.startup.page", 0);
 prefBranch.setCharPref("browser.startup.homepage_override.mstone", "ignore");
 
 function startTest() {
-  mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIWebNavigation)
-                      .QueryInterface(Ci.nsIDocShellTreeItem)
-                      .rootTreeItem
-                      .QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIDOMWindow);
+  mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
   doTest();
 }
 
 var contentPage = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html";
 
 function testOnWindow(aIsPrivate, aCallback) {
   var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
--- a/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
@@ -156,22 +156,17 @@ function whenDelayedStartupFinished(aCal
 
     aSubject.addEventListener("DOMContentLoaded", function() {
       SimpleTest.executeSoon(function() { aCallback(aSubject); });
     }, {capture: true, once: true});
   }, "browser-delayed-startup-finished");
 }
 
 function testOnWindow(aIsPrivate, callback) {
-  var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIWebNavigation)
-                         .QueryInterface(Ci.nsIDocShellTreeItem)
-                         .rootTreeItem
-                         .QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDOMWindow);
+  var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
   mainWindow.openWebLinkIn(CONTENT_PAGE, "window", {
                                   private: aIsPrivate });
   whenDelayedStartupFinished(callback);
 };
 </script>
 </head>
 <body onload="startTest();">
--- a/dom/url/tests/browser_download_after_revoke.js
+++ b/dom/url/tests/browser_download_after_revoke.js
@@ -15,18 +15,17 @@ function test () {
 
 	  is(domwindow.document.location.href, "chrome://mozapps/content/downloads/unknownContentType.xul", "Download page appeared");
 
 	  domwindow.close();
           gBrowser.removeTab(gBrowser.selectedTab);
 	  finish();
         }
 
-        var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                  .getInterface(Ci.nsIDOMWindow);
+        var domwindow = aXULWindow.docShell.domWindow;
         domwindow.addEventListener("load", downloadOnLoad, true);
       },
       onCloseWindow: function(aXULWindow) {},
     }
 
     Services.wm.addListener(listener);
 
     info("Creating BlobURL and clicking on a HTMLAnchorElement...");
--- a/dom/workers/test/test_sharedWorker_privateBrowsing.html
+++ b/dom/workers/test/test_sharedWorker_privateBrowsing.html
@@ -27,22 +27,17 @@ function testOnWindow(aIsPrivate, aCallb
 
     if (!aIsPrivate) {
       win.gBrowser.loadURI(contentPage);
     }
   }, {capture: true, once: true});
 }
 
 function setupWindow() {
-  mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIWebNavigation)
-                     .QueryInterface(Ci.nsIDocShellTreeItem)
-                     .rootTreeItem
-                     .QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindow);
+  mainWindow = window.document.docShell.rootTreeItem.domWindow;
   runTest();
 }
 
 var wN;
 var wP;
 
 function doTests() {
   testOnWindow(false, function(aWin) {
--- a/editor/spellchecker/tests/test_bug1209414.html
+++ b/editor/spellchecker/tests/test_bug1209414.html
@@ -38,23 +38,18 @@ var script;
 
 var onSpellCheck =
   SpecialPowers.Cu.import(
     "resource://testing-common/AsyncSpellCheckTestHelper.jsm").onSpellCheck;
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
   script = SpecialPowers.loadChromeScript(function() {
-    var chromeWin = browserElement.ownerDocument.defaultView
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow)
+    var chromeWin = browserElement.ownerDocument.docShell
+                    .rootTreeItem.domWindow
                     .QueryInterface(Ci.nsIDOMChromeWindow);
     var contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
     contextMenu.addEventListener("popupshown",
                                  () => sendAsyncMessage("popupshown"));
 
     var dir = Cc["@mozilla.org/file/directory_service;1"]
                 .getService(Ci.nsIProperties)
                 .get("CurWorkD", Ci.nsIFile);
--- a/image/test/mochitest/test_bug1132427.html
+++ b/image/test/mochitest/test_bug1132427.html
@@ -48,22 +48,17 @@ function checkPixel(canvas, context, x1,
 }
 
 var iterationsLeft = 10;
 
 function continueTest() {
   // we need to drawWindow the chrome window so we can get a dump of the retained widget layers
   // if we have to repaint to fulfill this drawWindow request then it will be impossible to
   // observe the bug
-  var chromewin = SpecialPowers.wrap(win).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
-                     .getInterface(SpecialPowers.Ci.nsIWebNavigation)
-                     .QueryInterface(SpecialPowers.Ci.nsIDocShellTreeItem)
-                     .rootTreeItem
-                     .QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
-                     .getInterface(SpecialPowers.Ci.nsIDOMWindow);
+  var chromewin = SpecialPowers.wrap(win).document.docShell.rootTreeItem.domWindow;
 
   var el = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
   el.width = chromewin.innerWidth;
   el.height = chromewin.innerHeight;
   var ctx = el.getContext("2d");
   // pass the correct flags so we don't have to flush the retained layers
   SpecialPowers.wrap(ctx).drawWindow(chromewin, 0, 0, chromewin.innerWidth, chromewin.innerHeight, "rgba(0,0,0,0)",
     ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_DRAW_CARET);
--- a/js/xpconnect/tests/unit/test_xray_named_element_access.js
+++ b/js/xpconnect/tests/unit/test_xray_named_element_access.js
@@ -7,17 +7,17 @@ ChromeUtils.import("resource://gre/modul
 add_task(async function() {
   let webnav = Services.appShell.createWindowlessBrowser(false);
 
   let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell);
 
   docShell.createAboutBlankContentViewer(null);
 
-  let window = webnav.getInterface(Ci.nsIDOMWindow);
+  let window = webnav.document.window;
   let unwrapped = Cu.waiveXrays(window);
 
   window.document.body.innerHTML = '<div id="foo"></div>';
 
   equal(window.foo, undefined, "Should not have named X-ray property access");
   equal(typeof unwrapped.foo, "object", "Should always have non-X-ray named property access");
 
   webnav.close();
--- a/layout/forms/test/test_bug536567_perwindowpb.html
+++ b/layout/forms/test/test_bug536567_perwindowpb.html
@@ -124,21 +124,17 @@ function endTest() {
   }
 
   normalWindow.close();
   privateWindow.close();
   MockFilePicker.cleanup();
   SimpleTest.finish();
 }
 
-var mainWindow =
-  window.QueryInterface(Ci.nsIInterfaceRequestor).
-    getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
-    rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
-    getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage = "http://mochi.test:8888/chrome/layout/forms/test/bug536567_iframe.html";
 
 function whenDelayedStartupFinished(aWindow, aCallback) {
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     if (aWindow == aSubject) {
       Services.obs.removeObserver(observer, aTopic);
       setTimeout(aCallback, 0);
     }
--- a/layout/tools/reftest/bootstrap.js
+++ b/layout/tools/reftest/bootstrap.js
@@ -3,20 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cm = Components.manager;
 
 ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var WindowListener = {
-  onOpenWindow: function(win) {
+  onOpenWindow: function(xulWin) {
     Services.wm.removeListener(WindowListener);
 
-    win = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    let win = xulWin.docShell.domWindow;
     win.addEventListener("load", function listener() {
       // Load into any existing windows.
       let windows = Services.wm.getEnumerator("navigator:browser");
       while (windows.hasMoreElements()) {
         win = windows.getNext();
         break;
       }
 
--- a/mobile/android/chrome/content/aboutAccounts.js
+++ b/mobile/android/chrome/content/aboutAccounts.js
@@ -299,23 +299,17 @@ document.addEventListener("DOMContentLoa
   var buttonOpenPrefs = document.getElementById("buttonOpenPrefs");
   buttonOpenPrefs.addEventListener("click", openPrefs);
 }, {capture: true, once: true});
 
 // This window is contained in a XUL <browser> element.  Return the
 // messageManager of that <browser> element, or null.
 function getBrowserMessageManager() {
   let browser = window
-        .QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIWebNavigation)
-        .QueryInterface(Ci.nsIDocShellTreeItem)
-        .rootTreeItem
-        .QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindow)
-        .QueryInterface(Ci.nsIDOMChromeWindow)
+        .document.docShell.rootTreeItem.domWindow;
         .BrowserApp
         .getBrowserForDocument(document);
   if (browser) {
     return browser.messageManager;
   }
   return null;
 }
 
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -11,22 +11,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const AMO_ICON = "chrome://browser/skin/images/amo-logo.png";
 const UPDATE_INDICATOR = "chrome://browser/skin/images/extension-update.svg";
 
 var gStringBundle = Services.strings.createBundle("chrome://browser/locale/aboutAddons.properties");
 
 XPCOMUtils.defineLazyGetter(window, "gChromeWin", function() {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor)
-           .getInterface(Ci.nsIWebNavigation)
-           .QueryInterface(Ci.nsIDocShellTreeItem)
-           .rootTreeItem
-           .QueryInterface(Ci.nsIInterfaceRequestor)
-           .getInterface(Ci.nsIDOMWindow)
+  return window.document.docShell.rootTreeItem.domWindow
            .QueryInterface(Ci.nsIDOMChromeWindow);
 });
 ChromeUtils.defineModuleGetter(window, "Preferences",
                                "resource://gre/modules/Preferences.jsm");
 
 var ContextMenus = {
   target: null,
 
--- a/mobile/android/chrome/content/aboutLogins.js
+++ b/mobile/android/chrome/content/aboutLogins.js
@@ -3,22 +3,17 @@
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://services-common/utils.js"); /* global: CommonUtils */
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/TelemetryStopwatch.jsm");
 
 XPCOMUtils.defineLazyGetter(window, "gChromeWin", () =>
-  window.QueryInterface(Ci.nsIInterfaceRequestor)
-    .getInterface(Ci.nsIWebNavigation)
-    .QueryInterface(Ci.nsIDocShellTreeItem)
-    .rootTreeItem
-    .QueryInterface(Ci.nsIInterfaceRequestor)
-    .getInterface(Ci.nsIDOMWindow)
+  window.document.docShell.rootTreeItem.domWindow
     .QueryInterface(Ci.nsIDOMChromeWindow));
 
 ChromeUtils.defineModuleGetter(this, "EventDispatcher",
                                "resource://gre/modules/Messaging.jsm");
 ChromeUtils.defineModuleGetter(this, "Snackbars", "resource://gre/modules/Snackbars.jsm");
 ChromeUtils.defineModuleGetter(this, "Prompt",
                                "resource://gre/modules/Prompt.jsm");
 
--- a/mobile/android/chrome/content/aboutPrivateBrowsing.js
+++ b/mobile/android/chrome/content/aboutPrivateBrowsing.js
@@ -4,22 +4,17 @@
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(window, "gChromeWin", () =>
-  window.QueryInterface(Ci.nsIInterfaceRequestor)
-    .getInterface(Ci.nsIWebNavigation)
-    .QueryInterface(Ci.nsIDocShellTreeItem)
-    .rootTreeItem
-    .QueryInterface(Ci.nsIInterfaceRequestor)
-    .getInterface(Ci.nsIDOMWindow)
+  window.document.docShell.rootTreeItem.domWindow
     .QueryInterface(Ci.nsIDOMChromeWindow));
 
 document.addEventListener("DOMContentLoaded", function() {
     let BrowserApp = window.gChromeWin.BrowserApp;
 
     if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
       document.body.setAttribute("class", "normal");
       document.getElementById("newPrivateTabLink").addEventListener("click", function() {
--- a/mobile/android/components/ContentPermissionPrompt.js
+++ b/mobile/android/components/ContentPermissionPrompt.js
@@ -46,22 +46,17 @@ ContentPermissionPrompt.prototype = {
       callback(/* allow */ false);
       return true;
     }
 
     return false;
   },
 
   getChromeWindow: function getChromeWindow(aWindow) {
-     let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIWebNavigation)
-                            .QueryInterface(Ci.nsIDocShellTreeItem)
-                            .rootTreeItem
-                            .QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIDOMWindow)
+     let chromeWin = aWindow.document.docShell.rootTreeItem.domWindow
                             .QueryInterface(Ci.nsIDOMChromeWindow);
      return chromeWin;
   },
 
   getChromeForRequest: function getChromeForRequest(request) {
     if (request.window) {
       let requestingWindow = request.window.top;
       return this.getChromeWindow(requestingWindow).wrappedJSObject;
--- a/mobile/android/components/extensions/ext-tabs.js
+++ b/mobile/android/components/extensions/ext-tabs.js
@@ -1,19 +1,17 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 ChromeUtils.defineModuleGetter(this, "PromiseUtils",
                                "resource://gre/modules/PromiseUtils.jsm");
 
 const getBrowserWindow = window => {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDocShell)
-               .QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem
-               .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+  return window.document.docShell.rootTreeItem.domWindow;
 };
 
 let tabListener = {
   tabReadyInitialized: false,
   tabReadyPromises: new WeakMap(),
   initializingTabs: new WeakSet(),
 
   initTabReady() {
--- a/mobile/android/modules/WebrtcUI.jsm
+++ b/mobile/android/modules/WebrtcUI.jsm
@@ -278,22 +278,17 @@ var WebrtcUI = {
     } else {
       message = Strings.browser.GetStringFromName("getUserMedia.blockedCameraAndMicrophoneAccess");
     }
 
     DoorHanger.show(aWindow, message, "webrtc-blocked");
   },
 
   getChromeWindow: function getChromeWindow(aWindow) {
-     let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIWebNavigation)
-                            .QueryInterface(Ci.nsIDocShellTreeItem)
-                            .rootTreeItem
-                            .QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIDOMWindow)
+     let chromeWin = aWindow.document.docShell.rootTreeItem.domWindow
                             .QueryInterface(Ci.nsIDOMChromeWindow);
      return chromeWin;
   },
 
   prompt: function prompt(aContentWindow, aCallID, aAudioRequested,
                           aVideoRequested, aDevices) {
     let audioDevices = [];
     let videoDevices = [];
--- a/mobile/android/modules/geckoview/GeckoViewUtils.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewUtils.jsm
@@ -254,17 +254,17 @@ var GeckoViewUtils = {
   /**
    * Return the outermost chrome DOM window (the XUL window) for a given DOM
    * window, in the parent process.
    *
    * @param aWin a DOM window.
    */
   getChromeWindow: function(aWin) {
     const docShell = this.getRootDocShell(aWin);
-    return docShell && docShell.getInterface(Ci.nsIDOMWindow);
+    return docShell && docShell.domWindow;
   },
 
   /**
    * Return the content frame message manager (aka the frame script global
    * object) for a given DOM window, in a child process.
    *
    * @param aWin a DOM window.
    */
--- a/mobile/android/tests/browser/chrome/test_awsy_lite.html
+++ b/mobile/android/tests/browser/chrome/test_awsy_lite.html
@@ -41,18 +41,18 @@
 
   function checkpoint(aName) {
     var mrm = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
     gResults.push( { name: aName, resident: mrm.resident } );
     info(`${aName} | Resident Memory: ${mrm.resident}`);
   }
 
   var browserListener = {
-    onOpenWindow: function(aWindow) {
-        var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    onOpenWindow: function(aXulWin) {
+        var win = aXulWin.docShell.domWindow;
         win.addEventListener("UIReady", function(aEvent) {
             attachTo(win);
         }, {once: true});
     },
 
     onCloseWindow: function(aWindow) {
         detachFrom(aWindow);
     },
--- a/mobile/android/tests/browser/robocop/roboextender/bootstrap.js
+++ b/mobile/android/tests/browser/robocop/roboextender/bootstrap.js
@@ -4,19 +4,19 @@ ChromeUtils.import("resource://gre/modul
 
 function loadIntoWindow(window) {}
 function unloadFromWindow(window) {}
 
 /*
  bootstrap.js API
 */
 var windowListener = {
-  onOpenWindow: function(aWindow) {
+  onOpenWindow: function(aXulWin) {
     // Wait for the window to finish loading
-    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    let domWindow = XulWin.docShell.domWindow;
     domWindow.addEventListener("load", function() {
       if (domWindow) {
         domWindow.addEventListener("scroll", function(e) {
           let message = {
             type: "Robocop:Scroll",
             y: XPCNativeWrapper.unwrap(e.target).documentElement.scrollTop,
             height: XPCNativeWrapper.unwrap(e.target).documentElement.scrollHeight,
             cheight: XPCNativeWrapper.unwrap(e.target).documentElement.clientHeight,
--- a/netwerk/test/browser/browser_NetUtil.js
+++ b/netwerk/test/browser/browser_NetUtil.js
@@ -67,18 +67,17 @@ function test_asyncFetchBadCert() {
 }
 
 function WindowListener(aURL, aCallback) {
   this.callback = aCallback;
   this.url = aURL;
 }
 WindowListener.prototype = {
   onOpenWindow: function(aXULWindow) {
-    var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindow);
+    var domwindow = aXULWindow.docShell.domWindow;
     var self = this;
     domwindow.addEventListener("load", function() {
       if (domwindow.document.location.href != self.url)
         return;
 
       // Allow other window load listeners to execute before passing to callback
       executeSoon(function() {
         self.callback(domwindow);
--- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
@@ -24,21 +24,17 @@
   ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
   ChromeUtils.import("resource://testing-common/ContentTask.jsm");
   ChromeUtils.import("resource://gre/modules/Services.jsm");
 
   // This is how many sub-tests (testframes) in each round.
   // When the round begins, this will be initialized.
   var testsleftinround = 0;
   var currentround = "";
-  var mainWindow =
-    window.QueryInterface(Ci.nsIInterfaceRequestor).
-    getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
-    rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
-    getInterface(Ci.nsIDOMWindow);
+  var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
   SpecialPowers.Services.prefs.setIntPref("browser.startup.page", 0);
 
   var testframes = {
     samedom: {
       url: `http://example.com/${STSPATH}/verify.sjs`,
       expected: {plain: "SECURE", subdom: "SECURE", nosts: "INSECURE"}
     },
--- a/testing/mochitest/bootstrap.js
+++ b/testing/mochitest/bootstrap.js
@@ -59,18 +59,18 @@ var WindowListener = {
 
   tearDownWindow(win) {
     if (win.nativeConsole) {
       win.console = win.nativeConsole;
       win.nativeConsole = undefined;
     }
   },
 
-  onOpenWindow(win) {
-    win = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+  onOpenWindow(xulWin) {
+    let win = xulWin.docShell.domWindow;
 
     win.addEventListener("load", function() {
       if (win.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
         WindowListener.setupWindow(win);
       }
     }, {once: true});
   }
 };
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1408,22 +1408,17 @@ SpecialPowersAPI.prototype = {
                  .QueryInterface(Ci.nsIDocShell);
   },
   _getMUDV(window) {
     return this._getDocShell(window).contentViewer;
   },
   // XXX: these APIs really ought to be removed, they're not e10s-safe.
   // (also they're pretty Firefox-specific)
   _getTopChromeWindow(window) {
-    return window.QueryInterface(Ci.nsIInterfaceRequestor)
-                 .getInterface(Ci.nsIWebNavigation)
-                 .QueryInterface(Ci.nsIDocShellTreeItem)
-                 .rootTreeItem
-                 .QueryInterface(Ci.nsIInterfaceRequestor)
-                 .getInterface(Ci.nsIDOMWindow)
+    return window.document.docShell.rootTreeItem.domWindow
                  .QueryInterface(Ci.nsIDOMChromeWindow);
   },
   _getAutoCompletePopup(window) {
     return this._getTopChromeWindow(window).document
                                            .getElementById("PopupAutoComplete");
   },
   addAutoCompletePopupEventListener(window, eventname, listener) {
     this._getAutoCompletePopup(window).addEventListener(eventname,
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -548,16 +548,24 @@ nsWebBrowser::GetDocument()
 
 nsPIDOMWindowOuter*
 nsWebBrowser::GetWindow()
 {
   return mDocShell ? mDocShell->GetWindow() : nullptr;
 }
 
 NS_IMETHODIMP
+nsWebBrowser::GetDomWindow(nsPIDOMWindowOuter** aWindow)
+{
+  if (!mDocShell)
+    return NS_ERROR_NOT_INITIALIZED;
+  return mDocShell->GetDomWindow(aWindow);
+}
+
+NS_IMETHODIMP
 nsWebBrowser::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
 {
   NS_ENSURE_ARG_POINTER(aTreeOwner);
   *aTreeOwner = nullptr;
   if (mDocShellTreeOwner) {
     if (mDocShellTreeOwner->mTreeOwner) {
       *aTreeOwner = mDocShellTreeOwner->mTreeOwner;
     } else {
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -910,18 +910,18 @@ var ExtensionContent = {
   },
 
   // Helpers
 
   * enumerateWindows(docShell) {
     let enum_ = docShell.getDocShellEnumerator(docShell.typeContent,
                                                docShell.ENUMERATE_FORWARDS);
 
-    for (let docShell of XPCOMUtils.IterSimpleEnumerator(enum_, Ci.nsIInterfaceRequestor)) {
+    for (let docShell of XPCOMUtils.IterSimpleEnumerator(enum_, Ci.nsIDocShell)) {
       try {
-        yield docShell.getInterface(Ci.nsIDOMWindow);
+        yield docShell.domWindow;
       } catch (e) {
         // This can fail if the docShell is being destroyed, so just
         // ignore the error.
       }
     }
   },
 };
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -648,18 +648,17 @@ class ExtensionPageContextParent extends
     this.extension.views.add(this);
 
     extension.emit("extension-proxy-context-load", this);
   }
 
   // The window that contains this context. This may change due to moving tabs.
   get xulWindow() {
     let win = this.xulBrowser.ownerGlobal;
-    return win.document.docShell.rootTreeItem
-              .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    return win.document.docShell.rootTreeItem.domWindow;
   }
 
   get currentWindow() {
     if (this.viewType !== "background") {
       return this.xulWindow;
     }
   }
 
--- a/toolkit/components/extensions/extension-process-script.js
+++ b/toolkit/components/extensions/extension-process-script.js
@@ -262,18 +262,18 @@ DocumentManager = {
 
   // Helpers
 
   * enumerateWindows(docShell) {
     if (docShell) {
       let enum_ = docShell.getDocShellEnumerator(docShell.typeContent,
                                                  docShell.ENUMERATE_FORWARDS);
 
-      for (let docShell of XPCOMUtils.IterSimpleEnumerator(enum_, Ci.nsIInterfaceRequestor)) {
-        yield docShell.getInterface(Ci.nsIDOMWindow);
+      for (let docShell of XPCOMUtils.IterSimpleEnumerator(enum_, Ci.nsIDocShell)) {
+        yield docShell.domWindow;
       }
     } else {
       for (let global of this.globals.keys()) {
         yield* this.enumerateWindows(global.docShell);
       }
     }
   },
 };
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_switchtab.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_switchtab.js
@@ -6,19 +6,18 @@ const PROMPT_URL = "chrome://global/cont
 
 add_task(async function test() {
   await new Promise(resolve => {
 
   let tab = BrowserTestUtils.addTab(gBrowser);
   isnot(tab, gBrowser.selectedTab, "New tab shouldn't be selected");
 
   let listener = {
-    onOpenWindow(window) {
-      var domwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIDOMWindow);
+    onOpenWindow(xulWin) {
+      var domwindow = xulWin.docShell.domWindow;
       waitForFocus(() => {
         is(domwindow.document.location.href, PROMPT_URL, "Should have seen a prompt window");
         is(domwindow.args.promptType, "promptUserAndPass", "Should be an authenticate prompt");
 
         is(gBrowser.selectedTab, tab, "Should have selected the new tab");
 
         domwindow.document.documentElement.cancelDialog();
       }, domwindow);
--- a/toolkit/components/passwordmgr/test/chrome/test_privbrowsing_perwindowpb.html
+++ b/toolkit/components/passwordmgr/test/chrome/test_privbrowsing_perwindowpb.html
@@ -189,22 +189,17 @@ function checkTest() {
       break;
 
     default:
       ok(false, "Unexpected call to checkTest for test #" + testNum);
 
   }
 }
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage = "http://mochi.test:8888/chrome/toolkit/components/passwordmgr/test/chrome/privbrowsing_perwindowpb_iframe.html";
 var testWindows = [];
 
 function whenDelayedStartupFinished(aWindow, aCallback) {
   Services.obs.addObserver(function obs(aSubject, aTopic) {
     if (aWindow == aSubject) {
       Services.obs.removeObserver(obs, aTopic);
       setTimeout(aCallback, 0);
--- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
+++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
@@ -181,18 +181,17 @@ const backgroundPageThumbsContent = {
       capture.canvasDrawTime = new Date() - canvasDrawDate;
 
       finalCanvas.toBlob(blob => {
         capture.imageBlob = new Blob([blob]);
         // Load about:blank to finish the capture and wait for onStateChange.
         this._loadAboutBlank();
       });
     };
-    let win = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIDOMWindow);
+    let win = docShell.domWindow;
     win.requestIdleCallback(() => doCapture().catch(ex => this._failCurrentCapture(ex.message)));
   },
 
   _finishCurrentCapture() {
     let capture = this._currentCapture;
     let fileReader = new FileReader();
     fileReader.onloadend = () => {
       sendAsyncMessage("BackgroundPageThumbs:didCapture", {
--- a/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html
@@ -16,22 +16,17 @@
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
 /* import-globals-from classifierHelper.js */
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
 var testDatas = [
   { url: "itisaphishingsite.org/phishing.html",
     list: "mochi1-phish-simple",
     provider: "google",
   },
 
   { url: "fakeitisaphishingsite.org/phishing.html",
--- a/toolkit/components/url-classifier/tests/mochitest/test_donottrack.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_donottrack.html
@@ -9,22 +9,17 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
 const tests = [
   // DNT turned on and TP turned off, DNT signal sent in both private browsing
   // and normal mode.
   {
     setting:  {dntPref: true, tpPref: false, tppbPref: false, pbMode: true},
     expected: {dnt: "1"},
   },
--- a/toolkit/components/url-classifier/tests/mochitest/test_privatebrowsing_trackingprotection.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_privatebrowsing_trackingprotection.html
@@ -11,22 +11,17 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage = "http://www.itisatrap.org/tests/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 
 function testOnWindow(aPrivate, aCallback) {
   var win = mainWindow.OpenBrowserWindow({private: aPrivate});
--- a/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html
@@ -18,22 +18,17 @@
 <script class="testbody" type="text/javascript">
 /* import-globals-from classifierHelper.js */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
 ChromeUtils.import("resource://testing-common/ContentTask.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 const SJS = "mochi.test:8888/chrome/toolkit/components/url-classifier/tests/mochitest/report.sjs";
 const BASE_URL = "http://" + SJS + "?";
 
 var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
 
 function addUrlToDB(list, url) {
   let testData = [{ db: list, url}];
 
--- a/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
@@ -17,22 +17,17 @@
 
 <script src="head.js"></script>
 <script class="testbody" type="text/javascript">
 /* import-globals-from classifierHelper.js */
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
 var listmanager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                     getService(Ci.nsIUrlListManager);
 const SJS = "mochi.test:8888/chrome/toolkit/components/url-classifier/tests/mochitest/threathit.sjs";
 
 function hash(str) {
   function bytesFromString(str1) {
     let converter =
--- a/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1157081.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1157081.html
@@ -11,22 +11,17 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage = "chrome://mochitests/content/chrome/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 
 function testOnWindow(aCallback) {
   var win = mainWindow.OpenBrowserWindow();
--- a/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1312515.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_bug1312515.html
@@ -11,22 +11,17 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIWebNavigation)
-                       .QueryInterface(Ci.nsIDocShellTreeItem)
-                       .rootTreeItem
-                       .QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage = "http://www.itisatrap.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.html";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 
 function testOnWindow(aPrivate, aCallback) {
   var win = mainWindow.OpenBrowserWindow({private: aPrivate});
--- a/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_whitelist.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_trackingprotection_whitelist.html
@@ -11,22 +11,17 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 var contentPage1 = "http://www.itisatrap.org/tests/toolkit/components/url-classifier/tests/mochitest/whitelistFrame.html";
 var contentPage2 = "http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/whitelistFrame.html";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 
 function testOnWindow(contentPage, aCallback) {
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -123,22 +123,17 @@ function sectionalizeObject(obj) {
   }
   return map;
 }
 
 /**
  * Obtain the main DOMWindow for the current context.
  */
 function getMainWindow() {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIWebNavigation)
-               .QueryInterface(Ci.nsIDocShellTreeItem)
-               .rootTreeItem
-               .QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindow);
+  return window.document.docShell.rootTreeItem.domWindow;
 }
 
 /**
  * Obtain the DOMWindow that can open a preferences pane.
  *
  * This is essentially "get the browser chrome window" with the added check
  * that the supposed browser chrome window is capable of opening a preferences
  * pane.
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -424,17 +424,17 @@
       <property name="webProgress"
                 readonly="true"
                 onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);"/>
 
       <field name="_contentWindow">null</field>
 
       <property name="contentWindow"
                 readonly="true"
-                onget="return this._contentWindow || (this._contentWindow = this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow));"/>
+                onget="return this._contentWindow || (this._contentWindow = this.docShell.domWindow);"/>
 
       <property name="contentWindowAsCPOW"
                 readonly="true"
                 onget="return this.contentWindow;"/>
 
       <property name="sessionHistory"
                 onget="return this.webNavigation.sessionHistory;"
                 readonly="true"/>
--- a/toolkit/content/widgets/editor.xml
+++ b/toolkit/content/widgets/editor.xml
@@ -128,17 +128,17 @@
           return frameLoader ? frameLoader.docShell : null;
         ]]></getter>
       </property>
       <property name="currentURI"
                 readonly="true"
                 onget="return this.webNavigation.currentURI;"/>
       <property name="contentWindow"
                 readonly="true"
-                onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);"/>
+                onget="return this.docShell.domWindow;"/>
       <property name="contentWindowAsCPOW"
                 readonly="true"
                 onget="return this.contentWindow;"/>
       <property name="webBrowserFind"
                 readonly="true"
                 onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebBrowserFind);"/>
       <property name="markupDocumentViewer"
                 readonly="true"
--- a/toolkit/content/widgets/general.xml
+++ b/toolkit/content/widgets/general.xml
@@ -66,17 +66,17 @@
       <property name="docShell" readonly="true">
         <getter><![CDATA[
           let {frameLoader} = this;
           return frameLoader ? frameLoader.docShell : null;
         ]]></getter>
       </property>
       <property name="contentWindow"
                 readonly="true"
-                onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);"/>
+                onget="return this.docShell.domWindow;"/>
       <property name="webNavigation"
                 onget="return this.docShell.QueryInterface(Components.interfaces.nsIWebNavigation);"
                 readonly="true"/>
       <property name="contentDocument" readonly="true"
                 onget="return this.webNavigation.document;"/>
     </implementation>
   </binding>
 
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -422,19 +422,17 @@ var BrowserUtils = {
   /**
    * Retrieve the root window object (i.e. the top-most content global) for a
    * specific docShell object.
    *
    * @param  {nsIDocShell} docShell
    * @return {nsIDOMWindow}
    */
   getRootWindow(docShell) {
-    return docShell.QueryInterface(Ci.nsIDocShellTreeItem)
-      .sameTypeRootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIDOMWindow);
+    return docShell.sameTypeRootTreeItem.domWindow;
   },
 
   /**
    * Trim the selection text to a reasonable size and sanitize it to make it
    * safe for search query input.
    *
    * @param aSelection
    *        The selection text to trim.
--- a/toolkit/modules/Finder.jsm
+++ b/toolkit/modules/Finder.jsm
@@ -466,17 +466,17 @@ Finder.prototype = {
       current: 0,
       _currentFound: false
     };
   },
 
   _getWindow() {
     if (!this._docShell)
       return null;
-    return this._docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    return this._docShell.domWindow;
   },
 
   /**
    * Get the bounding selection rect in CSS px relative to the origin of the
    * top-level content document.
    */
   _getResultRect() {
     let topWin = this._getWindow();
--- a/toolkit/modules/HiddenFrame.jsm
+++ b/toolkit/modules/HiddenFrame.jsm
@@ -55,18 +55,17 @@ HiddenFrame.prototype = {
     return this._deferred.promise;
   },
 
   /**
    * Fetch a sync ref to the window inside the frame (needed for the add-on SDK).
    */
   getWindow() {
     this.get();
-    this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
-    return this._browser.getInterface(Ci.nsIDOMWindow);
+    return this._browser.document.ownerGlobal;
   },
 
 
   destroy() {
     if (this._browser) {
       if (this._listener) {
         this._webProgress.removeProgressListener(this._listener);
         this._listener = null;
--- a/toolkit/modules/addons/WebNavigationContent.js
+++ b/toolkit/modules/addons/WebNavigationContent.js
@@ -8,18 +8,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
                                "resource://gre/modules/WebNavigationFrames.jsm");
 
 function getDocShellOuterWindowId(docShell) {
   if (!docShell) {
     return undefined;
   }
 
-  return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                 .getInterface(Ci.nsIDOMWindow)
+  return docShell.domWindow
                  .getInterface(Ci.nsIDOMWindowUtils)
                  .outerWindowID;
 }
 
 function loadListener(event) {
   let document = event.target;
   let window = document.defaultView;
   let url = document.documentURI;
@@ -115,18 +114,17 @@ var FormSubmitListener = {
 var WebProgressListener = {
   init: function() {
     // This WeakMap (DOMWindow -> nsIURI) keeps track of the pathname and hash
     // of the previous location for all the existent docShells.
     this.previousURIMap = new WeakMap();
 
     // Populate the above previousURIMap by iterating over the docShells tree.
     for (let currentDocShell of WebNavigationFrames.iterateDocShellTree(docShell)) {
-      let win = currentDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindow);
+      let win = currentDocShell.domWindow;
       let {currentURI} = currentDocShell.QueryInterface(Ci.nsIWebNavigation);
 
       this.previousURIMap.set(win, currentURI);
     }
 
     // This WeakSet of DOMWindows keeps track of the attempted refresh.
     this.refreshAttemptedDOMWindows = new WeakSet();
 
--- a/toolkit/modules/addons/WebNavigationFrames.jsm
+++ b/toolkit/modules/addons/WebNavigationFrames.jsm
@@ -4,27 +4,16 @@
 
 "use strict";
 
 const EXPORTED_SYMBOLS = ["WebNavigationFrames"];
 
 /* exported WebNavigationFrames */
 
 /**
- * Retrieve the DOMWindow associated to the docShell passed as parameter.
- *
- * @param    {nsIDocShell}  docShell - the docShell that we want to get the DOMWindow from.
- * @returns  {nsIDOMWindow}          - the DOMWindow associated to the docShell.
- */
-function docShellToWindow(docShell) {
-  return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                 .getInterface(Ci.nsIDOMWindow);
-}
-
-/**
  * The FrameDetail object which represents a frame in WebExtensions APIs.
  *
  * @typedef  {Object}  FrameDetail
  * @inner
  * @property {number}  frameId        - Represents the numeric id which identify the frame in its tab.
  * @property {number}  parentFrameId  - Represents the numeric id which identify the parent frame.
  * @property {string}  url            - Represents the current location URL loaded in the frame.
  * @property {boolean} errorOccurred  - Indicates whether an error is occurred during the last load
@@ -76,28 +65,27 @@ function getParentFrameId(window) {
   return getFrameId(window.parent);
 }
 
 function getDocShellFrameId(docShell) {
   if (!docShell) {
     return undefined;
   }
 
-  return getFrameId(docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIDOMWindow));
+  return getFrameId(docShell.domWindow);
 }
 
 /**
  * Convert a docShell object into its internal FrameDetail representation.
  *
  * @param    {nsIDocShell} docShell - the docShell object to be converted into a FrameDetail JSON object.
  * @returns  {FrameDetail} the FrameDetail JSON object which represents the docShell.
  */
 function convertDocShellToFrameDetail(docShell) {
-  let window = docShellToWindow(docShell);
+  let window = docShell.domWindow;
 
   return {
     frameId: getFrameId(window),
     parentFrameId: getParentFrameId(window),
     url: window.location.href,
   };
 }
 
@@ -108,17 +96,17 @@ function convertDocShellToFrameDetail(do
  * @param  {number}      frameId - the frame ID of the frame to retrieve, as
  *                                 described in getFrameId.
  * @param   {nsIDocShell} rootDocShell - the root docShell object
  * @returns {nsIDocShell?} the docShell with the given frameId, or null
  *                         if no match.
  */
 function findDocShell(frameId, rootDocShell) {
   for (let docShell of iterateDocShellTree(rootDocShell)) {
-    if (frameId == getFrameId(docShellToWindow(docShell))) {
+    if (frameId == getFrameId(docShell.domWindow)) {
       return docShell;
     }
   }
 
   return null;
 }
 
 var WebNavigationFrames = {
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -151,20 +151,17 @@ nsUnknownContentTypeDialog.prototype = {
   // When opening from new tab, if tab closes while dialog is opening,
   // (which is a race condition on the XUL file being cached and the timer
   // in nsExternalHelperAppService), the dialog gets a blur and doesn't
   // activate the OK button.  So we wait a bit before doing opening it.
   reallyShow() {
     try {
       let ir = this.mContext.QueryInterface(Ci.nsIInterfaceRequestor);
       let docShell = ir.getInterface(Ci.nsIDocShell);
-      let rootWin = docShell.QueryInterface(Ci.nsIDocShellTreeItem)
-                                 .rootTreeItem
-                                 .QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIDOMWindow);
+      let rootWin = docShell.rootTreeItem.domWindow;
       this.mDialog = Services.ww.openWindow(rootWin,
                                             "chrome://mozapps/content/downloads/unknownContentType.xul",
                                             null,
                                             "chrome,centerscreen,titlebar,dialog=yes,dependent",
                                             null);
     } catch (ex) {
       // The containing window may have gone away.  Break reference
       // cycles and stop doing the download.
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -279,22 +279,17 @@ function isDiscoverEnabled() {
 
   return true;
 }
 
 /**
  * Obtain the main DOMWindow for the current context.
  */
 function getMainWindow() {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIWebNavigation)
-               .QueryInterface(Ci.nsIDocShellTreeItem)
-               .rootTreeItem
-               .QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindow);
+  return window.document.docShell.rootTreeItem.domWindow;
 }
 
 function getBrowserElement() {
   return window.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDocShell)
                .chromeEventHandler;
 }
 
@@ -1911,18 +1906,17 @@ var gHeader = {
     var docshellItem = window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem);
 
     // If there is no outer frame then make the buttons visible
     if (docshellItem.rootTreeItem == docshellItem)
       return true;
 
-    var outerWin = docshellItem.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
-                                            .getInterface(Ci.nsIDOMWindow);
+    var outerWin = docshellItem.rootTreeItem.domWindow;
     var outerDoc = outerWin.document;
     var node = outerDoc.getElementById("back-button");
     // If the outer frame has no back-button then make the buttons visible
     if (!node)
       return true;
 
     // If the back-button or any of its parents are hidden then make the buttons
     // visible
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -449,21 +449,20 @@ function restart_manager(aManagerWindow,
 
   return close_manager(aManagerWindow)
     .then(() => open_manager(aView, aCallback, aLoadCallback));
 }
 
 function wait_for_window_open(aCallback) {
   let p = new Promise(resolve => {
     Services.wm.addListener({
-      onOpenWindow(aWindow) {
+      onOpenWindow(aXulWin) {
         Services.wm.removeListener(this);
 
-        let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindow);
+        let domwindow = aXulWin.docShell.domWindow;
         domwindow.addEventListener("load", function() {
           executeSoon(function() {
             resolve(domwindow);
           });
         }, {once: true});
       },
 
       onCloseWindow(aWindow) {
--- a/toolkit/mozapps/extensions/test/xpinstall/head.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/head.js
@@ -316,19 +316,18 @@ var Harness = {
       });
       this.expectingCancelled = false;
       this.endTest();
     }
   },
 
   // nsIWindowMediatorListener
 
-  onOpenWindow(window) {
-    var domwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindow);
+  onOpenWindow(xulWin) {
+    var domwindow = xulWin.docShell.domWindow;
     var self = this;
     waitForFocus(function() {
       self.windowReady(domwindow);
     }, domwindow);
   },
 
   onCloseWindow(window) {
   },
--- a/widget/headless/tests/test_headless.js
+++ b/widget/headless/tests/test_headless.js
@@ -32,18 +32,17 @@ function loadContentWindow(webNavigation
           return;
         }
         // Ignore events that don't change the document
         if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
           return;
         }
         let docShell = webNavigation.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell);
-        let contentWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                            .getInterface(Ci.nsIDOMWindow);
+        let contentWindow = docShell.domWindow;
         webProgress.removeProgressListener(progressListener);
         progressListeners.delete(progressListener);
         contentWindow.addEventListener("load", (event) => {
           resolve(contentWindow);
         }, { once: true });
       },
       QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
                                              "nsISupportsWeakReference"])
--- a/widget/tests/test_bug593307.xul
+++ b/widget/tests/test_bug593307.xul
@@ -24,22 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 
 function finish() {
   offscreenWindow.close();
   SimpleTest.finish();
 }
 
-var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIWebNavigation)
-                       .QueryInterface(Ci.nsIDocShellTreeItem)
-                       .rootTreeItem
-                       .QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDOMWindow);
+var mainWindow = window.document.docShell.rootTreeItem.domWindow;
 
 var offscreenWindow = mainWindow.openDialog("window_bug593307_offscreen.xul", "",
                                             "dialog=no,chrome,width=200,height=200,screenX=-3000,screenY=-3000",
                                             SimpleTest, finish);
 
 ]]>
 </script>