Merge inbound to mozilla-central r=merge a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Fri, 10 Nov 2017 11:55:43 +0200
changeset 391143 864174ac0707207f7fc698ed6c3c47c043e99395
parent 391051 e9814434b1a95cc4633c5a41e0f0e5b772bf9135 (current diff)
parent 391142 9d9e227c3a5e054cbcafeae96bdab938723389cb (diff)
child 391144 6683618bb98e768f545ac270847ed815904d6bba
child 391178 43c9ffb04eee6d40682156b15fdd6c5b09242a37
child 391276 915df99dbfe737cfa9e1ee6b231100761e229191
push id32860
push userebalazs@mozilla.com
push dateFri, 10 Nov 2017 09:56:38 +0000
treeherdermozilla-central@864174ac0707 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
864174ac0707 / 58.0a1 / 20171110100139 / files
nightly linux64
864174ac0707 / 58.0a1 / 20171110100139 / files
nightly mac
864174ac0707 / 58.0a1 / 20171110100139 / files
nightly win32
864174ac0707 / 58.0a1 / 20171110100139 / files
nightly win64
864174ac0707 / 58.0a1 / 20171110100139 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central r=merge a=merge
dom/interfaces/json/moz.build
dom/interfaces/json/nsIJSON.idl
dom/json/moz.build
dom/json/nsJSON.cpp
dom/json/nsJSON.h
dom/json/test/mochitest.ini
dom/json/test/test_json.html
dom/json/test/unit/decodeFromStream-01.json
dom/json/test/unit/decodeFromStream-small.json
dom/json/test/unit/test_decodeFromStream.js
dom/json/test/unit/xpcshell.ini
services/sync/tps/extensions/tps/resource/tps.jsm
toolkit/crashreporter/tools/unit-symbolstore.py
tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-nsISupportsString-preferences.js
tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -160,27 +160,26 @@ void
 ApplicationAccessible::Init()
 {
   // Basically children are kept updated by Append/RemoveChild method calls.
   // However if there are open windows before accessibility was started
   // then we need to make sure root accessibles for open windows are created so
   // that all root accessibles are stored in application accessible children
   // array.
 
-  nsGlobalWindow::WindowByIdTable* windowsById =
-    nsGlobalWindow::GetWindowsTable();
+  nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
+    nsGlobalWindowOuter::GetWindowsTable();
 
   if (!windowsById) {
     return;
   }
 
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
-    nsGlobalWindow* window = iter.Data();
-    if (window->GetDocShell() && window->IsOuterWindow() &&
-        window->IsRootOuterWindow()) {
+    nsGlobalWindowOuter* window = iter.Data();
+    if (window->GetDocShell() && window->IsRootOuterWindow()) {
       nsCOMPtr<nsIDocument> docNode = window->GetExtantDoc();
 
       if (docNode) {
         GetAccService()->GetDocAccessible(docNode);  // ensure creation
       }
     }
   }
 }
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -480,17 +480,18 @@ RootAccessible::Shutdown()
 
 Relation
 RootAccessible::RelationByType(RelationType aType)
 {
   if (!mDocumentNode || aType != RelationType::EMBEDS)
     return DocAccessibleWrap::RelationByType(aType);
 
   if (nsPIDOMWindowOuter* rootWindow = mDocumentNode->GetWindow()) {
-    nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
+    nsCOMPtr<nsPIDOMWindowOuter> contentWindow =
+      nsGlobalWindowOuter::Cast(rootWindow)->GetContent();
     if (contentWindow) {
       nsCOMPtr<nsIDocument> contentDocumentNode = contentWindow->GetDoc();
       if (contentDocumentNode) {
         DocAccessible* contentDocument =
           GetAccService()->GetDocAccessible(contentDocumentNode);
         if (contentDocument)
           return Relation(contentDocument);
       }
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -424,16 +424,17 @@ pref("browser.sessionhistory.max_entries
 pref("permissions.manager.defaultsUrl", "resource://app/defaults/permissions");
 
 // Set default fallback values for site permissions we want
 // the user to be able to globally change.
 pref("permissions.default.camera", 0);
 pref("permissions.default.microphone", 0);
 pref("permissions.default.geo", 0);
 pref("permissions.default.desktop-notification", 0);
+pref("permissions.default.shortcuts", 0);
 
 // handle links targeting new windows
 // 1=current window/tab, 2=new window, 3=new tab in most recent window
 pref("browser.link.open_newwindow", 3);
 
 // handle external links (i.e. links opened from a different application)
 // default: use browser.link.open_newwindow
 // 1-3: see browser.link.open_newwindow for interpretation
--- a/browser/base/content/test/permissions/browser.ini
+++ b/browser/base/content/test/permissions/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files=
   head.js
   permissions.html
 
 [browser_canvas_fingerprinting_resistance.js]
 [browser_permissions.js]
+[browser_reservedkey.js]
 [browser_temporary_permissions.js]
 support-files =
   temporary_permissions_subframe.html
   ../webrtc/get_user_media.html
 [browser_temporary_permissions_expiry.js]
 [browser_temporary_permissions_navigation.js]
 [browser_temporary_permissions_tabs.js]
--- a/browser/base/content/test/permissions/browser_permissions.js
+++ b/browser/base/content/test/permissions/browser_permissions.js
@@ -171,8 +171,48 @@ add_task(async function testPermissionIc
     SitePermissions.remove(gBrowser.currentURI, "geo");
 
     ok(!geoIcon.hasAttribute("showing"),
       "blocked permission icon is not shown after reset");
 
     SitePermissions.remove(gBrowser.currentURI, "camera");
   });
 });
+
+add_task(async function testPermissionShortcuts() {
+  await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function(browser) {
+    browser.focus();
+
+    await new Promise(r => {
+      SpecialPowers.pushPrefEnv({"set": [["permissions.default.shortcuts", 0]]}, r);
+    });
+
+    async function tryKey(desc, expectedValue) {
+      await EventUtils.synthesizeAndWaitKey("c", { accelKey: true });
+      let result = await ContentTask.spawn(browser, null, function() {
+        return content.wrappedJSObject.gKeyPresses;
+      });
+      is(result, expectedValue, desc);
+    }
+
+    await tryKey("pressed with default permissions", 1);
+
+    SitePermissions.set(gBrowser.currentURI, "shortcuts", SitePermissions.BLOCK);
+    await tryKey("pressed when site blocked", 1);
+
+    SitePermissions.set(gBrowser.currentURI, "shortcuts", SitePermissions.ALLOW);
+    await tryKey("pressed when site allowed", 2);
+
+    SitePermissions.remove(gBrowser.currentURI, "shortcuts");
+    await new Promise(r => {
+      SpecialPowers.pushPrefEnv({"set": [["permissions.default.shortcuts", 2]]}, r);
+    });
+
+    await tryKey("pressed when globally blocked", 2);
+    SitePermissions.set(gBrowser.currentURI, "shortcuts", SitePermissions.ALLOW);
+    await tryKey("pressed when globally blocked but site allowed", 3);
+
+    SitePermissions.set(gBrowser.currentURI, "shortcuts", SitePermissions.BLOCK);
+    await tryKey("pressed when globally blocked and site blocked", 3);
+
+    SitePermissions.remove(gBrowser.currentURI, "shortcuts");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/permissions/browser_reservedkey.js
@@ -0,0 +1,92 @@
+add_task(async function test_reserved_shortcuts() {
+  /* eslint-disable no-unsanitized/property */
+  let keyset = `<keyset>
+                  <key id='kt_reserved' modifiers='shift' key='O' reserved='true' count='0'
+                       oncommand='this.setAttribute("count", Number(this.getAttribute("count")) + 1)'/>
+                  <key id='kt_notreserved' modifiers='shift' key='P' reserved='false' count='0'
+                       oncommand='this.setAttribute("count", Number(this.getAttribute("count")) + 1)'/>
+                  <key id='kt_reserveddefault' modifiers='shift' key='Q' count='0'
+                       oncommand='this.setAttribute("count", Number(this.getAttribute("count")) + 1)'/>
+                </keyset>`;
+
+  let container = document.createElement("box");
+  container.innerHTML = keyset;
+  document.documentElement.appendChild(container);
+  /* eslint-enable no-unsanitized/property */
+
+  const pageUrl = "data:text/html,<body onload='document.body.firstChild.focus();'><div onkeydown='event.preventDefault();' tabindex=0>Test</div></body>";
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+
+  EventUtils.synthesizeKey("O", { shiftKey: true });
+  EventUtils.synthesizeKey("P", { shiftKey: true });
+  EventUtils.synthesizeKey("Q", { shiftKey: true });
+
+  is(document.getElementById("kt_reserved").getAttribute("count"), "1", "reserved='true' with preference off");
+  is(document.getElementById("kt_notreserved").getAttribute("count"), "0", "reserved='false' with preference off");
+  is(document.getElementById("kt_reserveddefault").getAttribute("count"), "0", "default reserved with preference off");
+
+  // Now try with reserved shortcut key handling enabled.
+  await new Promise(resolve => {
+    SpecialPowers.pushPrefEnv({"set": [["permissions.default.shortcuts", 2]]}, resolve);
+  });
+
+  EventUtils.synthesizeKey("O", { shiftKey: true });
+  EventUtils.synthesizeKey("P", { shiftKey: true });
+  EventUtils.synthesizeKey("Q", { shiftKey: true });
+
+  is(document.getElementById("kt_reserved").getAttribute("count"), "2", "reserved='true' with preference on");
+  is(document.getElementById("kt_notreserved").getAttribute("count"), "0", "reserved='false' with preference on");
+  is(document.getElementById("kt_reserveddefault").getAttribute("count"), "1", "default reserved with preference on");
+
+  document.documentElement.removeChild(container);
+
+  await BrowserTestUtils.removeTab(tab);
+});
+
+// This test checks that Alt+<key> and F10 cannot be blocked when the preference is set.
+if (navigator.platform.indexOf("Mac") == -1) {
+  add_task(async function test_accesskeys_menus() {
+    await new Promise(resolve => {
+      SpecialPowers.pushPrefEnv({"set": [["permissions.default.shortcuts", 2]]}, resolve);
+    });
+
+    const uri = "data:text/html,<body onkeydown='if (event.key == \"H\" || event.key == \"F10\") event.preventDefault();'>";
+    let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
+
+    // Pressing Alt+H should open the Help menu.
+    let helpPopup = document.getElementById("menu_HelpPopup");
+    let popupShown = BrowserTestUtils.waitForEvent(helpPopup, "popupshown");
+    EventUtils.synthesizeKey("VK_ALT", { type: "keydown" });
+    EventUtils.synthesizeKey("H", { altKey: true });
+    EventUtils.synthesizeKey("VK_ALT", { type: "keyup" });
+    await popupShown;
+
+    ok(true, "Help menu opened");
+
+    let popupHidden = BrowserTestUtils.waitForEvent(helpPopup, "popuphidden");
+    helpPopup.hidePopup();
+    await popupHidden;
+
+    // Pressing F10 should focus the menubar. On Linux, the file menu should open, but on Windows,
+    // pressing Down will open the file menu.
+    let menubar = document.getElementById("main-menubar");
+    let menubarActive = BrowserTestUtils.waitForEvent(menubar, "DOMMenuBarActive");
+    EventUtils.sendKey("F10");
+    await menubarActive;
+
+    let filePopup = document.getElementById("menu_FilePopup");
+    popupShown = BrowserTestUtils.waitForEvent(filePopup, "popupshown");
+    if (navigator.platform.indexOf("Win") >= 0) {
+      EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
+    }
+    await popupShown;
+
+    ok(true, "File menu opened");
+
+    popupHidden = BrowserTestUtils.waitForEvent(filePopup, "popuphidden");
+    filePopup.hidePopup();
+    await popupHidden;
+
+    await BrowserTestUtils.removeTab(tab1);
+  });
+}
--- a/browser/base/content/test/permissions/permissions.html
+++ b/browser/base/content/test/permissions/permissions.html
@@ -1,15 +1,18 @@
 <!DOCTYPE HTML>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <html dir="ltr" xml:lang="en-US" lang="en-US">
   <head>
     <meta charset="utf8">
   </head>
-  <body>
+<script>
+var gKeyPresses = 0;
+</script>
+  <body onkeypress="gKeyPresses++;">
 	<!-- This page could eventually request permissions from content
 	     and make sure that chrome responds appropriately -->
   <button id="geo" onclick="navigator.geolocation.getCurrentPosition(() => {})">Geolocation</button>
   <button id="camera" onclick="navigator.mediaDevices.getUserMedia({video: true, fake: true})">Camera</button>
   </body>
 </html>
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 2.0.104
+Current extension version is: 2.0.106
 
-Taken from upstream commit: 012d0756
+Taken from upstream commit: 0052dc2b
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -144,43 +144,52 @@ function getLocalizedString(strings, id,
     return strings[id][property];
   }
   return id;
 }
 
 // PDF data storage
 function PdfDataListener(length) {
   this.length = length; // less than 0, if length is unknown
-  this.buffer = null;
+  this.buffers = [];
   this.loaded = 0;
 }
 
 PdfDataListener.prototype = {
   append: function PdfDataListener_append(chunk) {
     // In most of the cases we will pass data as we receive it, but at the
     // beginning of the loading we may accumulate some data.
-    if (!this.buffer) {
-      this.buffer = new Uint8Array(chunk);
-    } else {
-      var buffer = this.buffer;
-      var newBuffer = new Uint8Array(buffer.length + chunk.length);
-      newBuffer.set(buffer);
-      newBuffer.set(chunk, buffer.length);
-      this.buffer = newBuffer;
-    }
+    this.buffers.push(chunk);
     this.loaded += chunk.length;
     if (this.length >= 0 && this.length < this.loaded) {
       this.length = -1; // reset the length, server is giving incorrect one
     }
     this.onprogress(this.loaded, this.length >= 0 ? this.length : void 0);
   },
   readData: function PdfDataListener_readData() {
-    var result = this.buffer;
-    this.buffer = null;
-    return result;
+    if (this.buffers.length === 0) {
+      return null;
+    }
+    if (this.buffers.length === 1) {
+      return this.buffers.pop();
+    }
+    // There are multiple buffers that need to be combined into a single
+    // buffer.
+    let combinedLength = 0;
+    for (let buffer of this.buffers) {
+      combinedLength += buffer.length;
+    }
+    let combinedArray = new Uint8Array(combinedLength);
+    let writeOffset = 0;
+    while (this.buffers.length) {
+      let buffer = this.buffers.shift();
+      combinedArray.set(buffer, writeOffset);
+      writeOffset += buffer.length;
+    }
+    return combinedArray;
   },
   finish: function PdfDataListener_finish() {
     this.isDataReady = true;
     if (this.oncompleteCallback) {
       this.oncompleteCallback(this.readData());
     }
   },
   error: function PdfDataListener_error(errorCode) {
@@ -873,18 +882,19 @@ PdfStreamConverter.prototype = {
   // nsIStreamListener::onDataAvailable
   onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount) {
     if (!this.dataListener) {
       return;
     }
 
     var binaryStream = this.binaryStream;
     binaryStream.setInputStream(aInputStream);
-    var chunk = binaryStream.readByteArray(aCount);
-    this.dataListener.append(chunk);
+    let chunk = new ArrayBuffer(aCount);
+    binaryStream.readArrayBuffer(aCount, chunk);
+    this.dataListener.append(new Uint8Array(chunk));
   },
 
   // nsIRequestObserver::onStartRequest
   onStartRequest(aRequest, aContext) {
     // Setup the request so we can use it below.
     var isHttpRequest = false;
     try {
       aRequest.QueryInterface(Ci.nsIHttpChannel);
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -1956,17 +1956,17 @@ function getDocument(src) {
     });
   }).catch(task._capability.reject);
   return task;
 }
 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
   if (worker.destroyed) {
     return Promise.reject(new Error('Worker was destroyed'));
   }
-  let apiVersion = '2.0.104';
+  let apiVersion = '2.0.106';
   source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
   source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
   source.chunkedViewerLoading = !!pdfDataRangeTransport;
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
@@ -3253,18 +3253,18 @@ var InternalRenderTask = function Intern
         }
       }
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.104';
-  exports.build = build = '012d0756';
+  exports.version = version = '2.0.106';
+  exports.build = build = '0052dc2b';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -4988,18 +4988,18 @@ exports.SVGGraphics = SVGGraphics;
 
 /***/ }),
 /* 9 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.104';
-var pdfjsBuild = '012d0756';
+var pdfjsVersion = '2.0.106';
+var pdfjsBuild = '0052dc2b';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(7);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(6);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(8);
 ;
@@ -8113,18 +8113,18 @@ var _svg = __w_pdfjs_require__(8);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 if (!_global_scope2.default.PDFJS) {
   _global_scope2.default.PDFJS = {};
 }
 var PDFJS = _global_scope2.default.PDFJS;
 {
-  PDFJS.version = '2.0.104';
-  PDFJS.build = '012d0756';
+  PDFJS.version = '2.0.106';
+  PDFJS.build = '0052dc2b';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -23279,18 +23279,18 @@ exports.PostScriptCompiler = PostScriptC
 
 /***/ }),
 /* 17 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.104';
-var pdfjsBuild = '012d0756';
+var pdfjsVersion = '2.0.106';
+var pdfjsBuild = '0052dc2b';
 var pdfjsCoreWorker = __w_pdfjs_require__(18);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 18 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -23475,17 +23475,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.104';
+    let workerVersion = '2.0.106';
     if (apiVersion !== null && apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
     var handler = new _util.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -201,17 +201,16 @@
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
 @RESPATH@/components/dom_html.xpt
 @RESPATH@/components/dom_offline.xpt
-@RESPATH@/components/dom_json.xpt
 @RESPATH@/components/dom_payments.xpt
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_push.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_sidebar.xpt
 @RESPATH@/components/dom_storage.xpt
--- a/browser/locales/en-US/chrome/browser/sitePermissions.properties
+++ b/browser/locales/en-US/chrome/browser/sitePermissions.properties
@@ -30,10 +30,11 @@ permission.cookie.label = Set Cookies
 permission.desktop-notification2.label = Receive Notifications
 permission.image.label = Load Images
 permission.camera.label = Use the Camera
 permission.microphone.label = Use the Microphone
 permission.screen.label = Share the Screen
 permission.install.label = Install Add-ons
 permission.popup.label = Open Pop-up Windows
 permission.geo.label = Access Your Location
+permission.shortcuts.label = Override Keyboard Shortcuts
 permission.focus-tab-by-prompt.label = Switch to this Tab
 permission.persistent-storage.label = Store Data in Persistent Storage
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -621,17 +621,21 @@ var gPermissionObject = {
   },
 
   "focus-tab-by-prompt": {
     exactHostMatch: true,
     states: [ SitePermissions.UNKNOWN, SitePermissions.ALLOW ],
   },
   "persistent-storage": {
     exactHostMatch: true
-  }
+  },
+
+  "shortcuts": {
+    states: [ SitePermissions.ALLOW, SitePermissions.BLOCK ],
+  },
 };
 
 // Delete this entry while being pre-off
 // or the persistent-storage permission would appear in Page info's Permission section
 if (!Services.prefs.getBoolPref("browser.storageManager.enabled")) {
   delete gPermissionObject["persistent-storage"];
 }
 
--- a/browser/modules/test/browser/browser_SitePermissions.js
+++ b/browser/modules/test/browser/browser_SitePermissions.js
@@ -20,20 +20,23 @@ add_task(async function testTempAllowThr
 });
 
 // This tests the SitePermissions.getAllPermissionDetailsForBrowser function.
 add_task(async function testGetAllPermissionDetailsForBrowser() {
   let uri = Services.io.newURI("https://example.com");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
 
+  Services.prefs.setIntPref("permissions.default.shortcuts", 2);
+
   SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
   SitePermissions.set(uri, "cookie", SitePermissions.ALLOW_COOKIES_FOR_SESSION);
   SitePermissions.set(uri, "popup", SitePermissions.BLOCK);
   SitePermissions.set(uri, "geo", SitePermissions.ALLOW, SitePermissions.SCOPE_SESSION);
+  SitePermissions.set(uri, "shortcuts", SitePermissions.ALLOW);
 
   let permissions = SitePermissions.getAllPermissionDetailsForBrowser(tab.linkedBrowser);
 
   let camera = permissions.find(({id}) => id === "camera");
   Assert.deepEqual(camera, {
     id: "camera",
     label: "Use the Camera",
     state: SitePermissions.ALLOW,
@@ -66,15 +69,26 @@ add_task(async function testGetAllPermis
   let geo = permissions.find(({id}) => id === "geo");
   Assert.deepEqual(geo, {
     id: "geo",
     label: "Access Your Location",
     state: SitePermissions.ALLOW,
     scope: SitePermissions.SCOPE_SESSION,
   });
 
+  let shortcuts = permissions.find(({id}) => id === "shortcuts");
+  Assert.deepEqual(shortcuts, {
+    id: "shortcuts",
+    label: "Override Keyboard Shortcuts",
+    state: SitePermissions.ALLOW,
+    scope: SitePermissions.SCOPE_PERSISTENT,
+  });
+
   SitePermissions.remove(uri, "cookie");
   SitePermissions.remove(uri, "popup");
   SitePermissions.remove(uri, "geo");
+  SitePermissions.remove(uri, "shortcuts");
+
+  Services.prefs.clearUserPref("permissions.default.shortcuts");
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
--- a/browser/modules/test/unit/test_SitePermissions.js
+++ b/browser/modules/test/unit/test_SitePermissions.js
@@ -5,17 +5,17 @@
 
 Components.utils.import("resource:///modules/SitePermissions.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const STORAGE_MANAGER_ENABLED = Services.prefs.getBoolPref("browser.storageManager.enabled");
 
 add_task(async function testPermissionsListing() {
   let expectedPermissions = ["camera", "cookie", "desktop-notification", "focus-tab-by-prompt",
-     "geo", "image", "install", "microphone", "popup", "screen"];
+     "geo", "image", "install", "microphone", "popup", "screen", "shortcuts"];
   if (STORAGE_MANAGER_ENABLED) {
     // The persistent-storage permission is still only pref-on on Nightly
     // so we add it only when it's pref-on.
     // Should remove this checking and add it as default after it is fully pref-on.
     expectedPermissions.push("persistent-storage");
   }
   Assert.deepEqual(SitePermissions.listPermissions().sort(), expectedPermissions.sort(),
     "Correct list of all permissions");
@@ -53,16 +53,28 @@ add_task(async function testGetAllByURI(
   SitePermissions.remove(uri, "camera");
   SitePermissions.remove(uri, "desktop-notification");
   Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
 
   // XXX Bug 1303108 - Control Center should only show non-default permissions
   SitePermissions.set(uri, "addon", SitePermissions.BLOCK);
   Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
   SitePermissions.remove(uri, "addon");
+
+  Assert.equal(Services.prefs.getIntPref("permissions.default.shortcuts"), 0);
+  SitePermissions.set(uri, "shortcuts", SitePermissions.BLOCK);
+
+  // Customized preference should have been enabled, but the default should not.
+  Assert.equal(Services.prefs.getIntPref("permissions.default.shortcuts"), 0);
+  Assert.deepEqual(SitePermissions.getAllByURI(uri), [
+      { id: "shortcuts", state: SitePermissions.BLOCK, scope: SitePermissions.SCOPE_PERSISTENT },
+  ]);
+
+  SitePermissions.remove(uri, "shortcuts");
+  Services.prefs.clearUserPref("permissions.default.shortcuts");
 });
 
 add_task(async function testGetAvailableStates() {
   Assert.deepEqual(SitePermissions.getAvailableStates("camera"),
                    [ SitePermissions.UNKNOWN,
                      SitePermissions.ALLOW,
                      SitePermissions.BLOCK ]);
 
@@ -91,17 +103,17 @@ add_task(async function testExactHostMat
   let exactHostMatched = ["desktop-notification", "focus-tab-by-prompt", "camera",
                           "microphone", "screen", "geo"];
   if (STORAGE_MANAGER_ENABLED) {
     // The persistent-storage permission is still only pref-on on Nightly
     // so we add it only when it's pref-on.
     // Should remove this checking and add it as default after it is fully pref-on.
     exactHostMatched.push("persistent-storage");
   }
-  let nonExactHostMatched = ["image", "cookie", "popup", "install"];
+  let nonExactHostMatched = ["image", "cookie", "popup", "install", "shortcuts"];
 
   let permissions = SitePermissions.listPermissions();
   for (let permission of permissions) {
     SitePermissions.set(uri, permission, SitePermissions.ALLOW);
 
     if (exactHostMatched.includes(permission)) {
       // Check that the sub-origin does not inherit the permission from its parent.
       Assert.equal(SitePermissions.get(subUri, permission).state, SitePermissions.UNKNOWN,
--- a/build/build-clang/clang-win32.json
+++ b/build/build-clang/clang-win32.json
@@ -8,11 +8,16 @@
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
     "python_path": "c:/mozilla-build/python/python.exe",
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "patches": [
       "msvc-host-x64.patch",
-      "loosen-msvc-detection.patch"
+      "loosen-msvc-detection.patch",
+      "r314201.patch",
+      "r315677.patch",
+      "r316048.patch",
+      "r317705.patch",
+      "r317709.patch"
     ]
 }
--- a/build/build-clang/clang-win64.json
+++ b/build/build-clang/clang-win64.json
@@ -8,11 +8,16 @@
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
     "python_path": "c:/mozilla-build/python/python.exe",
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "ml": "ml64.exe",
     "patches": [
-      "loosen-msvc-detection.patch"
+      "loosen-msvc-detection.patch",
+      "r314201.patch",
+      "r315677.patch",
+      "r316048.patch",
+      "r317705.patch",
+      "r317709.patch"
     ]
 }
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r314201.patch
@@ -0,0 +1,54 @@
+From 71e7a8ba8994e5b1f9cc0a0986b2ef5d37ed8ad2 Mon Sep 17 00:00:00 2001
+From: Sylvestre Ledru <sylvestre@debian.org>
+Date: Tue, 26 Sep 2017 11:56:43 +0000
+Subject: [PATCH] Don't move llvm.localescape outside the entry block in the
+ GCOV profiling pass
+
+Summary:
+This fixes https://bugs.llvm.org/show_bug.cgi?id=34714.
+
+Patch by Marco Castelluccio
+
+Reviewers: rnk
+
+Reviewed By: rnk
+
+Subscribers: llvm-commits
+
+Differential Revision: https://reviews.llvm.org/D38224
+
+git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314201 91177308-0d34-0410-b5e6-96231b3b80d8
+---
+ lib/Transforms/Instrumentation/GCOVProfiling.cpp | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+index b2033536ac8..3154c1939ea 100644
+--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
++++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+@@ -502,6 +502,16 @@ static bool functionHasLines(Function &F) {
+   return false;
+ }
+ 
++static bool shouldKeepInEntry(BasicBlock::iterator It) {
++	if (isa<AllocaInst>(*It)) return true;
++	if (isa<DbgInfoIntrinsic>(*It)) return true;
++	if (auto *II = dyn_cast<IntrinsicInst>(It)) {
++		if (II->getIntrinsicID() == llvm::Intrinsic::localescape) return true;
++	}
++
++	return false;
++}
++
+ void GCOVProfiler::emitProfileNotes() {
+   NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
+   if (!CU_Nodes) return;
+@@ -537,7 +547,7 @@ void GCOVProfiler::emitProfileNotes() {
+       // single successor, so split the entry block to make sure of that.
+       BasicBlock &EntryBlock = F.getEntryBlock();
+       BasicBlock::iterator It = EntryBlock.begin();
+-      while (isa<AllocaInst>(*It) || isa<DbgInfoIntrinsic>(*It))
++      while (shouldKeepInEntry(It))
+         ++It;
+       EntryBlock.splitBasicBlock(It);
+ 
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r315677.patch
@@ -0,0 +1,67 @@
+From 44847b2e9838888e1536c90ad442a3958362139a Mon Sep 17 00:00:00 2001
+From: Marco Castelluccio <mcastelluccio@mozilla.com>
+Date: Fri, 13 Oct 2017 13:49:15 +0000
+Subject: [PATCH] Disable gcov instrumentation of functions using funclet-based
+ exception handling
+
+Summary: This patch fixes the crash from https://bugs.llvm.org/show_bug.cgi?id=34659 and https://bugs.llvm.org/show_bug.cgi?id=34833.
+
+Reviewers: rnk, majnemer
+
+Reviewed By: rnk, majnemer
+
+Subscribers: majnemer, llvm-commits
+
+Differential Revision: https://reviews.llvm.org/D38223
+
+git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315677 91177308-0d34-0410-b5e6-96231b3b80d8
+---
+ lib/Transforms/Instrumentation/GCOVProfiling.cpp | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+index 3154c1939ea..67ca8172b0d 100644
+--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
++++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+@@ -21,6 +21,7 @@
+ #include "llvm/ADT/StringExtras.h"
+ #include "llvm/ADT/StringMap.h"
+ #include "llvm/ADT/UniqueVector.h"
++#include "llvm/Analysis/EHPersonalities.h"
+ #include "llvm/IR/DebugInfo.h"
+ #include "llvm/IR/DebugLoc.h"
+ #include "llvm/IR/IRBuilder.h"
+@@ -502,6 +503,13 @@ static bool functionHasLines(Function &F) {
+   return false;
+ }
+ 
++static bool isUsingFuncletBasedEH(Function &F) {
++  if (!F.hasPersonalityFn()) return false;
++
++  EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn());
++  return isFuncletEHPersonality(Personality);
++}
++
+ static bool shouldKeepInEntry(BasicBlock::iterator It) {
+ 	if (isa<AllocaInst>(*It)) return true;
+ 	if (isa<DbgInfoIntrinsic>(*It)) return true;
+@@ -542,6 +550,8 @@ void GCOVProfiler::emitProfileNotes() {
+       DISubprogram *SP = F.getSubprogram();
+       if (!SP) continue;
+       if (!functionHasLines(F)) continue;
++      // TODO: Functions using funclet-based EH are currently not supported.
++      if (isUsingFuncletBasedEH(F)) continue;
+ 
+       // gcov expects every function to start with an entry block that has a
+       // single successor, so split the entry block to make sure of that.
+@@ -619,7 +629,10 @@ bool GCOVProfiler::emitProfileArcs() {
+       DISubprogram *SP = F.getSubprogram();
+       if (!SP) continue;
+       if (!functionHasLines(F)) continue;
++      // TODO: Functions using funclet-based EH are currently not supported.
++      if (isUsingFuncletBasedEH(F)) continue;
+       if (!Result) Result = true;
++
+       unsigned Edges = 0;
+       for (auto &BB : F) {
+         TerminatorInst *TI = BB.getTerminator();
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r316048.patch
@@ -0,0 +1,60 @@
+From 98adaa2097783c0fe3a4c948397e3f2182dcc5d2 Mon Sep 17 00:00:00 2001
+From: Marco Castelluccio <mcastelluccio@mozilla.com>
+Date: Wed, 18 Oct 2017 00:22:01 +0000
+Subject: [PATCH] Use O_BINARY when opening GCDA file on Windows
+
+Summary:
+Fixes https://bugs.llvm.org/show_bug.cgi?id=34922.
+
+Apparently, the mode in **fdopen** gets simply ignored and Windows only cares about the mode of the original **open**.
+
+I have verified this both with the simple case from bug 34922 and with a full Firefox build.
+
+Reviewers: zturner
+
+Reviewed By: zturner
+
+Subscribers: llvm-commits
+
+Differential Revision: https://reviews.llvm.org/D38984
+
+git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316048 91177308-0d34-0410-b5e6-96231b3b80d8
+---
+ lib/profile/GCDAProfiling.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
+index 138af6ec4..8c92546bd 100644
+--- a/compiler-rt/lib/profile/GCDAProfiling.c
++++ b/compiler-rt/lib/profile/GCDAProfiling.c
+@@ -37,6 +37,9 @@
+ #ifndef MAP_FILE
+ #define MAP_FILE 0
+ #endif
++#ifndef O_BINARY
++#define O_BINARY 0
++#endif
+ #endif
+ 
+ #if defined(__FreeBSD__) && defined(__i386__)
+@@ -238,17 +241,17 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+ 
+   /* Try just opening the file. */
+   new_file = 0;
+-  fd = open(filename, O_RDWR);
++  fd = open(filename, O_RDWR | O_BINARY);
+ 
+   if (fd == -1) {
+     /* Try opening the file, creating it if necessary. */
+     new_file = 1;
+     mode = "w+b";
+-    fd = open(filename, O_RDWR | O_CREAT, 0644);
++    fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
+     if (fd == -1) {
+       /* Try creating the directories first then opening the file. */
+       __llvm_profile_recursive_mkdir(filename);
+-      fd = open(filename, O_RDWR | O_CREAT, 0644);
++      fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
+       if (fd == -1) {
+         /* Bah! It's hopeless. */
+         int errnum = errno;
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r317705.patch
@@ -0,0 +1,92 @@
+From 07e2a968c83c489c5b46efe4973114e78e1804c1 Mon Sep 17 00:00:00 2001
+From: Marco Castelluccio <mcastelluccio@mozilla.com>
+Date: Wed, 8 Nov 2017 19:11:54 +0000
+Subject: [PATCH] Implement flock for Windows in compiler-rt
+
+Summary:
+This patch implements flock for Windows, needed to make gcda writing work in a multiprocessing scenario.
+
+Fixes https://bugs.llvm.org/show_bug.cgi?id=34923.
+
+Reviewers: zturner
+
+Reviewed By: zturner
+
+Subscribers: rnk, zturner, llvm-commits
+
+Differential Revision: https://reviews.llvm.org/D38891
+
+git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317705 91177308-0d34-0410-b5e6-96231b3b80d8
+---
+ lib/profile/WindowsMMap.c | 58 ++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 55 insertions(+), 3 deletions(-)
+
+diff --git a/compiler-rt/lib/profile/WindowsMMap.c b/lib/profile/WindowsMMap.c
+index f81d7da53..0c534710b 100644
+--- a/compiler-rt/lib/profile/WindowsMMap.c
++++ b/compiler-rt/lib/profile/WindowsMMap.c
+@@ -120,9 +120,61 @@ int msync(void *addr, size_t length, int flags)
+ }
+ 
+ COMPILER_RT_VISIBILITY
+-int flock(int fd, int operation)
+-{
+-  return -1; /* Not supported. */
++int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
++  DWORD flags = lockType;
++  if (!blocking)
++    flags |= LOCKFILE_FAIL_IMMEDIATELY;
++
++  OVERLAPPED overlapped;
++  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
++  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
++  BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
++  if (!result) {
++    DWORD dw = GetLastError();
++
++    // In non-blocking mode, return an error if the file is locked.
++    if (!blocking && dw == ERROR_LOCK_VIOLATION)
++      return -1; // EWOULDBLOCK
++
++    // If the error is ERROR_IO_PENDING, we need to wait until the operation
++    // finishes. Otherwise, we return an error.
++    if (dw != ERROR_IO_PENDING)
++      return -1;
++
++    DWORD dwNumBytes;
++    if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
++      return -1;
++  }
++
++  return 0;
++}
++
++COMPILER_RT_VISIBILITY
++int flock(int fd, int operation) {
++  HANDLE handle = (HANDLE)_get_osfhandle(fd);
++  if (handle == INVALID_HANDLE_VALUE)
++    return -1;
++
++  BOOL blocking = (operation & LOCK_NB) == 0;
++  int op = operation & ~LOCK_NB;
++
++  switch (op) {
++  case LOCK_EX:
++    return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
++
++  case LOCK_SH:
++    return lock(handle, 0, blocking);
++
++  case LOCK_UN:
++    if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
++      return -1;
++    break;
++
++  default:
++    return -1;
++  }
++
++  return 0;
+ }
+ 
+ #undef DWORD_HI
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r317709.patch
@@ -0,0 +1,51 @@
+From 8f15f3c70065372ce412075f5f369847b55351d2 Mon Sep 17 00:00:00 2001
+From: Marco Castelluccio <mcastelluccio@mozilla.com>
+Date: Wed, 8 Nov 2017 19:21:54 +0000
+Subject: [PATCH] Add CoreOption flag to "-coverage" option to make it
+ available for clang-cl
+
+Summary:
+The -coverage option is not a CoreOption, so it is not available to clang-cl.
+This patch adds the CoreOption flag to "-coverage" to allow it to be used with clang-cl.
+
+Reviewers: rnk
+
+Reviewed By: rnk
+
+Subscribers: cfe-commits
+
+Differential Revision: https://reviews.llvm.org/D38221
+
+git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317709 91177308-0d34-0410-b5e6-96231b3b80d8
+---
+ include/clang/Driver/Options.td | 2 +-
+ test/Driver/coverage.c          | 7 +++++++
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+ create mode 100644 test/Driver/coverage.c
+
+diff --git a/clang/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
+index 597e03b563d..01605619e02 100644
+--- a/clang/include/clang/Driver/Options.td
++++ b/clang/include/clang/Driver/Options.td
+@@ -519,7 +519,7 @@ def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-round
+ def client__name : JoinedOrSeparate<["-"], "client_name">;
+ def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>;
+ def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">;
+-def coverage : Flag<["-", "--"], "coverage">;
++def coverage : Flag<["-", "--"], "coverage">, Flags<[CoreOption]>;
+ def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
+ def current__version : JoinedOrSeparate<["-"], "current_version">;
+ def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
+diff --git a/clang/test/Driver/coverage.c b/clang/test/Driver/coverage.c
+new file mode 100644
+index 00000000000..339c4a3f366
+--- /dev/null
++++ b/clang/test/Driver/coverage.c
+@@ -0,0 +1,7 @@
++// Test coverage flag.
++//
++// RUN: %clang_cl -### -coverage %s -o foo/bar.o 2>&1 | FileCheck -check-prefix=CLANG-CL-COVERAGE %s
++// CLANG-CL-COVERAGE-NOT: error:
++// CLANG-CL-COVERAGE-NOT: warning:
++// CLANG-CL-COVERAGE-NOT: argument unused
++// CLANG-CL-COVERAGE-NOT: unknown argument
--- a/devtools/client/commandline/test/browser_cmd_pref3.js
+++ b/devtools/client/commandline/test/browser_cmd_pref3.js
@@ -2,19 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the pref commands work
 
 var prefBranch = Cc["@mozilla.org/preferences-service;1"]
                     .getService(Ci.nsIPrefService).getBranch(null)
                     .QueryInterface(Ci.nsIPrefBranch);
 
-var supportsString = Cc["@mozilla.org/supports-string;1"]
-                      .createInstance(Ci.nsISupportsString);
-
 const TEST_URI = "data:text/html;charset=utf-8,gcli-pref3";
 
 function test() {
   return Task.spawn(spawnTest).then(finish, helpers.handleError);
 }
 
 function* spawnTest() {
   let options = yield helpers.openTab(TEST_URI);
@@ -96,15 +93,13 @@ function* spawnTest() {
       },
       post: function () {
         var mozfoo = prefBranch.getStringPref("devtools.debugger.remote-host");
         is(mozfoo, "moz.foo", "devtools.debugger.remote-host is moz.foo");
       }
     },
   ]);
 
-  supportsString.data = remoteHostOrig;
-  prefBranch.setComplexValue("devtools.debugger.remote-host",
-                             Ci.nsISupportsString, supportsString);
+  prefBranch.setStringPref("devtools.debugger.remote-host", remoteHostOrig);
 
   yield helpers.closeToolbar(options);
   yield helpers.closeTab(options);
 }
--- a/devtools/client/commandline/test/browser_cmd_settings.js
+++ b/devtools/client/commandline/test/browser_cmd_settings.js
@@ -2,19 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the pref commands work
 
 var prefBranch = Cc["@mozilla.org/preferences-service;1"]
                     .getService(Ci.nsIPrefService).getBranch(null)
                     .QueryInterface(Ci.nsIPrefBranch);
 
-var supportsString = Cc["@mozilla.org/supports-string;1"]
-                      .createInstance(Ci.nsISupportsString);
-
 const TEST_URI = "data:text/html;charset=utf-8,gcli-settings";
 
 function test() {
   return Task.spawn(spawnTest).then(finish, helpers.handleError);
 }
 
 function* spawnTest() {
   // Setup
@@ -109,15 +106,12 @@ function* spawnTest() {
 
   is(hideIntroEnabled.value, hideIntroEnabledDefault, "hideIntroEnabled reset");
   is(tabSize.value, tabSizeDefault, "tabSize reset");
   is(remoteHost.value, remoteHostDefault, "remoteHost reset");
 
   // Cleanup
   prefBranch.setBoolPref("devtools.gcli.hideIntro", hideIntroOrig);
   prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig);
-  supportsString.data = remoteHostOrig;
-  prefBranch.setComplexValue("devtools.debugger.remote-host",
-          Components.interfaces.nsISupportsString,
-          supportsString);
+  prefBranch.setStringPref("devtools.debugger.remote-host", remoteHostOrig);
 
   yield helpers.closeTab(options);
 }
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -88,16 +88,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_highlighter-csstransform_01.js]
 [browser_inspector_highlighter-csstransform_02.js]
 [browser_inspector_highlighter-embed.js]
 [browser_inspector_highlighter-eyedropper-clipboard.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_highlighter-eyedropper-csp.js]
 [browser_inspector_highlighter-eyedropper-events.js]
+skip-if = os == 'win' # bug 1413442
 [browser_inspector_highlighter-eyedropper-image.js]
 [browser_inspector_highlighter-eyedropper-label.js]
 [browser_inspector_highlighter-eyedropper-show-hide.js]
 [browser_inspector_highlighter-eyedropper-xul.js]
 [browser_inspector_highlighter-geometry_01.js]
 [browser_inspector_highlighter-geometry_02.js]
 [browser_inspector_highlighter-geometry_03.js]
 [browser_inspector_highlighter-geometry_04.js]
--- a/devtools/shared/gcli/source/lib/gcli/settings.js
+++ b/devtools/shared/gcli/source/lib/gcli/settings.js
@@ -26,21 +26,16 @@ var XPCOMUtils = Cu.import('resource://g
 var Services = require("Services");
 
 XPCOMUtils.defineLazyGetter(imports, 'prefBranch', function() {
   var prefService = Cc['@mozilla.org/preferences-service;1']
           .getService(Ci.nsIPrefService);
   return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch);
 });
 
-XPCOMUtils.defineLazyGetter(imports, 'supportsString', function() {
-  return Cc['@mozilla.org/supports-string;1']
-          .createInstance(Ci.nsISupportsString);
-});
-
 var util = require('./util/util');
 
 /**
  * All local settings have this prefix when used in Firefox
  */
 var DEVTOOLS_PREFIX = 'devtools.gcli.';
 
 /**
@@ -261,20 +256,17 @@ Object.defineProperty(Setting.prototype,
         imports.prefBranch.setBoolPref(this.name, value);
         break;
 
       case imports.prefBranch.PREF_INT:
         imports.prefBranch.setIntPref(this.name, value);
         break;
 
       case imports.prefBranch.PREF_STRING:
-        imports.supportsString.data = value;
-        imports.prefBranch.setComplexValue(this.name,
-                Ci.nsISupportsString,
-                imports.supportsString);
+        imports.prefBranch.setStringPref(this.name, value);
         break;
 
       default:
         throw new Error('Invalid value for ' + this.name);
     }
 
     Services.prefs.savePrefFile(null);
   },
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3269,17 +3269,17 @@ nsDocShell::GetCustomUserAgent(nsAString
   aCustomUserAgent = mCustomUserAgent;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
 {
   mCustomUserAgent = aCustomUserAgent;
-  RefPtr<nsGlobalWindow> win = mScriptGlobal ?
+  RefPtr<nsGlobalWindowInner> win = mScriptGlobal ?
     mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
   if (win) {
     Navigator* navigator = win->Navigator();
     if (navigator) {
       navigator->ClearUserAgentCache();
     }
   }
 
@@ -3774,17 +3774,17 @@ nsDocShell::CanAccessItem(nsIDocShellTre
 
   return CanAccessItem(openerItem, aAccessingItem, false);
 }
 
 static bool
 ItemIsActive(nsIDocShellTreeItem* aItem)
 {
   if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) {
-    auto* win = nsGlobalWindow::Cast(window);
+    auto* win = nsGlobalWindowOuter::Cast(window);
     MOZ_ASSERT(win->IsOuterWindow());
     if (!win->GetClosedOuter()) {
       return true;
     }
   }
 
   return false;
 }
@@ -10614,18 +10614,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       UpdateGlobalHistoryTitle(aURI);
 
       SetDocCurrentStateObj(mOSHE);
 
       // Inform the favicon service that the favicon for oldURI also
       // applies to aURI.
       CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
 
-      RefPtr<nsGlobalWindow> scriptGlobal = mScriptGlobal;
-      RefPtr<nsGlobalWindow> win = scriptGlobal ?
+      RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal;
+      RefPtr<nsGlobalWindowInner> win = scriptGlobal ?
         scriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
 
       // ScrollToAnchor doesn't necessarily cause us to scroll the window;
       // the function decides whether a scroll is appropriate based on the
       // arguments it receives.  But even if we don't end up scrolling,
       // ScrollToAnchor performs other important tasks, such as informing
       // the presShell that we have a new hash.  See bug 680257.
       rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -72,17 +72,18 @@ namespace dom {
 class EventTarget;
 class PendingGlobalHistoryEntry;
 typedef uint32_t ScreenOrientationInternal;
 } // namespace dom
 } // namespace mozilla
 
 class nsDocShell;
 class nsDOMNavigationTiming;
-class nsGlobalWindow;
+class nsGlobalWindowOuter;
+class nsGlobalWindowInner;
 class nsIController;
 class nsIScrollableFrame;
 class OnLinkClickEvent;
 class nsDSURIContentListener;
 class nsDocShellEditorData;
 class nsIClipboardDragDropHookList;
 class nsICommandManager;
 class nsIContentViewer;
@@ -913,17 +914,17 @@ protected:
   RefPtr<nsDSURIContentListener> mContentListener;
   nsCOMPtr<nsIContentViewer> mContentViewer;
   nsCOMPtr<nsIWidget> mParentWidget;
 
   // mCurrentURI should be marked immutable on set if possible.
   nsCOMPtr<nsIURI> mCurrentURI;
   nsCOMPtr<nsIURI> mReferrerURI;
   uint32_t mReferrerPolicy;
-  RefPtr<nsGlobalWindow> mScriptGlobal;
+  RefPtr<nsGlobalWindowOuter> mScriptGlobal;
   nsCOMPtr<nsISHistory> mSessionHistory;
   nsCOMPtr<nsIGlobalHistory2> mGlobalHistory;
   nsCOMPtr<nsIWebBrowserFind> mFind;
   nsCOMPtr<nsICommandManager> mCommandManager;
   // Reference to the SHEntry for this docshell until the page is destroyed.
   // Somebody give me better name
   nsCOMPtr<nsISHEntry> mOSHE;
   // Reference to the SHEntry for this docshell until the page is loaded
--- a/docshell/test/chrome/chrome.ini
+++ b/docshell/test/chrome/chrome.ini
@@ -48,16 +48,17 @@ support-files =
   mozFrameType_window.xul
   test_docRedirect.sjs
 
 [test_allowContentRetargeting.html]
 [test_bug112564.xul]
 [test_bug113934.xul]
 [test_bug215405.xul]
 [test_bug293235.xul]
+skip-if = true # bug 1393441
 [test_bug294258.xul]
 [test_bug298622.xul]
 [test_bug301397.xul]
 [test_bug303267.xul]
 [test_bug311007.xul]
 [test_bug321671.xul]
 [test_bug360511.xul]
 [test_bug364461.xul]
--- a/dom/animation/AnimationUtils.cpp
+++ b/dom/animation/AnimationUtils.cpp
@@ -37,17 +37,17 @@ AnimationUtils::LogAsyncAnimationFailure
   }
   aMessage.Append('\n');
   printf_stderr("%s", aMessage.get());
 }
 
 /* static */ nsIDocument*
 AnimationUtils::GetCurrentRealmDocument(JSContext* aCx)
 {
-  nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx);
+  nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aCx);
   if (!win) {
     return nullptr;
   }
   return win->GetDoc();
 }
 
 /* static */ bool
 AnimationUtils::IsOffscreenThrottlingEnabled()
--- a/dom/base/BarProps.cpp
+++ b/dom/base/BarProps.cpp
@@ -13,17 +13,17 @@
 #include "nsIWebBrowserChrome.h"
 
 namespace mozilla {
 namespace dom {
 
 //
 //  Basic (virtual) BarProp class implementation
 //
-BarProp::BarProp(nsGlobalWindow* aWindow)
+BarProp::BarProp(nsGlobalWindowInner* aWindow)
   : mDOMWindow(aWindow)
 {
   MOZ_ASSERT(aWindow->IsInnerWindow());
 }
 
 BarProp::~BarProp()
 {
 }
@@ -101,17 +101,17 @@ BarProp::GetBrowserChrome()
 
   return mDOMWindow->GetWebBrowserChrome();
 }
 
 //
 // MenubarProp class implementation
 //
 
-MenubarProp::MenubarProp(nsGlobalWindow *aWindow)
+MenubarProp::MenubarProp(nsGlobalWindowInner *aWindow)
   : BarProp(aWindow)
 {
 }
 
 MenubarProp::~MenubarProp()
 {
 }
 
@@ -127,17 +127,17 @@ MenubarProp::SetVisible(bool aVisible, C
   BarProp::SetVisibleByFlag(aVisible, nsIWebBrowserChrome::CHROME_MENUBAR,
                             aCallerType, aRv);
 }
 
 //
 // ToolbarProp class implementation
 //
 
-ToolbarProp::ToolbarProp(nsGlobalWindow *aWindow)
+ToolbarProp::ToolbarProp(nsGlobalWindowInner *aWindow)
   : BarProp(aWindow)
 {
 }
 
 ToolbarProp::~ToolbarProp()
 {
 }
 
@@ -153,17 +153,17 @@ ToolbarProp::SetVisible(bool aVisible, C
   BarProp::SetVisibleByFlag(aVisible, nsIWebBrowserChrome::CHROME_TOOLBAR,
                             aCallerType, aRv);
 }
 
 //
 // LocationbarProp class implementation
 //
 
-LocationbarProp::LocationbarProp(nsGlobalWindow *aWindow)
+LocationbarProp::LocationbarProp(nsGlobalWindowInner *aWindow)
   : BarProp(aWindow)
 {
 }
 
 LocationbarProp::~LocationbarProp()
 {
 }
 
@@ -181,17 +181,17 @@ LocationbarProp::SetVisible(bool aVisibl
   BarProp::SetVisibleByFlag(aVisible, nsIWebBrowserChrome::CHROME_LOCATIONBAR,
                             aCallerType, aRv);
 }
 
 //
 // PersonalbarProp class implementation
 //
 
-PersonalbarProp::PersonalbarProp(nsGlobalWindow *aWindow)
+PersonalbarProp::PersonalbarProp(nsGlobalWindowInner *aWindow)
   : BarProp(aWindow)
 {
 }
 
 PersonalbarProp::~PersonalbarProp()
 {
 }
 
@@ -210,17 +210,17 @@ PersonalbarProp::SetVisible(bool aVisibl
                             nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR,
                             aCallerType, aRv);
 }
 
 //
 // StatusbarProp class implementation
 //
 
-StatusbarProp::StatusbarProp(nsGlobalWindow *aWindow)
+StatusbarProp::StatusbarProp(nsGlobalWindowInner *aWindow)
   : BarProp(aWindow)
 {
 }
 
 StatusbarProp::~StatusbarProp()
 {
 }
 
@@ -238,17 +238,17 @@ StatusbarProp::SetVisible(bool aVisible,
                                    nsIWebBrowserChrome::CHROME_STATUSBAR,
                                    aCallerType, aRv);
 }
 
 //
 // ScrollbarsProp class implementation
 //
 
-ScrollbarsProp::ScrollbarsProp(nsGlobalWindow *aWindow)
+ScrollbarsProp::ScrollbarsProp(nsGlobalWindowInner *aWindow)
 : BarProp(aWindow)
 {
 }
 
 ScrollbarsProp::~ScrollbarsProp()
 {
 }
 
--- a/dom/base/BarProps.h
+++ b/dom/base/BarProps.h
@@ -14,31 +14,31 @@
 #define mozilla_dom_BarProps_h
 
 #include "mozilla/Attributes.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 class nsIWebBrowserChrome;
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 // Script "BarProp" object
 class BarProp : public nsISupports,
                 public nsWrapperCache
 {
 public:
-  explicit BarProp(nsGlobalWindow *aWindow);
+  explicit BarProp(nsGlobalWindowInner *aWindow);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BarProp)
 
   nsPIDOMWindowInner* GetParentObject() const;
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -51,84 +51,84 @@ protected:
   virtual ~BarProp();
 
   bool GetVisibleByFlag(uint32_t aChromeFlag, ErrorResult& aRv);
   void SetVisibleByFlag(bool aVisible, uint32_t aChromeFlag,
                         CallerType aCallerType, ErrorResult &aRv);
 
   already_AddRefed<nsIWebBrowserChrome> GetBrowserChrome();
 
-  RefPtr<nsGlobalWindow> mDOMWindow;
+  RefPtr<nsGlobalWindowInner> mDOMWindow;
 };
 
 // Script "menubar" object
 class MenubarProp final : public BarProp
 {
 public:
-  explicit MenubarProp(nsGlobalWindow *aWindow);
+  explicit MenubarProp(nsGlobalWindowInner *aWindow);
   virtual ~MenubarProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 // Script "toolbar" object
 class ToolbarProp final : public BarProp
 {
 public:
-  explicit ToolbarProp(nsGlobalWindow *aWindow);
+  explicit ToolbarProp(nsGlobalWindowInner *aWindow);
   virtual ~ToolbarProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 // Script "locationbar" object
 class LocationbarProp final : public BarProp
 {
 public:
-  explicit LocationbarProp(nsGlobalWindow *aWindow);
+  explicit LocationbarProp(nsGlobalWindowInner *aWindow);
   virtual ~LocationbarProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 // Script "personalbar" object
 class PersonalbarProp final : public BarProp
 {
 public:
-  explicit PersonalbarProp(nsGlobalWindow *aWindow);
+  explicit PersonalbarProp(nsGlobalWindowInner *aWindow);
   virtual ~PersonalbarProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 // Script "statusbar" object
 class StatusbarProp final : public BarProp
 {
 public:
-  explicit StatusbarProp(nsGlobalWindow *aWindow);
+  explicit StatusbarProp(nsGlobalWindowInner *aWindow);
   virtual ~StatusbarProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 // Script "scrollbars" object
 class ScrollbarsProp final : public BarProp
 {
 public:
-  explicit ScrollbarsProp(nsGlobalWindow *aWindow);
+  explicit ScrollbarsProp(nsGlobalWindowInner *aWindow);
   virtual ~ScrollbarsProp();
 
   virtual bool GetVisible(CallerType aCallerType, ErrorResult& aRv) override;
   virtual void SetVisible(bool aVisible, CallerType aCallerType,
                           ErrorResult& aRv) override;
 };
 
 } // namespace dom
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -510,33 +510,32 @@ Location::SetHrefWithBase(const nsAStrin
      * so that the new url will be appended to Session History.
      * This solution is tricky. Hopefully it isn't going to bite
      * anywhere else. This is part of solution for bug # 39938, 72197
      */
     bool inScriptTag = false;
     nsIScriptContext* scriptContext = nullptr;
     nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetEntryGlobal());
     if (win) {
-      scriptContext = nsGlobalWindow::Cast(win)->GetContextInternal();
+      scriptContext = nsGlobalWindowInner::Cast(win)->GetContextInternal();
     }
 
     if (scriptContext) {
       if (scriptContext->GetProcessingScriptTag()) {
         // Now check to make sure that the script is running in our window,
         // since we only want to replace if the location is set by a
         // <script> tag in the same window.  See bug 178729.
         nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
           docShell ? docShell->GetScriptGlobalObject() : nullptr;
         inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
       }
     }
 
     return SetURI(newUri, aReplace || inScriptTag);
-  }
-
+  } 
   return result;
 }
 
 void
 Location::GetOrigin(nsAString& aOrigin,
                     nsIPrincipal& aSubjectPrincipal,
                     ErrorResult& aRv)
 {
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1441,17 +1441,17 @@ void
 Navigator::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads,
                        ErrorResult& aRv)
 {
   if (!mWindow) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   win->SetHasGamepadEventListener(true);
   win->GetGamepads(aGamepads);
 }
 
 GamepadServiceTest*
 Navigator::RequestGamepadServiceTest()
 {
   if (!mGamepadServiceTest) {
@@ -1463,17 +1463,17 @@ Navigator::RequestGamepadServiceTest()
 already_AddRefed<Promise>
 Navigator::GetVRDisplays(ErrorResult& aRv)
 {
   if (!mWindow || !mWindow->GetDocShell()) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   win->NotifyVREventListenerAdded();
 
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
   RefPtr<Promise> p = Promise::Create(go, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
@@ -1500,33 +1500,33 @@ Navigator::GetActiveVRDisplays(nsTArray<
    * as that would cause enumeration and activation of other VR hardware.
    * Activating VR hardware is intrusive to the end user, as it may
    * involve physically powering on devices that the user did not
    * intend to use.
    */
   if (!mWindow || !mWindow->GetDocShell()) {
     return;
   }
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   nsTArray<RefPtr<VRDisplay>> displays;
   if (win->UpdateVRDisplays(displays)) {
     for (auto display : displays) {
       if (display->IsPresenting()) {
         aDisplays.AppendElement(display);
       }
     }
   }
 }
 
 void
 Navigator::NotifyVRDisplaysUpdated()
 {
   // Synchronize the VR devices and resolve the promises in
   // mVRGetDisplaysPromises
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
 
   nsTArray<RefPtr<VRDisplay>> vrDisplays;
   if (win->UpdateVRDisplays(vrDisplays)) {
     for (auto p : mVRGetDisplaysPromises) {
       p->MaybeResolve(vrDisplays);
     }
   } else {
     for (auto p : mVRGetDisplaysPromises) {
@@ -1541,43 +1541,43 @@ Navigator::NotifyActiveVRDisplaysChanged
 {
   NavigatorBinding::ClearCachedActiveVRDisplaysValue(this);
 }
 
 VRServiceTest*
 Navigator::RequestVRServiceTest()
 {
   // Ensure that the Mock VR devices are not released prematurely
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   win->NotifyVREventListenerAdded();
 
   if (!mVRServiceTest) {
     mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
   }
   return mVRServiceTest;
 }
 
 bool
 Navigator::IsWebVRContentDetected() const
 {
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   return win->IsVRContentDetected();
 }
 
 bool
 Navigator::IsWebVRContentPresenting() const
 {
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   return win->IsVRContentPresenting();
 }
 
 void
 Navigator::RequestVRPresentation(VRDisplay& aDisplay)
 {
-  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow);
   win->DispatchVRDisplayActivate(aDisplay.DisplayId(), VRDisplayEventReason::Requested);
 }
 
 //*****************************************************************************
 //    Navigator::nsIMozNavigatorNetwork
 //*****************************************************************************
 
 NS_IMETHODIMP
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -24,19 +24,19 @@
 #include "nsIPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsPresContext.h"
 #include "nsQueryObject.h"
 
 namespace mozilla {
 namespace dom {
 
-PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
+PostMessageEvent::PostMessageEvent(nsGlobalWindowOuter* aSource,
                                    const nsAString& aCallerOrigin,
-                                   nsGlobalWindow* aTargetWindow,
+                                   nsGlobalWindowOuter* aTargetWindow,
                                    nsIPrincipal* aProvidedPrincipal,
                                    nsIDocument* aSourceDocument,
                                    bool aTrustedCaller)
   : Runnable("dom::PostMessageEvent")
   , StructuredCloneHolder(CloningSupported,
                           TransferringSupported,
                           StructuredCloneScope::SameProcessSameThread)
   , mSource(aSource)
@@ -71,17 +71,17 @@ PostMessageEvent::Run()
   // Use a stack variable so mSourceDocument is not held onto after this method
   // finishes, regardless of the method outcome.
   nsCOMPtr<nsIDocument> sourceDocument;
   sourceDocument.swap(mSourceDocument);
 
   // If we bailed before this point we're going to leak mMessage, but
   // that's probably better than crashing.
 
-  RefPtr<nsGlobalWindow> targetWindow;
+  RefPtr<nsGlobalWindowInner> targetWindow;
   if (mTargetWindow->IsClosedOrClosing() ||
       !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
       targetWindow->IsClosedOrClosing())
     return NS_OK;
 
   MOZ_ASSERT(targetWindow->IsInnerWindow(),
              "we ordered an inner window!");
   JSAutoCompartment ac(cx, targetWindow->GetWrapper());
@@ -171,17 +171,17 @@ PostMessageEvent::Run()
                           messageData, mCallerOrigin,
                           EmptyString(), source, ports);
 
   Dispatch(targetWindow, event);
   return NS_OK;
 }
 
 void
-PostMessageEvent::DispatchError(JSContext* aCx, nsGlobalWindow* aTargetWindow,
+PostMessageEvent::DispatchError(JSContext* aCx, nsGlobalWindowInner* aTargetWindow,
                                 mozilla::dom::EventTarget* aEventTarget)
 {
   RootedDictionary<MessageEventInit> init(aCx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mOrigin = mCallerOrigin;
 
   if (mSource) {
@@ -190,17 +190,17 @@ PostMessageEvent::DispatchError(JSContex
 
   RefPtr<Event> event =
     MessageEvent::Constructor(aEventTarget, NS_LITERAL_STRING("messageerror"),
                               init);
   Dispatch(aTargetWindow, event);
 }
 
 void
-PostMessageEvent::Dispatch(nsGlobalWindow* aTargetWindow, Event* aEvent)
+PostMessageEvent::Dispatch(nsGlobalWindowInner* aTargetWindow, Event* aEvent)
 {
   // We can't simply call dispatchEvent on the window because doing so ends
   // up flipping the trusted bit on the event, and we don't want that to
   // happen because then untrusted content can call postMessage on a chrome
   // window if it can get a reference to it.
 
   nsIPresShell *shell = aTargetWindow->GetExtantDoc()->GetShell();
   RefPtr<nsPresContext> presContext;
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -8,53 +8,54 @@
 #define mozilla_dom_PostMessageEvent_h
 
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowOuter;
+class nsGlobalWindowInner;
 class nsIDocument;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
 /**
  * Class used to represent events generated by calls to Window.postMessage,
  * which asynchronously creates and dispatches events.
  */
 class PostMessageEvent final : public Runnable
                              , public StructuredCloneHolder
 {
 public:
   NS_DECL_NSIRUNNABLE
 
-  PostMessageEvent(nsGlobalWindow* aSource,
+  PostMessageEvent(nsGlobalWindowOuter* aSource,
                    const nsAString& aCallerOrigin,
-                   nsGlobalWindow* aTargetWindow,
+                   nsGlobalWindowOuter* aTargetWindow,
                    nsIPrincipal* aProvidedPrincipal,
                    nsIDocument* aSourceDocument,
                    bool aTrustedCaller);
 
 private:
   ~PostMessageEvent();
 
   void
-  Dispatch(nsGlobalWindow* aTargetWindow, Event* aEvent);
+  Dispatch(nsGlobalWindowInner* aTargetWindow, Event* aEvent);
 
   void
-  DispatchError(JSContext* aCx, nsGlobalWindow* aTargetWindow,
+  DispatchError(JSContext* aCx, nsGlobalWindowInner* aTargetWindow,
                 mozilla::dom::EventTarget* aEventTarget);
 
-  RefPtr<nsGlobalWindow> mSource;
+  RefPtr<nsGlobalWindowOuter> mSource;
   nsString mCallerOrigin;
-  RefPtr<nsGlobalWindow> mTargetWindow;
+  RefPtr<nsGlobalWindowOuter> mTargetWindow;
   nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
   nsCOMPtr<nsIDocument> mSourceDocument;
   bool mTrustedCaller;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/ScreenOrientation.cpp
+++ b/dom/base/ScreenOrientation.cpp
@@ -608,17 +608,17 @@ ScreenOrientation::VisibleEventListener:
   nsCOMPtr<EventTarget> target = aEvent->InternalDOMEvent()->GetCurrentTarget();
   MOZ_ASSERT(target);
 
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(target);
   if (!doc || doc->Hidden()) {
     return NS_OK;
   }
 
-  auto* win = nsGlobalWindow::Cast(doc->GetInnerWindow());
+  auto* win = nsGlobalWindowInner::Cast(doc->GetInnerWindow());
   if (!win) {
     return NS_OK;
   }
 
   ErrorResult rv;
   nsScreen* screen = win->GetScreen(rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
--- a/dom/base/Timeout.h
+++ b/dom/base/Timeout.h
@@ -64,17 +64,17 @@ private:
 
 public:
   // Public member variables in this section.  Please don't add to this list
   // or mix methods with these.  The interleaving public/private sections
   // is necessary as we migrate members to private while still trying to
   // keep decent binary packing.
 
   // Window for which this timeout fires
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowInner> mWindow;
 
   // The language-specific information about the callback.
   nsCOMPtr<nsITimeoutHandler> mScriptHandler;
 
   // Interval
   TimeDuration mInterval;
 
   // Returned as value of setTimeout()
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -390,17 +390,17 @@ uint32_t gMaxConsecutiveCallbacksMillise
 
 // Only propagate the open window click permission if the setTimeout() is equal
 // to or less than this value.
 #define DEFAULT_DISABLE_OPEN_CLICK_DELAY 0
 int32_t gDisableOpenClickDelay;
 
 } // anonymous namespace
 
-TimeoutManager::TimeoutManager(nsGlobalWindow& aWindow)
+TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow)
   : mWindow(aWindow),
     mExecutor(new TimeoutExecutor(this)),
     mNormalTimeouts(*this),
     mTrackingTimeouts(*this),
     mTimeoutIdCounter(1),
     mNextFiringId(InvalidFiringId + 1),
     mRunningTimeout(nullptr),
     mIdleCallbackTimeoutCounter(1),
@@ -1189,17 +1189,17 @@ TimeoutManager::IsTimeoutTracking(uint32
 }
 
 namespace {
 
 class ThrottleTimeoutsCallback final : public nsITimerCallback
                                      , public nsINamed
 {
 public:
-  explicit ThrottleTimeoutsCallback(nsGlobalWindow* aWindow)
+  explicit ThrottleTimeoutsCallback(nsGlobalWindowInner* aWindow)
     : mWindow(aWindow)
   {
     MOZ_DIAGNOSTIC_ASSERT(aWindow->IsInnerWindow());
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
@@ -1210,17 +1210,17 @@ public:
   }
 
 private:
   ~ThrottleTimeoutsCallback() {}
 
 private:
   // The strong reference here keeps the Window and hence the TimeoutManager
   // object itself alive.
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowInner> mWindow;
 };
 
 NS_IMPL_ISUPPORTS(ThrottleTimeoutsCallback, nsITimerCallback, nsINamed)
 
 NS_IMETHODIMP
 ThrottleTimeoutsCallback::Notify(nsITimer* aTimer)
 {
   mWindow->AsInner()->TimeoutManager().StartThrottlingTimeouts();
--- a/dom/base/TimeoutManager.h
+++ b/dom/base/TimeoutManager.h
@@ -7,29 +7,29 @@
 #ifndef mozilla_dom_TimeoutManager_h__
 #define mozilla_dom_TimeoutManager_h__
 
 #include "mozilla/dom/Timeout.h"
 #include "nsTArray.h"
 
 class nsIEventTarget;
 class nsITimeoutHandler;
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class OrderedTimeoutIterator;
 class TimeoutExecutor;
 
 // This class manages the timeouts in a Window's setTimeout/setInterval pool.
 class TimeoutManager final
 {
 public:
-  explicit TimeoutManager(nsGlobalWindow& aWindow);
+  explicit TimeoutManager(nsGlobalWindowInner& aWindow);
   ~TimeoutManager();
   TimeoutManager(const TimeoutManager& rhs) = delete;
   void operator=(const TimeoutManager& rhs) = delete;
 
   bool IsRunningTimeout() const;
 
   static uint32_t GetNestingLevel() { return sNestingLevel; }
   static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }
@@ -210,19 +210,19 @@ private:
 
     // mTimeoutList is generally sorted by mWhen, but new values are always
     // inserted after any Timeouts with a valid FiringId.
     TimeoutList               mTimeoutList;
   };
 
   friend class OrderedTimeoutIterator;
 
-  // Each nsGlobalWindow object has a TimeoutManager member.  This reference
+  // Each nsGlobalWindowInner object has a TimeoutManager member.  This reference
   // points to that holder object.
-  nsGlobalWindow&             mWindow;
+  nsGlobalWindowInner&             mWindow;
   // The executor is specific to the nsGlobalWindow/TimeoutManager, but it
   // can live past the destruction of the window if its scheduled.  Therefore
   // it must be a separate ref-counted object.
   RefPtr<TimeoutExecutor>     mExecutor;
   // The list of timeouts coming from non-tracking scripts.
   Timeouts                    mNormalTimeouts;
   // The list of timeouts coming from scripts on the tracking protection list.
   Timeouts                    mTrackingTimeouts;
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1692,17 +1692,17 @@ WebSocketImpl::Init(JSContext* aCx,
         if (NS_WARN_IF(!currentInnerWindow)) {
           return NS_ERROR_DOM_SECURITY_ERR;
         }
 
         // We are at the top. Let's see if we have an opener window.
         if (innerWindow == currentInnerWindow) {
           ErrorResult error;
           parentWindow =
-            nsGlobalWindow::Cast(innerWindow)->GetOpenerWindow(error);
+            nsGlobalWindowInner::Cast(innerWindow)->GetOpenerWindow(error);
           if (NS_WARN_IF(error.Failed())) {
             error.SuppressException();
             return NS_ERROR_DOM_SECURITY_ERR;
           }
 
           if (!parentWindow) {
             break;
           }
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -101,17 +101,17 @@ WindowNamedPropertiesHandler::getOwnProp
   }
 
   if(str.IsEmpty()) {
     return true;
   }
 
   // Grab the DOM window.
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
-  nsGlobalWindow* win = xpc::WindowOrNull(global);
+  nsGlobalWindowInner* win = xpc::WindowOrNull(global);
   if (win->Length() > 0) {
     nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(str);
     if (childWin && ShouldExposeChildWindow(str, childWin)) {
       // We found a subframe of the right name. Shadowing via |var foo| in
       // global scope is still allowed, since |var| only looks up |own|
       // properties. But unqualified shadowing will fail, per-spec.
       JS::Rooted<JS::Value> v(aCx);
       if (!WrapObject(aCx, childWin, &v)) {
@@ -173,20 +173,20 @@ WindowNamedPropertiesHandler::ownPropNam
                                            JS::AutoIdVector& aProps) const
 {
   if (!(flags & JSITER_HIDDEN)) {
     // None of our named properties are enumerable.
     return true;
   }
 
   // Grab the DOM window.
-  nsGlobalWindow* win = xpc::WindowOrNull(JS_GetGlobalForObject(aCx, aProxy));
+  nsGlobalWindowInner* win = xpc::WindowOrNull(JS_GetGlobalForObject(aCx, aProxy));
   nsTArray<nsString> names;
   // The names live on the outer window, which might be null
-  nsGlobalWindow* outer = win->GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = win->GetOuterWindowInternal();
   if (outer) {
     nsDOMWindowList* childWindows = outer->GetWindowList();
     if (childWindows) {
       uint32_t length = childWindows->GetLength();
       for (uint32_t i = 0; i < length; ++i) {
         nsCOMPtr<nsIDocShellTreeItem> item =
           childWindows->GetDocShellTreeItemAt(i);
         // This is a bit silly, since we could presumably just do
--- a/dom/base/WindowOrientationObserver.cpp
+++ b/dom/base/WindowOrientationObserver.cpp
@@ -7,23 +7,23 @@
 #include "WindowOrientationObserver.h"
 
 #include "nsGlobalWindow.h"
 #include "mozilla/Hal.h"
 
 using namespace mozilla::dom;
 
 /**
- * This class is used by nsGlobalWindow to implement window.orientation
+ * This class is used by nsGlobalWindowInner to implement window.orientation
  * and window.onorientationchange. This class is defined in its own file
  * because Hal.h pulls in windows.h and can't be included from
  * nsGlobalWindow.cpp
  */
 WindowOrientationObserver::WindowOrientationObserver(
-  nsGlobalWindow* aGlobalWindow)
+  nsGlobalWindowInner* aGlobalWindow)
   : mWindow(aGlobalWindow)
 {
   MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow());
   hal::RegisterScreenConfigurationObserver(this);
 
   hal::ScreenConfiguration config;
   hal::GetCurrentScreenConfiguration(&config);
   mAngle = config.angle();
--- a/dom/base/WindowOrientationObserver.h
+++ b/dom/base/WindowOrientationObserver.h
@@ -4,32 +4,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_WindowOrientationObserver_h
 #define mozilla_dom_WindowOrientationObserver_h
 
 #include "mozilla/HalScreenConfiguration.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class WindowOrientationObserver final :
   public mozilla::hal::ScreenConfigurationObserver
 {
 public:
-  explicit WindowOrientationObserver(nsGlobalWindow* aGlobalWindow);
+  explicit WindowOrientationObserver(nsGlobalWindowInner* aGlobalWindow);
   ~WindowOrientationObserver();
   void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override;
   static int16_t OrientationAngle();
 
 private:
   // Weak pointer, instance is owned by mWindow.
-  nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
+  nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
   uint16_t mAngle;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_WindowOrientationObserver_h
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -207,17 +207,17 @@ MarkContentViewer(nsIContentViewer* aVie
         elm->MarkForCC();
       }
       nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow());
       if (win) {
         elm = win->GetExistingListenerManager();
         if (elm) {
           elm->MarkForCC();
         }
-        static_cast<nsGlobalWindow*>(win.get())->AsInner()->
+        static_cast<nsGlobalWindowInner*>(win.get())->AsInner()->
           TimeoutManager().UnmarkGrayTimers();
       }
     } else if (aPrepareForCC) {
       // Unfortunately we need to still mark user data just before running CC so
       // that it has the right generation.
       doc->PropertyTable(DOM_USER_DATA)->
         EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
     }
@@ -498,22 +498,22 @@ mozilla::dom::TraceBlackJS(JSTracer* aTr
   if (nsFrameMessageManager::GetChildProcessManager()) {
     nsIContentProcessMessageManager* pg = ProcessGlobal::Get();
     if (pg) {
       mozilla::TraceScriptHolder(pg, aTrc);
     }
   }
 
   // Mark globals of active windows black.
-  nsGlobalWindow::WindowByIdTable* windowsById =
-    nsGlobalWindow::GetWindowsTable();
+  nsGlobalWindowOuter::OuterWindowByIdTable* windowsById =
+    nsGlobalWindowOuter::GetWindowsTable();
   if (windowsById) {
     for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
-      nsGlobalWindow* window = iter.Data();
-      if (!window->IsCleanedUp() && window->IsOuterWindow()) {
+      nsGlobalWindowOuter* window = iter.Data();
+      if (!window->IsCleanedUp()) {
         window->TraceGlobalJSObject(aTrc);
         EventListenerManager* elm = window->GetExistingListenerManager();
         if (elm) {
           elm->TraceListeners(aTrc);
         }
 
         if (window->IsRootOuterWindow()) {
           // In child process trace all the TabChildGlobals.
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -66,16 +66,17 @@
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/Likely.h"
 #include "mozilla/ManualNAC.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ResultExtensions.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/TextEvents.h"
 #include "nsArrayUtils.h"
 #include "nsAString.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsBindingManager.h"
@@ -159,16 +160,17 @@
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsIParser.h"
 #include "nsIPermissionManager.h"
 #include "nsIPluginHost.h"
+#include "nsIRemoteBrowser.h"
 #include "nsIRequest.h"
 #include "nsIRunnable.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
@@ -4734,17 +4736,18 @@ nsContentUtils::MatchElementId(nsIConten
 nsIDocument*
 nsContentUtils::GetSubdocumentWithOuterWindowId(nsIDocument *aDocument,
                                                 uint64_t aOuterWindowId)
 {
   if (!aDocument || !aOuterWindowId) {
     return nullptr;
   }
 
-  RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetOuterWindowWithId(aOuterWindowId);
+  RefPtr<nsGlobalWindowOuter> window =
+    nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowId);
   if (!window) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->AsOuter();
   nsCOMPtr<nsIDocument> foundDoc = outerWindow->GetDoc();
   if (nsContentUtils::ContentIsCrossDocDescendantOf(foundDoc, aDocument)) {
     // Note that ContentIsCrossDocDescendantOf will return true if
@@ -9886,17 +9889,17 @@ nsContentUtils::SerializeNodeToMarkup(ns
 
 bool
 nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri)
 {
   // aUri must start with about: or this isn't the right function to be using.
   MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0);
 
   // Make sure the global is a window
-  nsGlobalWindow* win = xpc::WindowGlobalOrNull(aGlobal);
+  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aGlobal);
   if (!win) {
     return false;
   }
 
   nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
   NS_ENSURE_TRUE(principal, false);
   nsCOMPtr<nsIURI> uri;
   principal->GetURI(getter_AddRefs(uri));
@@ -10583,16 +10586,50 @@ nsContentUtils::CreateJSValueFromSequenc
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   aValue.setObject(*array);
   return NS_OK;
 }
 
+/* static */
+bool
+nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent* aKeyEvent)
+{
+  nsCOMPtr<nsIPrincipal> principal;
+  nsCOMPtr<nsIRemoteBrowser> targetBrowser = do_QueryInterface(aKeyEvent->mOriginalTarget);
+  if (targetBrowser) {
+    targetBrowser->GetContentPrincipal(getter_AddRefs(principal));
+  }
+  else {
+    // Get the top-level document.
+    nsCOMPtr<nsIContent> content = do_QueryInterface(aKeyEvent->mOriginalTarget);
+    if (content) {
+      nsIDocument* doc = content->GetUncomposedDoc();
+      if (doc) {
+        nsCOMPtr<nsIDocShellTreeItem> docShell = doc->GetDocShell();
+        if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
+          nsCOMPtr<nsIDocShellTreeItem> rootItem;
+          docShell->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
+          if (rootItem && rootItem->GetDocument()) {
+            principal = rootItem->GetDocument()->NodePrincipal();
+          }
+        }
+      }
+    }
+  }
+
+  if (principal) {
+    return nsContentUtils::IsSitePermDeny(principal, "shortcuts");
+  }
+
+  return false;
+}
+
 /* static */ Element*
 nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
 {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aElement->IsNativeAnonymous());
 
   Element* e = aElement;
   while (e && e->IsNativeAnonymous()) {
@@ -10728,17 +10765,18 @@ nsContentUtils::GetEventTargetByLoadInfo
     // There's no document yet, but this might be a top-level load where we can
     // find a TabGroup.
     uint64_t outerWindowId;
     if (NS_FAILED(aLoadInfo->GetOuterWindowID(&outerWindowId))) {
       // No window. This might be an add-on XHR, a service worker request, or
       // something else.
       return nullptr;
     }
-    RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetOuterWindowWithId(outerWindowId);
+    RefPtr<nsGlobalWindowOuter> window =
+      nsGlobalWindowOuter::GetOuterWindowWithId(outerWindowId);
     if (!window) {
       return nullptr;
     }
 
     target = window->TabGroup()->EventTargetFor(aCategory);
   }
 
   return target.forget();
@@ -10905,30 +10943,65 @@ nsContentUtils::IsOverridingWindowName(c
 {
   return !aName.IsEmpty() &&
     !aName.LowerCaseEqualsLiteral("_blank") &&
     !aName.LowerCaseEqualsLiteral("_top") &&
     !aName.LowerCaseEqualsLiteral("_parent") &&
     !aName.LowerCaseEqualsLiteral("_self");
 }
 
+// Unfortunately, we can't unwrap an IDL object using only a concrete type.
+// We need to calculate type data based on the IDL typename. Which means
+// wrapping our templated function in a macro.
+#define EXTRACT_EXN_VALUES(T, ...)                                \
+  ExtractExceptionValues<mozilla::dom::prototypes::id::T,         \
+                         T##Binding::NativeType, T>(__VA_ARGS__).isOk()
+
+template <prototypes::ID PrototypeID, class NativeType, typename T>
+static Result<Ok, nsresult>
+ExtractExceptionValues(JSContext* aCx,
+                       JS::HandleObject aObj,
+                       nsACString& aSourceSpecOut,
+                       uint32_t* aLineOut,
+                       uint32_t* aColumnOut,
+                       nsString& aMessageOut)
+{
+  RefPtr<T> exn;
+  MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn)));
+
+  nsAutoString filename;
+  exn->GetFilename(aCx, filename);
+  if (!filename.IsEmpty()) {
+    CopyUTF16toUTF8(filename, aSourceSpecOut);
+    *aLineOut = exn->LineNumber(aCx);
+    *aColumnOut = exn->ColumnNumber();
+  }
+
+  exn->GetName(aMessageOut);
+  aMessageOut.AppendLiteral(": ");
+
+  nsAutoString message;
+  exn->GetMessageMoz(message);
+  aMessageOut.Append(message);
+  return Ok();
+}
+
 /* static */ void
 nsContentUtils::ExtractErrorValues(JSContext* aCx,
                                    JS::Handle<JS::Value> aValue,
                                    nsACString& aSourceSpecOut,
                                    uint32_t* aLineOut,
                                    uint32_t* aColumnOut,
                                    nsString& aMessageOut)
 {
   MOZ_ASSERT(aLineOut);
   MOZ_ASSERT(aColumnOut);
 
   if (aValue.isObject()) {
     JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
-    RefPtr<dom::DOMException> domException;
 
     // Try to process as an Error object.  Use the file/line/column values
     // from the Error as they will be more specific to the root cause of
     // the problem.
     JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
     if (err) {
       // Use xpc to extract the error message only.  We don't actually send
       // this report anywhere.
@@ -10942,48 +11015,43 @@ nsContentUtils::ExtractErrorValues(JSCon
         CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
         *aLineOut = report->mLineNumber;
         *aColumnOut = report->mColumn;
       }
       aMessageOut.Assign(report->mErrorMsg);
     }
 
     // Next, try to unwrap the rejection value as a DOMException.
-    else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
-
-      nsAutoString filename;
-      domException->GetFilename(aCx, filename);
-      if (!filename.IsEmpty()) {
-        CopyUTF16toUTF8(filename, aSourceSpecOut);
-        *aLineOut = domException->LineNumber(aCx);
-        *aColumnOut = domException->ColumnNumber();
-      }
-
-      domException->GetName(aMessageOut);
-      aMessageOut.AppendLiteral(": ");
-
-      nsAutoString message;
-      domException->GetMessageMoz(message);
-      aMessageOut.Append(message);
+    else if (EXTRACT_EXN_VALUES(DOMException, aCx, obj, aSourceSpecOut,
+                                aLineOut, aColumnOut, aMessageOut)) {
+      return;
+    }
+
+    // Next, try to unwrap the rejection value as an XPC Exception.
+    else if (EXTRACT_EXN_VALUES(Exception, aCx, obj, aSourceSpecOut,
+                                aLineOut, aColumnOut, aMessageOut)) {
+      return;
     }
   }
 
   // If we could not unwrap a specific error type, then perform default safe
   // string conversions on primitives.  Objects will result in "[Object]"
   // unfortunately.
   if (aMessageOut.IsEmpty()) {
     nsAutoJSString jsString;
     if (jsString.init(aCx, aValue)) {
       aMessageOut = jsString;
     } else {
       JS_ClearPendingException(aCx);
     }
   }
 }
 
+#undef EXTRACT_EXN_VALUES
+
 /* static */ bool
 nsContentUtils::DevToolsEnabled(JSContext* aCx)
 {
   if (NS_IsMainThread()) {
     return sDevToolsEnabled;
   }
 
   workers::WorkerPrivate* workerPrivate = workers::GetWorkerPrivateFromContext(aCx);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3124,16 +3124,22 @@ public:
   CreateJSValueFromSequenceOfObject(JSContext* aCx,
                                     const mozilla::dom::Sequence<JSObject*>& aTransfer,
                                     JS::MutableHandle<JS::Value> aValue);
 
   static bool
   IsWebComponentsEnabled() { return sIsWebComponentsEnabled; }
 
   /**
+   * Returns true if reserved key events should be prevented from being sent
+   * to their target. Instead, the key event should be handled by chrome only.
+   */
+  static bool ShouldBlockReservedKeys(mozilla::WidgetKeyboardEvent* aKeyEvent);
+
+  /**
    * Walks up the tree from aElement until it finds an element that is
    * not native anonymous content.  aElement must be NAC itself.
    */
   static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
 
   /**
    * Returns the nsIPluginTag for the plugin we should try to use for a given
    * MIME type.
@@ -3406,16 +3412,17 @@ private:
 #ifndef RELEASE_OR_BETA
   static bool sBypassCSSOMOriginCheck;
 #endif
   static bool sIsScopedStyleEnabled;
   static bool sIsBytecodeCacheEnabled;
   static int32_t sBytecodeCacheStrategy;
   static uint32_t sCookiesLifetimePolicy;
   static uint32_t sCookiesBehavior;
+  static bool sShortcutsCustomized;
 
   static int32_t sPrivacyMaxInnerWidth;
   static int32_t sPrivacyMaxInnerHeight;
 
   class UserInteractionObserver;
   static UserInteractionObserver* sUserInteractionObserver;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -221,17 +221,17 @@ FindObjectClass(JSContext* cx, JSObject*
     js::GetObjectProto(cx, obj, &proto);
   } while (proto);
 
   sObjectClass = js::GetObjectJSClass(obj);
 }
 
 // Helper to handle torn-down inner windows.
 static inline nsresult
-SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
+SetParentToWindow(nsGlobalWindowInner *win, JSObject **parent)
 {
   MOZ_ASSERT(win);
   MOZ_ASSERT(win->IsInnerWindow());
   *parent = win->FastGetGlobalJSObject();
 
   if (MOZ_UNLIKELY(!*parent)) {
     // The inner window has been torn down. The scope is dying, so don't create
     // any new wrappers.
@@ -719,17 +719,17 @@ nsDOMClassInfo::HasInstance(nsIXPConnect
                             bool *_retval)
 {
   NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!");
 
   return NS_ERROR_UNEXPECTED;
 }
 
 static nsresult
-ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
+ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindowInner *aWin, JSContext *cx,
                  JS::Handle<JSObject*> obj, const char16_t *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
                  JSObject *dot_prototype,
                  JS::MutableHandle<JS::PropertyDescriptor> ctorDesc);
 
 NS_IMETHODIMP
@@ -776,17 +776,17 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
 
   // Make prototype delegation work correctly. Consider if a site sets
   // HTMLElement.prototype.foopy = function () { ... } Now, calling
   // document.body.foopy() needs to ensure that looking up foopy on
   // document.body's prototype will find the right function.
   JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, proto));
 
   // Only do this if the global object is a window.
-  nsGlobalWindow* win;
+  nsGlobalWindowInner* win;
   if (NS_FAILED(UNWRAP_OBJECT(Window, &global, win))) {
     // Not a window.
     return NS_OK;
   }
 
   if (win->IsClosedOrClosing()) {
     return NS_OK;
   }
@@ -798,19 +798,19 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
                                     &contentDefinedProperty)) {
     return NS_ERROR_FAILURE;
   }
 
   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
 
   JS::Rooted<JS::PropertyDescriptor> desc(cx);
-  nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
-                                 mData, nullptr, nameSpaceManager, proto,
-                                 &desc);
+  nsresult rv = ResolvePrototype(sXPConnect, win->AssertInner(), cx, global,
+                                 mData->mNameUTF16, mData, nullptr,
+                                 nameSpaceManager, proto, &desc);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
     desc.attributesRef() |= JSPROP_RESOLVING;
     if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
                              NS_strlen(mData->mNameUTF16), desc)) {
       return NS_ERROR_UNEXPECTED;
     }
   }
@@ -1072,17 +1072,17 @@ nsresult
 nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj)
 {
   nsCOMPtr<nsPIDOMWindowInner> owner(do_QueryReferent(mWeakOwner));
   if (!owner) {
     // Can't do anything.
     return NS_OK;
   }
 
-  nsGlobalWindow *win = nsGlobalWindow::Cast(owner);
+  nsGlobalWindowInner *win = nsGlobalWindowInner::Cast(owner);
   return SetParentToWindow(win, parentObj);
 }
 
 nsresult
 nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                             JS::Handle<JSObject*> obj, const JS::CallArgs &args,
                             bool *_retval)
 {
@@ -1268,17 +1268,17 @@ nsDOMConstructor::ToString(nsAString &aR
   aResult.Append(mClassName);
   aResult.Append(char16_t(']'));
 
   return NS_OK;
 }
 
 
 static nsresult
-GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin,
+GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindowInner *aWin,
             const nsGlobalNameStruct *aNameStruct,
             JS::MutableHandle<JSObject*> aProto)
 {
   NS_ASSERTION(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor,
                "Wrong type!");
 
   int32_t id = aNameStruct->mDOMClassInfoID;
   MOZ_ASSERT(id >= 0, "Negative DOM classinfo?!?");
@@ -1293,17 +1293,17 @@ GetXPCProto(nsIXPConnect *aXPConnect, JS
   NS_ENSURE_SUCCESS(rv, rv);
 
   return JS_WrapObject(cx, aProto) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Either ci_data must be non-null or name_struct must be non-null and of type
 // eTypeClassProto.
 static nsresult
-ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
+ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindowInner *aWin, JSContext *cx,
                  JS::Handle<JSObject*> obj, const char16_t *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
                  JSObject* aDot_prototype,
                  JS::MutableHandle<JS::PropertyDescriptor> ctorDesc)
 {
   JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype);
@@ -1457,17 +1457,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 static bool
 OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
-                             nsGlobalWindow *aWin, JSContext *cx)
+                             nsGlobalWindowInner *aWin, JSContext *cx)
 {
   MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty ||
              aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor);
 
   // Don't expose chrome only constructors to content windows.
   if (aStruct->mChromeOnly) {
     bool expose;
     if (aStruct->mAllowXBL) {
@@ -1486,17 +1486,17 @@ OldBindingConstructorEnabled(const nsGlo
 
 static nsresult
 LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
                      nsPIDOMWindowInner *win,
                      JS::MutableHandle<JS::PropertyDescriptor> desc);
 
 // static
 bool
-nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
+nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindowInner *aWin,
                               const nsAString& aName,
                               const nsGlobalNameStruct& aNameStruct)
 {
   // DOMConstructor is special: creating its proto does not actually define it
   // as a property on the global.  So we don't want to expose its name either.
   if (aName.EqualsLiteral("DOMConstructor")) {
     return false;
   }
@@ -1516,17 +1516,17 @@ static const JSClass ControllersShimClas
 };
 static const JSClass XULControllersShimClass = {
     "XULControllers", 0
 };
 #endif
 
 // static
 nsresult
-nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
+nsWindowSH::GlobalResolve(nsGlobalWindowInner *aWin, JSContext *cx,
                           JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                           JS::MutableHandle<JS::PropertyDescriptor> desc)
 {
   if (id == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
     return LookupComponentsShim(cx, obj, aWin->AsInner(), desc);
   }
 
 #ifdef USE_CONTROLLERS_SHIM
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -16,16 +16,17 @@
 #include "nsIXPConnect.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 struct nsGlobalNameStruct;
 class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 struct nsDOMClassInfoData;
 
 typedef nsIClassInfo* (*nsDOMClassInfoConstructorFnc)
   (nsDOMClassInfoData* aData);
 
 typedef nsresult (*nsDOMConstructorFunc)(nsISupports** aNewObject);
 
@@ -135,23 +136,23 @@ public:
   virtual void PreserveWrapper(nsISupports *aNative) override;
 };
 
 // A place to hang some static methods that we should really consider
 // moving to be nsGlobalWindow member methods.  See bug 1062418.
 class nsWindowSH
 {
 protected:
-  static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
+  static nsresult GlobalResolve(nsGlobalWindowInner *aWin, JSContext *cx,
                                 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                                 JS::MutableHandle<JS::PropertyDescriptor> desc);
 
   friend class nsGlobalWindow;
 public:
-  static bool NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
+  static bool NameStructEnabled(JSContext* aCx, nsGlobalWindowInner *aWin,
                                 const nsAString& aName,
                                 const nsGlobalNameStruct& aNameStruct);
 };
 
 
 // Event handler 'this' translator class, this is called by XPConnect
 // when a "function interface" (nsIDOMEventListener) is called, this
 // class extracts 'this' fomr the first argument to the called
--- a/dom/base/nsDOMMutationObserver.h
+++ b/dom/base/nsDOMMutationObserver.h
@@ -621,17 +621,17 @@ protected:
   void ScheduleForRun();
   void RescheduleForRun();
 
   nsDOMMutationRecord* CurrentRecord(nsAtom* aType);
   bool HasCurrentRecord(const nsAString& aType);
 
   bool Suppressed()
   {
-    return mOwner && nsGlobalWindow::Cast(mOwner)->IsInSyncOperation();
+    return mOwner && nsGlobalWindowInner::Cast(mOwner)->IsInSyncOperation();
   }
 
   static void HandleMutationsInternal(mozilla::AutoSlowOperation& aAso);
 
   static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
                                            uint32_t aMutationLevel);
 
   nsCOMPtr<nsPIDOMWindowInner>                       mOwner;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -203,17 +203,17 @@ NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsDOMWindowUtils)
 NS_IMPL_RELEASE(nsDOMWindowUtils)
 
-nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindow *aWindow)
+nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter *aWindow)
 {
   nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
   mWindow = do_GetWeakReference(supports);
   NS_ASSERTION(aWindow->IsOuterWindow(), "How did that happen?");
 }
 
 nsDOMWindowUtils::~nsDOMWindowUtils()
 {
@@ -2352,17 +2352,17 @@ nsDOMWindowUtils::LeaveModalState()
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::IsInModalState(bool *retval)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
-  *retval = nsGlobalWindow::Cast(window)->IsInModalState();
+  *retval = nsGlobalWindowOuter::Cast(window)->IsInModalState();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetDesktopModeViewport(bool aDesktopMode)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
@@ -2384,18 +2384,18 @@ nsDOMWindowUtils::GetOuterWindowID(uint6
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetCurrentInnerWindowID(uint64_t *aWindowID)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
 
   NS_ASSERTION(window->IsOuterWindow(), "How did that happen?");
-  nsGlobalWindow* inner =
-    nsGlobalWindow::Cast(window)->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* inner =
+    nsGlobalWindowOuter::Cast(window)->GetCurrentInnerWindowInternal();
   if (!inner) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aWindowID = inner->WindowID();
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3263,37 +3263,37 @@ nsDOMWindowUtils::NumberOfAssignedPainte
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::EnableDialogs()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  nsGlobalWindow::Cast(window)->EnableDialogs();
+  nsGlobalWindowOuter::Cast(window)->EnableDialogs();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::DisableDialogs()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  nsGlobalWindow::Cast(window)->DisableDialogs();
+  nsGlobalWindowOuter::Cast(window)->DisableDialogs();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::AreDialogsEnabled(bool* aResult)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  *aResult = nsGlobalWindow::Cast(window)->AreDialogsEnabled();
+  *aResult = nsGlobalWindowOuter::Cast(window)->AreDialogsEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
                             int64_t* _retval)
 {
   if (aFile.isPrimitive()) {
@@ -3791,17 +3791,17 @@ nsDOMWindowUtils::GetMillisSinceLastUser
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::AllowScriptsToClose()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
-  nsGlobalWindow::Cast(window)->AllowScriptsToClose();
+  nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible)
 {
   // this should reflect the "is parent window visible" logic in
   // nsWindowWatcher::OpenWindowInternal()
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -8,17 +8,17 @@
 #define nsDOMWindowUtils_h_
 
 #include "nsWeakReference.h"
 
 #include "nsIDOMWindowUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasicEvents.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowOuter;
 class nsIPresShell;
 class nsIWidget;
 class nsPresContext;
 class nsIDocument;
 class nsView;
 struct nsPoint;
 
 namespace mozilla {
@@ -57,17 +57,17 @@ private:
 };
 
 class nsDOMWindowUtils final : public nsIDOMWindowUtils,
                                public nsSupportsWeakReference
 {
   typedef mozilla::widget::TextEventDispatcher
     TextEventDispatcher;
 public:
-  explicit nsDOMWindowUtils(nsGlobalWindow *aWindow);
+  explicit nsDOMWindowUtils(nsGlobalWindowOuter *aWindow);
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMWINDOWUTILS
 
 protected:
   ~nsDOMWindowUtils();
 
   nsWeakPtr mWindow;
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -86,17 +86,16 @@
 #include "nsIServiceManager.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "imgLoader.h"
 
 #include "nsCanvasFrame.h"
 #include "nsContentCID.h"
 #include "nsError.h"
 #include "nsPresContext.h"
-#include "nsIJSON.h"
 #include "nsThreadUtils.h"
 #include "nsNodeInfoManager.h"
 #include "nsIFileChannel.h"
 #include "nsIMultiPartChannel.h"
 #include "nsIRefreshURI.h"
 #include "nsIWebNavigation.h"
 #include "nsIScriptError.h"
 #include "nsISimpleEnumerator.h"
@@ -2485,17 +2484,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
       if (NS_SUCCEEDED(rv)) {
         SetPrincipal(principal);
       }
     }
   }
 
   // Refresh the principal on the compartment.
   if (nsPIDOMWindowInner* win = GetInnerWindow()) {
-    nsGlobalWindow::Cast(win)->RefreshCompartmentPrincipal();
+    nsGlobalWindowInner::Cast(win)->RefreshCompartmentPrincipal();
   }
 }
 
 already_AddRefed<nsIPrincipal>
 nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
 {
   if (!aPrincipal) {
     return nullptr;
@@ -6373,17 +6372,17 @@ nsIDocument::CreateAttributeNS(const nsA
 
 bool
 nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
 
   JS::Rooted<JSObject*> global(aCx,
     JS_GetGlobalForObject(aCx, &args.callee()));
-  RefPtr<nsGlobalWindow> window;
+  RefPtr<nsGlobalWindowInner> window;
   UNWRAP_OBJECT(Window, global, window);
   MOZ_ASSERT(window, "Should have a non-null window");
 
   nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
 
   // Function name is the type of the custom element.
   JSString* jsFunName =
     JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
@@ -7196,17 +7195,17 @@ already_AddRefed<Location>
 nsIDocument::GetLocation() const
 {
   nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(mScriptGlobalObject);
 
   if (!w) {
     return nullptr;
   }
 
-  nsGlobalWindow* window = nsGlobalWindow::Cast(w);
+  nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(w);
   RefPtr<Location> loc = window->GetLocation();
   return loc.forget();
 }
 
 Element*
 nsIDocument::GetHtmlElement() const
 {
   Element* rootElement = GetRootElement();
@@ -8465,17 +8464,17 @@ nsDocument::GetEventTargetParent(EventCh
 
   aVisitor.mCanHandle = true;
    // FIXME! This is a hack to make middle mouse paste working also in Editor.
    // Bug 329119
   aVisitor.mForceContentDispatch = true;
 
   // Load events must not propagate to |window| object, see bug 335251.
   if (aVisitor.mEvent->mMessage != eLoad) {
-    nsGlobalWindow* window = nsGlobalWindow::Cast(GetWindow());
+    nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(GetWindow());
     aVisitor.mParentTarget =
       window ? window->GetTargetForEventTargetChain() : nullptr;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
@@ -9153,17 +9152,17 @@ nsDocument::CanSavePresentation(nsIReque
       if (!canCache) {
         return false;
       }
     }
   }
 
 
   if (win) {
-    auto* globalWindow = nsGlobalWindow::Cast(win);
+    auto* globalWindow = nsGlobalWindowInner::Cast(win);
 #ifdef MOZ_WEBSPEECH
     if (globalWindow->HasActiveSpeechSynthesis()) {
       return false;
     }
 #endif
     if (globalWindow->HasUsedVR()) {
       return false;
     }
@@ -10881,17 +10880,17 @@ nsDocument::NotifyMediaFeatureValuesChan
     if (content->IsHTMLElement(nsGkAtoms::img)) {
       auto* imageElement = static_cast<HTMLImageElement*>(content.get());
       imageElement->MediaFeatureValuesChanged();
     }
   }
 }
 
 already_AddRefed<Touch>
-nsIDocument::CreateTouch(nsGlobalWindow* aView,
+nsIDocument::CreateTouch(nsGlobalWindowInner* aView,
                          EventTarget* aTarget,
                          int32_t aIdentifier,
                          int32_t aPageX, int32_t aPageY,
                          int32_t aScreenX, int32_t aScreenY,
                          int32_t aClientX, int32_t aClientY,
                          int32_t aRadiusX, int32_t aRadiusY,
                          float aRotationAngle,
                          float aForce)
@@ -14317,17 +14316,17 @@ nsIDocument::GetSelection(ErrorResult& a
     return nullptr;
   }
 
   NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
   if (!window->IsCurrentInnerWindow()) {
     return nullptr;
   }
 
-  return nsGlobalWindow::Cast(window)->GetSelection(aRv);
+  return nsGlobalWindowInner::Cast(window)->GetSelection(aRv);
 }
 
 void
 nsDocument::RecordNavigationTiming(ReadyState aReadyState)
 {
   if (!XRE_IsContentProcess()) {
     return;
   }
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -1597,17 +1597,17 @@ nsFrameLoader::SwapWithOtherRemoteLoader
   }
 
   aOther->mRemoteBrowser->SetBrowserDOMWindow(browserDOMWindow);
   mRemoteBrowser->SetBrowserDOMWindow(otherBrowserDOMWindow);
 
 #ifdef XP_WIN
   // Native plugin windows used by this remote content need to be reparented.
   if (nsPIDOMWindowOuter* newWin = ourDoc->GetWindow()) {
-    RefPtr<nsIWidget> newParent = nsGlobalWindow::Cast(newWin)->GetMainWidget();
+    RefPtr<nsIWidget> newParent = nsGlobalWindowOuter::Cast(newWin)->GetMainWidget();
     const ManagedContainer<mozilla::plugins::PPluginWidgetParent>& plugins =
       aOther->mRemoteBrowser->ManagedPPluginWidgetParent();
     for (auto iter = plugins.ConstIter(); !iter.Done(); iter.Next()) {
       static_cast<mozilla::plugins::PluginWidgetParent*>(iter.Get()->GetKey())->SetParent(newParent);
     }
   }
 #endif // XP_WIN
 
@@ -3835,18 +3835,18 @@ nsFrameLoader::Print(uint64_t aOuterWind
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     bool success = mRemoteBrowser->SendPrint(aOuterWindowID, printData);
     return success ? NS_OK : NS_ERROR_FAILURE;
   }
 
-  nsGlobalWindow* outerWindow =
-    nsGlobalWindow::GetOuterWindowWithId(aOuterWindowID);
+  nsGlobalWindowOuter* outerWindow =
+    nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowID);
   if (NS_WARN_IF(!outerWindow)) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
     do_GetInterface(outerWindow->AsOuter());
   if (NS_WARN_IF(!webBrowserPrint)) {
     return NS_ERROR_FAILURE;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -283,17 +283,18 @@ using namespace mozilla::dom::ipc;
 using mozilla::BasePrincipal;
 using mozilla::OriginAttributes;
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 using mozilla::dom::cache::CacheStorage;
 
 static LazyLogModule gDOMLeakPRLog("DOMLeak");
 
-nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
+nsGlobalWindowInner::InnerWindowByIdTable *nsGlobalWindowInner::sInnerWindowsById = nullptr;
+nsGlobalWindowOuter::OuterWindowByIdTable *nsGlobalWindowOuter::sOuterWindowsById = nullptr;
 bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
 
 static int32_t              gRefCnt                    = 0;
 static int32_t              gOpenPopupSpamCount        = 0;
 static PopupControlState    gPopupControlState         = openAbused;
 static bool                 gMouseDown                 = false;
 static bool                 gDragServiceDisabled       = false;
 static FILE                *gDumpFile                  = nullptr;
@@ -886,17 +887,17 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler,
                                            TimeoutHandler)
 
   nsresult Call() override
   {
-    return nsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true);
+    return nsGlobalWindowInner::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true);
   }
 
 private:
   ~IdleRequestTimeoutHandler() override {}
 
   RefPtr<IdleRequest> mIdleRequest;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 };
@@ -1011,17 +1012,17 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMW
   mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
   mLargeAllocStatus(LargeAllocStatus::NONE),
   mHasTriedToCacheTopInnerWindow(false),
   mNumOfIndexedDBDatabases(0),
   mNumOfOpenWebSockets(0)
 {
   if (aOuterWindow) {
     mTimeoutManager =
-      MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindow::Cast(AsInner()));
+      MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindowInner::Cast(AsInner()));
   }
 }
 
 template<class T>
 nsPIDOMWindow<T>::~nsPIDOMWindow() {}
 
 /* static */
 nsPIDOMWindowOuter*
@@ -1421,17 +1422,17 @@ nsOuterWindowProxy::GetSubframeWindow(JS
   nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id);
   if (!frame) {
     found = false;
     return true;
   }
 
   found = true;
   // Just return the window's global
-  nsGlobalWindow* global = nsGlobalWindow::Cast(frame);
+  nsGlobalWindowOuter* global = nsGlobalWindowOuter::Cast(frame);
   frame->EnsureInnerWindow();
   JSObject* obj = global->FastGetGlobalJSObject();
   // This null check fixes a hard-to-reproduce crash that occurs when we
   // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
   // comment 105.
   if (MOZ_UNLIKELY(!obj)) {
     return xpc::Throw(cx, NS_ERROR_FAILURE);
   }
@@ -1667,24 +1668,16 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
                   getpid(),
                   gSerialCounter,
                   static_cast<void*>(ToCanonicalSupports(aOuterWindow)));
   }
 #endif
 
   MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
           ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
-
-  NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
-  NS_ASSERTION(!sWindowsById->Get(mWindowID),
-               "This window shouldn't be in the hash table yet!");
-  // We seem to see crashes in release builds because of null |sWindowsById|.
-  if (sWindowsById) {
-    sWindowsById->Put(mWindowID, this);
-  }
 }
 
 #ifdef DEBUG
 
 /* static */
 void
 nsGlobalWindow::AssertIsOnMainThread()
 {
@@ -1696,17 +1689,20 @@ nsGlobalWindow::AssertIsOnMainThread()
 /* static */
 void
 nsGlobalWindow::Init()
 {
   AssertIsOnMainThread();
 
   NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
 
-  sWindowsById = new WindowByIdTable();
+  nsGlobalWindowOuter::sOuterWindowsById =
+    new nsGlobalWindowOuter::OuterWindowByIdTable();
+  nsGlobalWindowInner::sInnerWindowsById =
+    new nsGlobalWindowInner::InnerWindowByIdTable();
 }
 
 nsGlobalWindow::~nsGlobalWindow()
 {
   AssertIsOnMainThread();
 
   if (IsChromeWindow()) {
     MOZ_ASSERT(mCleanMessageManager,
@@ -1719,22 +1715,28 @@ nsGlobalWindow::~nsGlobalWindow()
         mChromeFields.mMessageManager.get())->Disconnect();
     }
 
     mCleanMessageManager = false;
   }
 
   DisconnectEventTargetObjects();
 
-  // We have to check if sWindowsById isn't null because ::Shutdown might have
-  // been called.
-  if (sWindowsById) {
-    NS_ASSERTION(sWindowsById->Get(mWindowID),
+  if (IsOuterWindow()) {
+    if (nsGlobalWindowOuter::sOuterWindowsById) {
+      MOZ_ASSERT(nsGlobalWindowOuter::sOuterWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
-    sWindowsById->Remove(mWindowID);
+      nsGlobalWindowOuter::sOuterWindowsById->Remove(mWindowID);
+    }
+  } else {
+    if (nsGlobalWindowInner::sInnerWindowsById) {
+      MOZ_ASSERT(nsGlobalWindowInner::sInnerWindowsById->Get(mWindowID),
+                 "This window should be in the hash table");
+      nsGlobalWindowInner::sInnerWindowsById->Remove(mWindowID);
+    }
   }
 
   --gRefCnt;
 
 #ifdef DEBUG
   if (!PR_GetEnv("MOZ_QUIET")) {
     nsAutoCString url;
     if (mLastOpenedURI) {
@@ -1742,17 +1744,17 @@ nsGlobalWindow::~nsGlobalWindow()
 
       // Data URLs can be very long, so truncate to avoid flooding the log.
       const uint32_t maxURLLength = 1000;
       if (url.Length() > maxURLLength) {
         url.Truncate(maxURLLength);
       }
     }
 
-    nsGlobalWindow* outer = nsGlobalWindow::Cast(mOuterWindow);
+    nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow);
     printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
                   gRefCnt,
                   static_cast<void*>(ToCanonicalSupports(this)),
                   getpid(),
                   mSerial,
                   static_cast<void*>(ToCanonicalSupports(outer)),
                   url.get());
   }
@@ -1853,18 +1855,20 @@ nsGlobalWindow::ShutDown()
 {
   AssertIsOnMainThread();
 
   if (gDumpFile && gDumpFile != stdout) {
     fclose(gDumpFile);
   }
   gDumpFile = nullptr;
 
-  delete sWindowsById;
-  sWindowsById = nullptr;
+  delete nsGlobalWindowInner::sInnerWindowsById;
+  nsGlobalWindowInner::sInnerWindowsById = nullptr;
+  delete nsGlobalWindowOuter::sOuterWindowsById;
+  nsGlobalWindowOuter::sOuterWindowsById = nullptr;
 }
 
 // static
 void
 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
 {
   if (aWindow->mCachedXBLPrototypeHandlers &&
       aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
@@ -2059,17 +2063,17 @@ nsGlobalWindow::FreeInnerObjects()
 {
   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
 
   // Make sure that this is called before we null out the document and
   // other members that the window destroyed observers could
   // re-create.
   NotifyDOMWindowDestroyed(this);
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
-    reporter->ObserveDOMWindowDetached(this);
+    reporter->ObserveDOMWindowDetached(AssertInner());
   }
 
   mInnerObjectsFreed = true;
 
   // Kill all of the workers for this window.
   mozilla::dom::workers::CancelWorkersForWindow(AsInner());
 
   if (mTimeoutManager) {
@@ -2349,17 +2353,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerRegistrationTable)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
 #endif
 
   if (tmp->mOuterWindow) {
-    nsGlobalWindow::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
+    nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
   }
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
   }
 
@@ -2786,35 +2790,35 @@ nsGlobalWindow::ComputeIsSecureContext(n
 
   // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
   // With some modifications to allow for aFlags.
 
   bool hadNonSecureContextCreator = false;
 
   nsPIDOMWindowOuter* parentOuterWin = GetScriptableParent();
   MOZ_ASSERT(parentOuterWin, "How can we get here? No docShell somehow?");
-  if (nsGlobalWindow::Cast(parentOuterWin) != this) {
+  if (nsGlobalWindowOuter::Cast(parentOuterWin) != this) {
     // There may be a small chance that parentOuterWin has navigated in
     // the time that it took us to start loading this sub-document.  If that
     // were the case then parentOuterWin->GetCurrentInnerWindow() wouldn't
     // return the window for the document that is embedding us.  For this
     // reason we only use the GetScriptableParent call above to check that we
     // have a same-type parent, but actually get the inner window via the
     // document that we know is embedding us.
     nsIDocument* creatorDoc = aDocument->GetParentDocument();
     if (!creatorDoc) {
       return false; // we must be tearing down
     }
-    nsGlobalWindow* parentWin =
-      nsGlobalWindow::Cast(creatorDoc->GetInnerWindow());
+    nsGlobalWindowInner* parentWin =
+      nsGlobalWindowInner::Cast(creatorDoc->GetInnerWindow());
     if (!parentWin) {
       return false; // we must be tearing down
     }
     MOZ_ASSERT(parentWin ==
-               nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()),
+               nsGlobalWindowInner::Cast(parentOuterWin->GetCurrentInnerWindow()),
                "Creator window mismatch while setting Secure Context state");
     if (aFlags != SecureContextFlags::eIgnoreOpener) {
       hadNonSecureContextCreator = !parentWin->IsSecureContext();
     } else {
       hadNonSecureContextCreator = !parentWin->IsSecureContextIfOpenerIgnored();
     }
   } else if (mHadOriginalOpener) {
     if (aFlags != SecureContextFlags::eIgnoreOpener) {
@@ -2877,33 +2881,33 @@ SelectZoneGroup(nsGlobalWindow* aNewInne
   if (XRE_IsParentProcess()) {
     return aOptions.setNewZoneInSystemZoneGroup();
   }
 
   // Otherwise, find a zone group from the TabGroup. Typically we only have to
   // go through one iteration of this loop.
   RefPtr<TabGroup> tabGroup = aNewInner->TabGroup();
   for (nsPIDOMWindowOuter* outer : tabGroup->GetWindows()) {
-    nsGlobalWindow* window = nsGlobalWindow::Cast(outer);
+    nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(outer);
     if (JSObject* global = window->GetGlobalJSObject()) {
       return aOptions.setNewZoneInExistingZoneGroup(global);
     }
   }
 
   return aOptions.setNewZoneInNewZoneGroup();
 }
 
 /**
  * Create a new global object that will be used for an inner window.
  * Return the native global and an nsISupports 'holder' that can be used
  * to manage the lifetime of it.
  */
 static nsresult
 CreateNativeGlobalForInner(JSContext* aCx,
-                           nsGlobalWindow* aNewInner,
+                           nsGlobalWindowInner* aNewInner,
                            nsIURI* aURI,
                            nsIPrincipal* aPrincipal,
                            JS::MutableHandle<JSObject*> aGlobal,
                            bool aIsSecureContext)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aNewInner);
   MOZ_ASSERT(aNewInner->IsInnerWindow());
@@ -3133,17 +3137,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       // and proto, which makes the JS engine look up classes in
       // cx->globalObject, i.e. this outer window].
 
       mInnerWindow = nullptr;
 
       mCreatingInnerWindow = true;
       // Every script context we are initialized with must create a
       // new global.
-      rv = CreateNativeGlobalForInner(cx, newInnerWindow,
+      rv = CreateNativeGlobalForInner(cx, newInnerWindow->AssertInner(),
                                       aDocument->GetDocumentURI(),
                                       aDocument->NodePrincipal(),
                                       &newInnerGlobal,
                                       ComputeIsSecureContext(aDocument));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
                    newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
                    "Failed to get script global");
       newInnerWindow->mIsSecureContextIfOpenerIgnored =
@@ -3484,17 +3488,18 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
 
   if (aDocShell == mDocShell) {
     return;
   }
 
   mDocShell = aDocShell; // Weak Reference
 
   nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull();
-  MOZ_RELEASE_ASSERT(!parentWindow || !mTabGroup || mTabGroup == Cast(parentWindow)->mTabGroup);
+  MOZ_RELEASE_ASSERT(!parentWindow || !mTabGroup ||
+                     mTabGroup == nsGlobalWindowOuter::Cast(parentWindow)->mTabGroup);
 
   mTopLevelOuterContentWindow =
     !mIsChrome && GetScriptableTopInternal() == this;
 
   NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
 
   if (mFrames) {
     mFrames->SetDocShell(aDocShell);
@@ -3542,19 +3547,18 @@ nsGlobalWindow::DetachFromDocShell()
   // are GC-owned.
   for (RefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
        inner != this;
        inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
     MOZ_ASSERT(!inner->mOuterWindow || inner->mOuterWindow == AsOuter());
     inner->FreeInnerObjects();
   }
 
-  if (auto* reporter = nsWindowMemoryReporter::Get()) {
-    reporter->ObserveDOMWindowDetached(this);
-  }
+  // Don't report that we were detached to the nsWindowMemoryReporter, as it
+  // only tracks inner windows.
 
   NotifyWindowIDDestroyed("outer-window-destroyed");
 
   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
 
   if (currentInner) {
     NS_ASSERTION(mDoc, "Must have doc!");
 
@@ -3617,17 +3621,17 @@ nsGlobalWindow::SetOpenerWindow(nsPIDOMW
   // Check that the js visible opener matches! We currently don't depend on this
   // being true outside of nightly, so we disable the assertion in optimized
   // release / beta builds.
   nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener);
 
   // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.
   mozilla::Unused << contentOpener;
   MOZ_DIAGNOSTIC_ASSERT(!contentOpener || !mTabGroup ||
-    mTabGroup == Cast(contentOpener)->mTabGroup);
+    mTabGroup == nsGlobalWindowOuter::Cast(contentOpener)->mTabGroup);
 
   if (aOriginalOpener) {
     MOZ_ASSERT(!mHadOriginalOpener,
                "Probably too late to call ComputeIsSecureContext again");
     mHadOriginalOpener = true;
     mOriginalOpenerWasSecureContext =
       aOpener->GetCurrentInnerWindow()->IsSecureContext();
   }
@@ -4198,26 +4202,26 @@ nsPIDOMWindowInner::UnmuteAudioContexts(
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     if (!mAudioContexts[i]->IsOffline()) {
       mAudioContexts[i]->Unmute();
     }
   }
 }
 
-nsGlobalWindow*
+nsGlobalWindowInner*
 nsGlobalWindow::Window()
 {
-  return this;
-}
-
-nsGlobalWindow*
+  return AssertInner();
+}
+
+nsGlobalWindowInner*
 nsGlobalWindow::Self()
 {
-  return this;
+  return AssertInner();
 }
 
 Navigator*
 nsGlobalWindow::Navigator()
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mNavigator) {
@@ -4319,53 +4323,53 @@ nsPIDOMWindowInner::CreatePerformanceObj
   if (timing) {
     mPerformance = Performance::CreateForMainThread(this, timing, timedChannel);
   }
 }
 
 bool
 nsPIDOMWindowInner::IsSecureContext() const
 {
-  return nsGlobalWindow::Cast(this)->IsSecureContext();
+  return nsGlobalWindowInner::Cast(this)->IsSecureContext();
 }
 
 bool
 nsPIDOMWindowInner::IsSecureContextIfOpenerIgnored() const
 {
-  return nsGlobalWindow::Cast(this)->IsSecureContextIfOpenerIgnored();
+  return nsGlobalWindowInner::Cast(this)->IsSecureContextIfOpenerIgnored();
 }
 
 void
 nsPIDOMWindowInner::Suspend()
 {
-  nsGlobalWindow::Cast(this)->Suspend();
+  nsGlobalWindowInner::Cast(this)->Suspend();
 }
 
 void
 nsPIDOMWindowInner::Resume()
 {
-  nsGlobalWindow::Cast(this)->Resume();
+  nsGlobalWindowInner::Cast(this)->Resume();
 }
 
 void
 nsPIDOMWindowInner::Freeze()
 {
-  nsGlobalWindow::Cast(this)->Freeze();
+  nsGlobalWindowInner::Cast(this)->Freeze();
 }
 
 void
 nsPIDOMWindowInner::Thaw()
 {
-  nsGlobalWindow::Cast(this)->Thaw();
+  nsGlobalWindowInner::Cast(this)->Thaw();
 }
 
 void
 nsPIDOMWindowInner::SyncStateFromParentWindow()
 {
-  nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();
+  nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow();
 }
 
 void
 nsGlobalWindow::UpdateTopInnerWindow()
 {
   if (!IsInnerWindow() || AsInner()->IsTopInnerWindow() || !mTopInnerWindow) {
     return;
   }
@@ -4448,17 +4452,17 @@ nsPIDOMWindowInner::TryToCacheTopInnerWi
   if (mHasTriedToCacheTopInnerWindow) {
     return;
   }
 
   MOZ_ASSERT(!mInnerObjectsFreed);
 
   mHasTriedToCacheTopInnerWindow = true;
 
-  nsGlobalWindow* window = nsGlobalWindow::Cast(AsInner());
+  nsGlobalWindow* window = nsGlobalWindowInner::Cast(AsInner());
 
   MOZ_ASSERT(window);
 
   if (nsCOMPtr<nsPIDOMWindowOuter> topOutter = window->GetScriptableTop()) {
     mTopInnerWindow = topOutter->GetCurrentInnerWindow();
   }
 }
 
@@ -4790,17 +4794,17 @@ nsGlobalWindow::GetScriptableParent()
  * if GetScriptableParent would return this window.
  */
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetScriptableParentOrNull()
 {
   FORWARD_TO_OUTER(GetScriptableParentOrNull, (), nullptr);
 
   nsPIDOMWindowOuter* parent = GetScriptableParent();
-  return (Cast(parent) == this) ? nullptr : parent;
+  return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
 }
 
 /**
  * nsPIDOMWindow::GetParent (when called from C++) is just a wrapper around
  * GetRealParent.
  */
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindow::GetParent()
@@ -5018,74 +5022,74 @@ nsGlobalWindow::GetPrompter(nsIPrompt** 
 }
 
 BarProp*
 nsGlobalWindow::GetMenubar(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mMenubar) {
-    mMenubar = new MenubarProp(this);
+    mMenubar = new MenubarProp(AssertInner());
   }
 
   return mMenubar;
 }
 
 BarProp*
 nsGlobalWindow::GetToolbar(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mToolbar) {
-    mToolbar = new ToolbarProp(this);
+    mToolbar = new ToolbarProp(AssertInner());
   }
 
   return mToolbar;
 }
 
 BarProp*
 nsGlobalWindow::GetLocationbar(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mLocationbar) {
-    mLocationbar = new LocationbarProp(this);
+    mLocationbar = new LocationbarProp(AssertInner());
   }
   return mLocationbar;
 }
 
 BarProp*
 nsGlobalWindow::GetPersonalbar(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mPersonalbar) {
-    mPersonalbar = new PersonalbarProp(this);
+    mPersonalbar = new PersonalbarProp(AssertInner());
   }
   return mPersonalbar;
 }
 
 BarProp*
 nsGlobalWindow::GetStatusbar(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mStatusbar) {
-    mStatusbar = new StatusbarProp(this);
+    mStatusbar = new StatusbarProp(AssertInner());
   }
   return mStatusbar;
 }
 
 BarProp*
 nsGlobalWindow::GetScrollbars(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mScrollbars) {
-    mScrollbars = new ScrollbarsProp(this);
+    mScrollbars = new ScrollbarsProp(AssertInner());
   }
 
   return mScrollbars;
 }
 
 bool
 nsGlobalWindow::GetClosedOuter()
 {
@@ -5166,17 +5170,17 @@ nsGlobalWindow::DoResolve(JSContext* aCx
   if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
     return false;
   }
 
   if (found) {
     return true;
   }
 
-  nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
+  nsresult rv = nsWindowSH::GlobalResolve(AssertInner(), aCx, aObj, aId, aDesc);
   if (NS_FAILED(rv)) {
     return Throw(aCx, rv);
   }
 
   return true;
 }
 
 /* static */
@@ -5257,17 +5261,17 @@ nsGlobalWindow::GetOwnPropertyNames(JSCo
         WebIDLGlobalNameHash::UnresolvedNamesOnly :
         WebIDLGlobalNameHash::AllNames;
     if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) {
       aRv.NoteJSContextException(aCx);
     }
 
     for (auto i = nameSpaceManager->GlobalNameIter(); !i.Done(); i.Next()) {
       const GlobalNameMapEntry* entry = i.Get();
-      if (nsWindowSH::NameStructEnabled(aCx, this, entry->mKey,
+      if (nsWindowSH::NameStructEnabled(aCx, AssertInner(), entry->mKey,
                                         entry->mGlobalName)) {
         // Just append all of these; even if they get deleted our resolve hook
         // just goes ahead and recreates them.
         JSString* str = JS_AtomizeUCStringN(aCx,
                                             entry->mKey.BeginReading(),
                                             entry->mKey.Length());
         if (!str || !aNames.append(NON_INTEGER_ATOM_TO_JSID(str))) {
           aRv.NoteJSContextException(aCx);
@@ -5422,17 +5426,17 @@ nsGlobalWindow::GetControllers(nsIContro
 
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetSanitizedOpener(nsPIDOMWindowOuter* aOpener)
 {
   if (!aOpener) {
     return nullptr;
   }
 
-  nsGlobalWindow* win = nsGlobalWindow::Cast(aOpener);
+  nsGlobalWindow* win = nsGlobalWindowOuter::Cast(aOpener);
 
   // First, ensure that we're not handing back a chrome window to content:
   if (win->IsChromeWindow()) {
     return nullptr;
   }
 
   // We don't want to reveal the opener if the opener is a mail window,
   // because opener can be used to spoof the contents of a message (bug 105050).
@@ -5465,17 +5469,17 @@ nsGlobalWindow::GetOpenerWindowOuter()
   if (!opener) {
     return nullptr;
   }
 
   // First, check if we were called from a privileged chrome script
   if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     // Catch the case where we're chrome but the opener is not...
     if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
-        nsGlobalWindow::Cast(opener)->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
+        nsGlobalWindowOuter::Cast(opener)->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
       return nullptr;
     }
     return opener;
   }
 
   return GetSanitizedOpener(opener);
 }
 
@@ -6264,17 +6268,17 @@ double
 nsGlobalWindow::GetDevicePixelRatio(CallerType aCallerType, ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatioOuter, (aCallerType), aError, 0.0);
 }
 
 float
 nsPIDOMWindowOuter::GetDevicePixelRatio(CallerType aCallerType)
 {
-  return nsGlobalWindow::Cast(this)->GetDevicePixelRatioOuter(aCallerType);
+  return nsGlobalWindowOuter::Cast(this)->GetDevicePixelRatioOuter(aCallerType);
 }
 
 uint64_t
 nsGlobalWindow::GetMozPaintCountOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   if (!mDocShell) {
@@ -6537,17 +6541,17 @@ nsGlobalWindow::CheckSecurityLeftAndTop(
   // Check security state for use in determing window dimensions
 
   if (aCallerType != CallerType::System) {
 #ifdef MOZ_XUL
     // if attempting to move the window, hide any open popups
     nsContentUtils::HidePopupsInDocument(mDoc);
 #endif
 
-    if (nsGlobalWindow* rootWindow = nsGlobalWindow::Cast(GetPrivateRoot())) {
+    if (nsGlobalWindowOuter* rootWindow = nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
       rootWindow->FlushPendingNotifications(FlushType::Layout);
     }
 
     nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
 
     nsCOMPtr<nsIDOMScreen> screen = GetScreen();
 
     if (treeOwner && screen) {
@@ -7107,17 +7111,17 @@ NS_IMETHODIMP
 FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
                                             const char* aTopic,
                                             const char16_t* aData)
 {
   bool shouldContinue = false;
   if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
     nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
     nsCOMPtr<nsIWidget> widget = win ?
-      nsGlobalWindow::Cast(win)->GetMainWidget() : nullptr;
+      nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
     if (widget == mTask->mWidget) {
       // The paint notification arrives first. Cancel the timer.
       mTask->mTimer->Cancel();
       shouldContinue = true;
       PROFILER_ADD_MARKER("Fullscreen toggle end");
     }
   } else {
 #ifdef DEBUG
@@ -7390,17 +7394,17 @@ nsGlobalWindow::FullScreen() const
       return widget->SizeMode() == nsSizeMode_Fullscreen;
     }
     return false;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
   NS_ENSURE_TRUE(window, mFullScreen);
 
-  return nsGlobalWindow::Cast(window)->FullScreen();
+  return nsGlobalWindowOuter::Cast(window)->FullScreen();
 }
 
 bool
 nsGlobalWindow::GetFullScreenOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   return FullScreen();
 }
@@ -8781,24 +8785,27 @@ bool IsPopupBlocked(nsIDocument* aDoc)
 }
 
 void
 nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
                                       nsIURI* aPopupURI,
                                       const nsAString& aPopupWindowName,
                                       const nsAString& aPopupWindowFeatures)
 {
+  MOZ_ASSERT(IsOuterWindow(), "All callers seem to assume we're an outer window?");
   MOZ_ASSERT(aDoc);
 
   // Fire a "DOMPopupBlocked" event so that the UI can hear about
   // blocked popups.
   PopupBlockedEventInit init;
   init.mBubbles = true;
   init.mCancelable = true;
-  init.mRequestingWindow = this;
+  // XXX: This is a different object, but webidl requires an inner window here
+  // now.
+  init.mRequestingWindow = GetCurrentInnerWindowInternal();
   init.mPopupWindowURI = aPopupURI;
   init.mPopupWindowName = aPopupWindowName;
   init.mPopupWindowFeatures = aPopupWindowFeatures;
 
   RefPtr<PopupBlockedEvent> event =
     PopupBlockedEvent::Constructor(aDoc,
                                    NS_LITERAL_STRING("DOMPopupBlocked"),
                                    init);
@@ -8830,17 +8837,17 @@ nsGlobalWindow::PopupWhitelisted()
     return true;
 
   nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
   if (parent == AsOuter())
   {
     return false;
   }
 
-  return nsGlobalWindow::Cast(parent)->PopupWhitelisted();
+  return nsGlobalWindowOuter::Cast(parent)->PopupWhitelisted();
 }
 
 /*
  * Examine the current document state to see if we're in a way that is
  * typically abused by web designers. The window.open code uses this
  * routine to determine whether to allow the new window.
  * Returns a value from the PopupControlState enum.
  */
@@ -8886,16 +8893,17 @@ nsGlobalWindow::RevisePopupAbuseLevel(Po
 }
 
 /* If a window open is blocked, fire the appropriate DOM events. */
 void
 nsGlobalWindow::FireAbuseEvents(const nsAString &aPopupURL,
                                 const nsAString &aPopupWindowName,
                                 const nsAString &aPopupWindowFeatures)
 {
+  MOZ_ASSERT(IsOuterWindow());
   // fetch the URI of the window requesting the opened window
 
   nsCOMPtr<nsPIDOMWindowOuter> window = GetTop();
   if (!window) {
     return;
   }
 
   nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
@@ -9071,17 +9079,17 @@ nsGlobalWindow::GetFramesOuter()
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindow::GetFrames(ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetFramesOuter, (), aError, nullptr);
 }
 
-nsGlobalWindow*
+nsGlobalWindowInner*
 nsGlobalWindow::CallerInnerWindow()
 {
   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   NS_ENSURE_TRUE(cx, nullptr);
   nsIGlobalObject* global = GetIncumbentGlobal();
   NS_ENSURE_TRUE(global, nullptr);
   JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
   NS_ENSURE_TRUE(scope, nullptr);
@@ -9103,17 +9111,17 @@ nsGlobalWindow::CallerInnerWindow()
       global = xpc::NativeGlobal(scopeProto);
       NS_ENSURE_TRUE(global, nullptr);
     }
   }
 
   // The calling window must be holding a reference, so we can return a weak
   // pointer.
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
-  return nsGlobalWindow::Cast(win);
+  return nsGlobalWindowInner::Cast(win);
 }
 
 void
 nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                                     const nsAString& aTargetOrigin,
                                     JS::Handle<JS::Value> aTransfer,
                                     nsIPrincipal& aSubjectPrincipal,
                                     ErrorResult& aError)
@@ -9240,17 +9248,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo
 
   // Create and asynchronously dispatch a runnable which will handle actual DOM
   // event creation and dispatch.
   RefPtr<PostMessageEvent> event =
     new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
                          ? nullptr
                          : callerInnerWin->GetOuterWindowInternal(),
                          origin,
-                         this,
+                         AssertOuter(),
                          providedPrincipal,
                          callerInnerWin
                          ? callerInnerWin->GetDoc()
                          : nullptr,
                          nsContentUtils::IsCallerChrome());
 
   JS::Rooted<JS::Value> message(aCx, aMessage);
   JS::Rooted<JS::Value> transfer(aCx, aTransfer);
@@ -10688,41 +10696,41 @@ void nsGlobalWindow::MaybeUpdateTouchSta
 void
 nsGlobalWindow::EnableGamepadUpdates()
 {
   MOZ_ASSERT(IsInnerWindow());
 
   if (mHasGamepad) {
     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
     if (gamepadManager) {
-      gamepadManager->AddListener(this);
+      gamepadManager->AddListener(AssertInner());
     }
   }
 }
 
 void
 nsGlobalWindow::DisableGamepadUpdates()
 {
   MOZ_ASSERT(IsInnerWindow());
 
   if (mHasGamepad) {
     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
     if (gamepadManager) {
-      gamepadManager->RemoveListener(this);
+      gamepadManager->RemoveListener(AssertInner());
     }
   }
 }
 
 void
 nsGlobalWindow::EnableVRUpdates()
 {
   MOZ_ASSERT(IsInnerWindow());
 
   if (mHasVREvents && !mVREventObserver) {
-    mVREventObserver = new VREventObserver(this);
+    mVREventObserver = new VREventObserver(AssertInner());
   }
 }
 
 void
 nsGlobalWindow::DisableVRUpdates()
 {
   MOZ_ASSERT(IsInnerWindow());
   if (mVREventObserver) {
@@ -11210,17 +11218,17 @@ nsGlobalWindow::GetComputedStyleHelperOu
     return nullptr;
   }
 
   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 
   if (!presShell) {
     // Try flushing frames on our parent in case there's a pending
     // style change that will create the presshell.
-    auto* parent = nsGlobalWindow::Cast(GetPrivateParent());
+    auto* parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
     if (!parent) {
       return nullptr;
     }
 
     parent->FlushPendingNotifications(FlushType::Frames);
 
     // Might have killed mDocShell
     if (!mDocShell) {
@@ -11439,17 +11447,17 @@ nsGlobalWindow::GetInterface(const nsIID
       if (viewer) {
         nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
         webBrowserPrint.forget(aSink);
       }
     }
   }
 #endif
   else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     if (!mWindowUtils) {
       mWindowUtils = new nsDOMWindowUtils(outer);
     }
 
     *aSink = mWindowUtils;
     NS_ADDREF(((nsISupports *) *aSink));
@@ -12616,18 +12624,18 @@ nsGlobalWindow::SyncStateFromParentWindo
   MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
   nsPIDOMWindowOuter* outer = GetOuterWindow();
   MOZ_ASSERT(outer);
 
   // Attempt to find our parent windows.
   nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
   nsPIDOMWindowOuter* parentOuter = frame ? frame->OwnerDoc()->GetWindow()
                                           : nullptr;
-  nsGlobalWindow* parentInner =
-    parentOuter ? nsGlobalWindow::Cast(parentOuter->GetCurrentInnerWindow())
+  nsGlobalWindowInner* parentInner =
+    parentOuter ? nsGlobalWindowInner::Cast(parentOuter->GetCurrentInnerWindow())
                 : nullptr;
 
   // If our outer is in a modal state, but our parent is not in a modal
   // state, then we must apply the suspend directly.  If our parent is
   // in a modal state then we should get the suspend automatically
   // via the parentSuspendDepth application below.
   if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) {
     Suspend();
@@ -12673,18 +12681,18 @@ nsGlobalWindow::CallOnChildren(Method aM
     docShell->GetChildAt(i, getter_AddRefs(childShell));
     NS_ASSERTION(childShell, "null child shell");
 
     nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow();
     if (!pWin) {
       continue;
     }
 
-    auto* win = nsGlobalWindow::Cast(pWin);
-    nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
+    auto* win = nsGlobalWindowOuter::Cast(pWin);
+    nsGlobalWindowInner* inner = win->GetCurrentInnerWindowInternal();
 
     // This is a bit hackish. Only freeze/suspend windows which are truly our
     // subwindows.
     nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
     if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
       continue;
     }
 
@@ -12720,17 +12728,17 @@ nsGlobalWindow::FireDelayedDOMEvents()
     docShell->GetChildCount(&childCount);
 
     for (int32_t i = 0; i < childCount; ++i) {
       nsCOMPtr<nsIDocShellTreeItem> childShell;
       docShell->GetChildAt(i, getter_AddRefs(childShell));
       NS_ASSERTION(childShell, "null child shell");
 
       if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
-        auto* win = nsGlobalWindow::Cast(pWin);
+        auto* win = nsGlobalWindowOuter::Cast(pWin);
         win->FireDelayedDOMEvents();
       }
     }
   }
 
   return NS_OK;
 }
 
@@ -12990,17 +12998,17 @@ nsGlobalWindow::OpenInternal(const nsASt
 
   return rv;
 }
 
 //*****************************************************************************
 // nsGlobalWindow: Timeout Functions
 //*****************************************************************************
 
-nsGlobalWindow*
+nsGlobalWindowInner*
 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
 {
   nsGlobalWindow* currentInner;
   nsGlobalWindow* forwardTo;
   if (IsInnerWindow()) {
     nsGlobalWindow* outer = GetOuterWindowInternal();
     currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
 
@@ -13030,24 +13038,26 @@ nsGlobalWindow::InnerForSetTimeoutOrInte
     if (forwardTo->GetOuterWindow() != AsOuter() ||
         !forwardTo->IsInnerWindow()) {
       if (!currentInner) {
         NS_WARNING("No inner window available!");
         aError.Throw(NS_ERROR_NOT_INITIALIZED);
         return nullptr;
       }
 
-      return currentInner;
+      return static_cast<nsGlobalWindowInner*>(currentInner);
     }
   }
 
   // If forwardTo is not the window with an active document then we want the
   // call to setTimeout/Interval to be a noop, so return null but don't set an
   // error.
-  return forwardTo->AsInner()->HasActiveDocument() ? currentInner : nullptr;
+  return forwardTo->AsInner()->HasActiveDocument()
+    ? static_cast<nsGlobalWindowInner*>(currentInner)
+    : nullptr;
 }
 
 int32_t
 nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
                            int32_t aTimeout,
                            const Sequence<JS::Value>& aArguments,
                            ErrorResult& aError)
 {
@@ -13113,17 +13123,17 @@ nsGlobalWindow::SetTimeoutOrInterval(JSC
   }
 
   if (inner != this) {
     return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
                                        aIsInterval, aError);
   }
 
   nsCOMPtr<nsIScriptTimeoutHandler> handler =
-    NS_CreateJSTimeoutHandler(aCx, this, aFunction, aArguments, aError);
+    NS_CreateJSTimeoutHandler(aCx, AssertInner(), aFunction, aArguments, aError);
   if (!handler) {
     return 0;
   }
 
   int32_t result;
   aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
                                       Timeout::Reason::eTimeoutOrInterval,
                                       &result);
@@ -13141,17 +13151,17 @@ nsGlobalWindow::SetTimeoutOrInterval(JSC
   }
 
   if (inner != this) {
     return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
                                        aError);
   }
 
   nsCOMPtr<nsIScriptTimeoutHandler> handler =
-    NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError);
+    NS_CreateJSTimeoutHandler(aCx, AssertInner(), aHandler, aError);
   if (!handler) {
     return 0;
   }
 
   int32_t result;
   aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
                                       Timeout::Reason::eTimeoutOrInterval,
                                       &result);
@@ -13345,17 +13355,17 @@ nsGlobalWindow::GetScrollFrame()
 nsresult
 nsGlobalWindow::SecurityCheckURL(const char *aURL)
 {
   nsCOMPtr<nsPIDOMWindowInner> sourceWindow = do_QueryInterface(GetEntryGlobal());
   if (!sourceWindow) {
     sourceWindow = AsOuter()->GetCurrentInnerWindow();
   }
   AutoJSContext cx;
-  nsGlobalWindow* sourceWin = nsGlobalWindow::Cast(sourceWindow);
+  nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
   JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
 
   // Resolve the baseURI, which could be relative to the calling window.
   //
   // Note the algorithm to get the base URI should match the one
   // used to actually kick off the load in nsWindowWatcher.cpp.
   nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
   nsIURI* baseURI = nullptr;
@@ -13397,17 +13407,17 @@ nsGlobalWindow::FlushPendingNotification
 void
 nsGlobalWindow::EnsureSizeAndPositionUpToDate()
 {
   MOZ_ASSERT(IsOuterWindow());
 
   // If we're a subframe, make sure our size is up to date.  It's OK that this
   // crosses the content/chrome boundary, since chrome can have pending reflows
   // too.
-  nsGlobalWindow *parent = nsGlobalWindow::Cast(GetPrivateParent());
+  nsGlobalWindow *parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
   if (parent) {
     parent->FlushPendingNotifications(FlushType::Layout);
   }
 }
 
 already_AddRefed<nsISupports>
 nsGlobalWindow::SaveWindowState()
 {
@@ -13534,17 +13544,17 @@ nsGlobalWindow::DisableDeviceSensor(uint
 #if defined(MOZ_WIDGET_ANDROID)
 void
 nsGlobalWindow::EnableOrientationChangeListener()
 {
   MOZ_ASSERT(IsInnerWindow());
   if (!nsContentUtils::ShouldResistFingerprinting(mDocShell) &&
       !mOrientationChangeObserver) {
     mOrientationChangeObserver =
-      MakeUnique<WindowOrientationObserver>(this);
+      MakeUnique<WindowOrientationObserver>(AssertInner());
   }
 }
 
 void
 nsGlobalWindow::DisableOrientationChangeListener()
 {
   MOZ_ASSERT(IsInnerWindow());
 
@@ -14003,17 +14013,23 @@ nsGlobalWindow::DispatchVRDisplayPresent
       return;
     }
   }
 }
 
 /* static */ already_AddRefed<nsGlobalWindow>
 nsGlobalWindow::CreateChrome(nsGlobalWindow *aOuterWindow)
 {
-  RefPtr<nsGlobalWindow> window = new nsGlobalWindow(aOuterWindow);
+  RefPtr<nsGlobalWindow> window;
+  if (aOuterWindow) {
+    window = new nsGlobalWindowInner(
+      static_cast<nsGlobalWindowOuter*>(aOuterWindow));
+  } else {
+    window = new nsGlobalWindowOuter();
+  }
   window->mIsChrome = true;
   window->mCleanMessageManager = true;
 
   window->InitWasOffline();
   return window.forget();
 }
 
 enum WindowState {
@@ -14394,17 +14410,23 @@ nsGlobalWindow::TakeOpenerForInitialCont
   // Intentionally forget our own member
   mChromeFields.mOpenerForInitialContentBrowser.forget(aOpenerWindow);
   return NS_OK;
 }
 
 /* static */ already_AddRefed<nsGlobalWindow>
 nsGlobalWindow::Create(nsGlobalWindow *aOuterWindow)
 {
-  RefPtr<nsGlobalWindow> window = new nsGlobalWindow(aOuterWindow);
+  RefPtr<nsGlobalWindow> window;
+  if (aOuterWindow) {
+    window = new nsGlobalWindowInner(
+      static_cast<nsGlobalWindowOuter*>(aOuterWindow));
+  } else {
+    window = new nsGlobalWindowOuter();
+  }
   window->InitWasOffline();
   return window.forget();
 }
 
 void
 nsGlobalWindow::InitWasOffline()
 {
   mWasOffline = NS_IsOffline();
@@ -14498,18 +14520,18 @@ nsGlobalWindow::GetSidebar(OwningExterna
 }
 
 void
 nsGlobalWindow::ClearDocumentDependentSlots(JSContext* aCx)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
-  if (!WindowBinding::ClearCachedDocumentValue(aCx, this) ||
-      !WindowBinding::ClearCachedPerformanceValue(aCx, this)) {
+  if (!WindowBinding::ClearCachedDocumentValue(aCx, AssertInner()) ||
+      !WindowBinding::ClearCachedPerformanceValue(aCx, AssertInner())) {
     MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
   }
 }
 
 /* static */
 JSObject*
 nsGlobalWindow::CreateNamedPropertiesObject(JSContext *aCx,
                                             JS::Handle<JSObject*> aProto)
@@ -14529,23 +14551,23 @@ nsPIDOMWindowOuter::SetLargeAllocStatus(
 {
   MOZ_ASSERT(mLargeAllocStatus == LargeAllocStatus::NONE);
   mLargeAllocStatus = aStatus;
 }
 
 bool
 nsPIDOMWindowOuter::IsTopLevelWindow()
 {
-  return nsGlobalWindow::Cast(this)->IsTopLevelWindow();
+  return nsGlobalWindowOuter::Cast(this)->IsTopLevelWindow();
 }
 
 bool
 nsPIDOMWindowOuter::HadOriginalOpener() const
 {
-  return nsGlobalWindow::Cast(this)->HadOriginalOpener();
+  return nsGlobalWindowOuter::Cast(this)->HadOriginalOpener();
 }
 
 void
 nsGlobalWindow::ReportLargeAllocStatus()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   uint32_t errorFlags = nsIScriptError::warningFlag;
@@ -14868,17 +14890,18 @@ nsGlobalWindow::TabGroupOuter()
     if (mIsChrome) {
       MOZ_ASSERT(mTabGroup == TabGroup::GetChromeTabGroup());
     } else {
       // Sanity check that our tabgroup matches our opener or parent.
       RefPtr<nsPIDOMWindowOuter> parent = GetScriptableParentOrNull();
       MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
       nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
       nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
-      MOZ_ASSERT_IF(opener && Cast(opener) != this, opener->TabGroup() == mTabGroup);
+      MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this,
+                    opener->TabGroup() == mTabGroup);
     }
     mIsValidatingTabGroup = false;
   }
 #endif
 
   return mTabGroup;
 }
 
@@ -15051,11 +15074,56 @@ nsGlobalWindow::GetIntlUtils(ErrorResult
 
   if (!mIntlUtils) {
     mIntlUtils = new IntlUtils(AsInner());
   }
 
   return mIntlUtils;
 }
 
+nsGlobalWindowOuter::nsGlobalWindowOuter()
+  : nsGlobalWindow(nullptr)
+{
+  // Add ourselves to the outer windows list.
+  MOZ_ASSERT(sOuterWindowsById, "Outer Windows hash table must be created!");
+
+  // |this| is an outer window, add to the outer windows list.
+  MOZ_ASSERT(!sOuterWindowsById->Get(mWindowID),
+             "This window shouldn't be in the hash table yet!");
+  // We seem to see crashes in release builds because of null |sOuterWindowsById|.
+  if (sOuterWindowsById) {
+    sOuterWindowsById->Put(mWindowID, AssertOuter());
+  }
+}
+
+nsGlobalWindowOuter::~nsGlobalWindowOuter()
+{
+  // NOTE: We remove ourselves from the sOuterWindowsById table in
+  // nsGlobalWindow::~nsGlobalWindow. We can't do it here because we have to
+  // remove ourselves before running some cleanup in that function.
+}
+
+nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow)
+  : nsGlobalWindow(aOuterWindow)
+{
+  // Add ourselves to the inner windows list.
+  MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
+  MOZ_ASSERT(!sInnerWindowsById->Get(mWindowID),
+             "This window shouldn't be in the hash table yet!");
+  // We seem to see crashes in release builds because of null |sInnerWindowsById|.
+  if (sInnerWindowsById) {
+    sInnerWindowsById->Put(mWindowID, AssertInner());
+    // NOTE: We remove ourselves from this table in
+    // nsGlobalWindow::~nsGlobalWindow. We can't do it here because we have to
+    // remove ourselves before running some cleanup in that function.
+  }
+}
+
+nsGlobalWindowInner::~nsGlobalWindowInner()
+{
+  // NOTE: We remove ourselves from the sInnerWindowsById table in
+  // nsGlobalWindow::~nsGlobalWindow. We can't do it here because we have to
+  // remove ourselves before running some cleanup in that function.
+}
+
 template class nsPIDOMWindow<mozIDOMWindowProxy>;
 template class nsPIDOMWindow<mozIDOMWindow>;
 template class nsPIDOMWindow<nsISupports>;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -149,23 +149,23 @@ class Worklet;
 namespace cache {
 class CacheStorage;
 } // namespace cache
 class IDBFactory;
 } // namespace dom
 } // namespace mozilla
 
 extern already_AddRefed<nsIScriptTimeoutHandler>
-NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
+NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindowInner *aWindow,
                           mozilla::dom::Function& aFunction,
                           const mozilla::dom::Sequence<JS::Value>& aArguments,
                           mozilla::ErrorResult& aError);
 
 extern already_AddRefed<nsIScriptTimeoutHandler>
-NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
+NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindowInner *aWindow,
                           const nsAString& aExpression,
                           mozilla::ErrorResult& aError);
 
 extern const js::Class OuterWindowProxyClass;
 
 struct IdleObserverHolder
 {
   nsCOMPtr<nsIIdleObserver> mIdleObserver;
@@ -223,16 +223,19 @@ public:
            JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError);
 private:
   virtual ~DialogValueHolder() {}
 
   nsCOMPtr<nsIPrincipal> mOrigin;
   nsCOMPtr<nsIVariant> mValue;
 };
 
+class nsGlobalWindowInner;
+class nsGlobalWindowOuter;
+
 //*****************************************************************************
 // nsGlobalWindow: Global Object for Scripting
 //*****************************************************************************
 // Beware that all scriptable interfaces implemented by
 // nsGlobalWindow will be reachable from JS, if you make this class
 // implement new interfaces you better know what you're
 // doing. Security wise this is very sensitive code. --
 // jst@netscape.com
@@ -267,48 +270,27 @@ class nsGlobalWindow : public mozilla::d
                        public nsIScriptObjectPrincipal,
                        public nsSupportsWeakReference,
                        public nsIInterfaceRequestor,
                        public PRCListStr
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
-  typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
 
   static void
   AssertIsOnMainThread()
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
-  static nsGlobalWindow* Cast(nsPIDOMWindowInner* aPIWin) {
-    return static_cast<nsGlobalWindow*>(
-                        reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
-  }
-  static const nsGlobalWindow* Cast(const nsPIDOMWindowInner* aPIWin) {
-    return static_cast<const nsGlobalWindow*>(
-                        reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
-  }
-  static nsGlobalWindow* Cast(mozIDOMWindow* aWin) {
-    return Cast(nsPIDOMWindowInner::From(aWin));
-  }
-  static nsGlobalWindow* Cast(nsPIDOMWindowOuter* aPIWin) {
-    return static_cast<nsGlobalWindow*>(
-                        reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
-  }
-  static const nsGlobalWindow* Cast(const nsPIDOMWindowOuter* aPIWin) {
-    return static_cast<const nsGlobalWindow*>(
-                        reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
-  }
-  static nsGlobalWindow* Cast(mozIDOMWindowProxy* aWin) {
-    return Cast(nsPIDOMWindowOuter::From(aWin));
-  }
+  nsGlobalWindowInner* AssertInner();
+  nsGlobalWindowOuter* AssertOuter();
 
   // public methods
   nsPIDOMWindowOuter* GetPrivateParent();
 
   // callback for close event
   void ReallyCloseWindow();
 
   // nsISupports
@@ -368,24 +350,17 @@ public:
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 const mozilla::dom::AddEventListenerOptionsOrBoolean& aOptions,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) override;
   virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
 
-  virtual nsIGlobalObject* GetOwnerGlobal() const override
-  {
-    if (IsOuterWindow()) {
-      return GetCurrentInnerWindowInternal();
-    }
-
-    return const_cast<nsGlobalWindow*>(this);
-  }
+  virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   // nsPIDOMWindow
   virtual nsPIDOMWindowOuter* GetPrivateRoot() override;
 
   // Outer windows only.
   virtual void ActivateOrDeactivate(bool aActivate) override;
   virtual void SetActive(bool aActive) override;
   virtual bool IsTopLevelWindowActive() override;
@@ -501,31 +476,19 @@ public:
     return (nsGlobalWindow *)(mozilla::dom::EventTarget *)supports;
   }
   static nsGlobalWindow *FromWrapper(nsIXPConnectWrappedNative *wrapper)
   {
     return FromSupports(wrapper->Native());
   }
   already_AddRefed<nsPIDOMWindowOuter> GetTop() override;
   nsPIDOMWindowOuter* GetScriptableTop() override;
-  inline nsGlobalWindow *GetTopInternal()
-  {
-    nsGlobalWindow* outer = IsOuterWindow() ? this : GetOuterWindowInternal();
-    nsCOMPtr<nsPIDOMWindowOuter> top = outer ? outer->GetTop() : nullptr;
-    if (top) {
-      return nsGlobalWindow::Cast(top);
-    }
-    return nullptr;
-  }
+  inline nsGlobalWindowOuter *GetTopInternal();
 
-  inline nsGlobalWindow* GetScriptableTopInternal()
-  {
-    nsPIDOMWindowOuter* top = GetScriptableTop();
-    return nsGlobalWindow::Cast(top);
-  }
+  inline nsGlobalWindowOuter* GetScriptableTopInternal();
 
   nsPIDOMWindowOuter* GetChildWindow(const nsAString& aName);
 
   // These return true if we've reached the state in this top level window
   // where we ask the user if further dialogs should be blocked.
   //
   // DialogsAreBeingAbused must be called on the scriptable top inner window.
   //
@@ -564,40 +527,23 @@ public:
     RefPtr<nsGlobalWindow> mTopWindow;
     // This is not a AutoRestore<bool> because that would require careful
     // member destructor ordering, which is a bit fragile.  This way we can
     // explicitly restore things before we drop our ref to mTopWindow.
     bool mSavedDialogsEnabled;
   };
   friend class TemporarilyDisableDialogs;
 
-  nsIScriptContext *GetContextInternal()
-  {
-    if (mOuterWindow) {
-      return GetOuterWindowInternal()->mContext;
-    }
+  nsIScriptContext *GetContextInternal();
 
-    return mContext;
-  }
+  nsGlobalWindowOuter *GetOuterWindowInternal();
 
-  nsGlobalWindow *GetOuterWindowInternal()
-  {
-    return nsGlobalWindow::Cast(GetOuterWindow());
-  }
+  nsGlobalWindowInner* GetCurrentInnerWindowInternal() const;
 
-  nsGlobalWindow* GetCurrentInnerWindowInternal() const
-  {
-    MOZ_ASSERT(IsOuterWindow());
-    return nsGlobalWindow::Cast(mInnerWindow);
-  }
-
-  nsGlobalWindow* EnsureInnerWindowInternal()
-  {
-    return nsGlobalWindow::Cast(AsOuter()->EnsureInnerWindow());
-  }
+  nsGlobalWindowInner* EnsureInnerWindowInternal();
 
   bool IsCreatingInnerWindow() const
   {
     return mCreatingInnerWindow;
   }
 
   bool IsChromeWindow() const
   {
@@ -677,62 +623,28 @@ public:
 
   bool
   HadOriginalOpener() const
   {
     MOZ_ASSERT(IsOuterWindow());
     return mHadOriginalOpener;
   }
 
-  bool
-  IsTopLevelWindow()
-  {
-    MOZ_ASSERT(IsOuterWindow());
-    nsPIDOMWindowOuter* parentWindow = GetScriptableTop();
-    return parentWindow == this->AsOuter();
-  }
+  bool IsTopLevelWindow();
 
   virtual void
   FirePopupBlockedEvent(nsIDocument* aDoc,
                         nsIURI* aPopupURI,
                         const nsAString& aPopupWindowName,
                         const nsAString& aPopupWindowFeatures) override;
 
   virtual uint32_t GetSerial() override {
     return mSerial;
   }
 
-  static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID) {
-    AssertIsOnMainThread();
-
-    if (!sWindowsById) {
-      return nullptr;
-    }
-
-    nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
-    return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nullptr;
-  }
-
-  static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID) {
-    AssertIsOnMainThread();
-
-    if (!sWindowsById) {
-      return nullptr;
-    }
-
-    nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
-    return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
-  }
-
-  static WindowByIdTable* GetWindowsTable() {
-    AssertIsOnMainThread();
-
-    return sWindowsById;
-  }
-
   void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const;
 
   // Inner windows only.
   void AddEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
   void RemoveEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
 
   void NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
                           bool aCallOnidle);
@@ -850,18 +762,18 @@ public:
   nsISupports* GetParentObject()
   {
     return nullptr;
   }
 
   static JSObject*
     CreateNamedPropertiesObject(JSContext *aCx, JS::Handle<JSObject*> aProto);
 
-  nsGlobalWindow* Window();
-  nsGlobalWindow* Self();
+  nsGlobalWindowInner* Window();
+  nsGlobalWindowInner* Self();
   nsIDocument* GetDocument()
   {
     return GetDoc();
   }
   void GetNameOuter(nsAString& aName);
   void GetName(nsAString& aName, mozilla::ErrorResult& aError);
   void SetNameOuter(const nsAString& aName, mozilla::ErrorResult& aError);
   void SetName(const nsAString& aName, mozilla::ErrorResult& aError);
@@ -1468,38 +1380,31 @@ protected:
   inline void MaybeClearInnerWindow(nsGlobalWindow* aExpectedInner)
   {
     if(mInnerWindow == aExpectedInner->AsInner()) {
       mInnerWindow = nullptr;
     }
   }
 
   void FreeInnerObjects();
-  nsGlobalWindow *CallerInnerWindow();
+  nsGlobalWindowInner *CallerInnerWindow();
 
   // Only to be called on an inner window.
   // aDocument must not be null.
   void InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument);
 
   // Inner windows only.
   nsresult DefineArgumentsProperty(nsIArray *aArguments);
 
   // Get the parent, returns null if this is a toplevel window
   nsPIDOMWindowOuter* GetParentInternal();
 
 public:
   // popup tracking
-  bool IsPopupSpamWindow()
-  {
-    if (IsInnerWindow() && !mOuterWindow) {
-      return false;
-    }
-
-    return GetOuterWindowInternal()->mIsPopupSpam;
-  }
+  bool IsPopupSpamWindow();
 
   // Outer windows only.
   void SetIsPopupSpamWindow(bool aIsPopupSpam);
 
 protected:
   // Window Control Functions
 
   // Outer windows only.
@@ -1664,20 +1569,17 @@ public:
   void SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
   nsRect GetInnerScreenRect();
 
   void ScrollTo(const mozilla::CSSIntPoint& aScroll,
                 const mozilla::dom::ScrollOptions& aOptions);
 
-  bool IsFrame()
-  {
-    return GetParentInternal() != nullptr;
-  }
+  bool IsFrame();
 
   // Outer windows only.
   // If aLookForCallerOnJSStack is true, this method will look at the JS stack
   // to determine who the caller is.  If it's false, it'll use |this| as the
   // caller.
   bool WindowExists(const nsAString& aName, bool aForceNoOpener,
                     bool aLookForCallerOnJSStack);
 
@@ -1754,17 +1656,17 @@ protected:
 
   // Outer windows only.
   void PreloadLocalStorage();
 
   // Returns CSS pixels based on primary screen.  Outer windows only.
   mozilla::CSSIntPoint GetScreenXY(mozilla::dom::CallerType aCallerType,
                                    mozilla::ErrorResult& aError);
 
-  nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);
+  nsGlobalWindowInner* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);
 
   void PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                            const nsAString& aTargetOrigin,
                            JS::Handle<JS::Value> aTransfer,
                            nsIPrincipal& aSubjectPrincipal,
                            mozilla::ErrorResult& aError);
   void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const nsAString& aTargetOrigin,
@@ -2083,40 +1985,228 @@ protected:
   } mChromeFields;
 
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class mozilla::dom::PostMessageEvent;
   friend class DesktopNotification;
   friend class mozilla::dom::TimeoutManager;
   friend class IdleRequestExecutor;
-
-  static WindowByIdTable* sWindowsById;
 };
 
 inline nsISupports*
 ToSupports(nsGlobalWindow *p)
 {
     return static_cast<nsIDOMEventTarget*>(p);
 }
 
 inline nsISupports*
 ToCanonicalSupports(nsGlobalWindow *p)
 {
     return static_cast<nsIDOMEventTarget*>(p);
 }
 
+class nsGlobalWindowOuter : public nsGlobalWindow
+{
+public:
+  typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindowOuter*> OuterWindowByIdTable;
+
+  friend class nsGlobalWindow;
+
+  static nsGlobalWindowOuter* Cast(nsPIDOMWindowOuter* aPIWin) {
+    return static_cast<nsGlobalWindowOuter*>(
+                        reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
+  }
+  static const nsGlobalWindowOuter* Cast(const nsPIDOMWindowOuter* aPIWin) {
+    return static_cast<const nsGlobalWindowOuter*>(
+                        reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
+  }
+  static nsGlobalWindowOuter* Cast(mozIDOMWindowProxy* aWin) {
+    return Cast(nsPIDOMWindowOuter::From(aWin));
+  }
+
+  static nsGlobalWindowOuter*
+  GetOuterWindowWithId(uint64_t aWindowID)
+  {
+    AssertIsOnMainThread();
+
+    if (!sOuterWindowsById) {
+      return nullptr;
+    }
+
+    nsGlobalWindowOuter* outerWindow = sOuterWindowsById->Get(aWindowID);
+    MOZ_ASSERT(!outerWindow || outerWindow->IsOuterWindow(),
+               "Inner window in sOuterWindowsById?");
+    return outerWindow;
+  }
+
+  static OuterWindowByIdTable* GetWindowsTable() {
+    AssertIsOnMainThread();
+
+    return sOuterWindowsById;
+  }
+
+private:
+  nsGlobalWindowOuter();
+  ~nsGlobalWindowOuter();
+
+  static OuterWindowByIdTable* sOuterWindowsById;
+};
+
+class nsGlobalWindowInner : public nsGlobalWindow
+{
+public:
+  typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindowInner*> InnerWindowByIdTable;
+
+  friend class nsGlobalWindow;
+
+  static nsGlobalWindowInner* Cast(nsPIDOMWindowInner* aPIWin) {
+    return static_cast<nsGlobalWindowInner*>(
+                        reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
+  }
+  static const nsGlobalWindowInner* Cast(const nsPIDOMWindowInner* aPIWin) {
+    return static_cast<const nsGlobalWindowInner*>(
+                        reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
+  }
+  static nsGlobalWindowInner* Cast(mozIDOMWindow* aWin) {
+    return Cast(nsPIDOMWindowInner::From(aWin));
+  }
+
+  static nsGlobalWindowInner*
+  GetInnerWindowWithId(uint64_t aInnerWindowID)
+  {
+    AssertIsOnMainThread();
+
+    if (!sInnerWindowsById) {
+      return nullptr;
+    }
+
+    nsGlobalWindowInner* innerWindow =
+      sInnerWindowsById->Get(aInnerWindowID);
+    MOZ_ASSERT(!innerWindow || innerWindow->IsInnerWindow(),
+               "Outer window in sInnerWindowsById?");
+    return innerWindow;
+  }
+
+  static InnerWindowByIdTable* GetWindowsTable() {
+    AssertIsOnMainThread();
+
+    return sInnerWindowsById;
+  }
+
+private:
+  explicit nsGlobalWindowInner(nsGlobalWindowOuter* aOuter);
+  ~nsGlobalWindowInner();
+
+  static InnerWindowByIdTable* sInnerWindowsById;
+};
+
+inline nsIGlobalObject*
+nsGlobalWindow::GetOwnerGlobal() const
+{
+  if (IsOuterWindow()) {
+    return GetCurrentInnerWindowInternal();
+  }
+
+  return const_cast<nsGlobalWindow*>(this);
+}
+
+inline nsGlobalWindowOuter*
+nsGlobalWindow::GetTopInternal()
+{
+  nsGlobalWindow* outer = IsOuterWindow() ? this : GetOuterWindowInternal();
+  nsCOMPtr<nsPIDOMWindowOuter> top = outer ? outer->GetTop() : nullptr;
+  if (top) {
+    return nsGlobalWindowOuter::Cast(top);
+  }
+  return nullptr;
+}
+
+inline nsGlobalWindowOuter*
+nsGlobalWindow::GetScriptableTopInternal()
+{
+  nsPIDOMWindowOuter* top = GetScriptableTop();
+  return nsGlobalWindowOuter::Cast(top);
+}
+
+inline nsIScriptContext*
+nsGlobalWindow::GetContextInternal()
+  {
+    if (mOuterWindow) {
+      return GetOuterWindowInternal()->mContext;
+    }
+
+    return mContext;
+  }
+
+inline nsGlobalWindowOuter*
+nsGlobalWindow::GetOuterWindowInternal()
+{
+  return nsGlobalWindowOuter::Cast(GetOuterWindow());
+}
+
+inline nsGlobalWindowInner*
+nsGlobalWindow::GetCurrentInnerWindowInternal() const
+{
+  MOZ_ASSERT(IsOuterWindow());
+  return nsGlobalWindowInner::Cast(mInnerWindow);
+}
+
+inline nsGlobalWindowInner*
+nsGlobalWindow::EnsureInnerWindowInternal()
+{
+  return nsGlobalWindowInner::Cast(AsOuter()->EnsureInnerWindow());
+}
+
+inline bool
+nsGlobalWindow::IsTopLevelWindow()
+{
+  MOZ_ASSERT(IsOuterWindow());
+  nsPIDOMWindowOuter* parentWindow = GetScriptableTop();
+  return parentWindow == this->AsOuter();
+}
+
+inline bool
+nsGlobalWindow::IsPopupSpamWindow()
+{
+  if (IsInnerWindow() && !mOuterWindow) {
+    return false;
+  }
+
+  return GetOuterWindowInternal()->mIsPopupSpam;
+}
+
+inline bool
+nsGlobalWindow::IsFrame()
+{
+  return GetParentInternal() != nullptr;
+}
+
+inline nsGlobalWindowInner*
+nsGlobalWindow::AssertInner()
+{
+  MOZ_RELEASE_ASSERT(IsInnerWindow());
+  return static_cast<nsGlobalWindowInner*>(this);
+}
+
+inline nsGlobalWindowOuter*
+nsGlobalWindow::AssertOuter()
+{
+  MOZ_RELEASE_ASSERT(IsOuterWindow());
+  return static_cast<nsGlobalWindowOuter*>(this);
+}
+
 /* factory function */
-inline already_AddRefed<nsGlobalWindow>
+inline already_AddRefed<nsGlobalWindowOuter>
 NS_NewScriptGlobalObject(bool aIsChrome)
 {
   RefPtr<nsGlobalWindow> global;
 
   if (aIsChrome) {
     global = nsGlobalWindow::CreateChrome(nullptr);
   } else {
     global = nsGlobalWindow::Create(nullptr);
   }
 
-  return global.forget();
+  return global.forget().downcast<nsGlobalWindowOuter>();
 }
 
 #endif /* nsGlobalWindow_h___ */
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -57,16 +57,17 @@ class ElementCreationOptionsOrString;
 class gfxUserFontSet;
 class imgIRequest;
 class nsBindingManager;
 class nsCachableElementsByNameNodeList;
 class nsIDocShell;
 class nsDocShell;
 class nsDOMNavigationTiming;
 class nsFrameLoader;
+class nsGlobalWindowInner;
 class nsHTMLCSSStyleSheet;
 class nsHTMLDocument;
 class nsHTMLStyleSheet;
 class nsAtom;
 class nsIBFCacheEntry;
 class nsIChannel;
 class nsIContent;
 class nsIContentSink;
@@ -3040,17 +3041,17 @@ public:
                      mozilla::ErrorResult& rv);
   nsINode* CreateNSResolver(nsINode& aNodeResolver);
   already_AddRefed<mozilla::dom::XPathResult>
     Evaluate(JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode,
              mozilla::dom::XPathNSResolver* aResolver, uint16_t aType,
              JS::Handle<JSObject*> aResult, mozilla::ErrorResult& rv);
   // Touch event handlers already on nsINode
   already_AddRefed<mozilla::dom::Touch>
-    CreateTouch(nsGlobalWindow* aView, mozilla::dom::EventTarget* aTarget,
+    CreateTouch(nsGlobalWindowInner* aView, mozilla::dom::EventTarget* aTarget,
                 int32_t aIdentifier, int32_t aPageX, int32_t aPageY,
                 int32_t aScreenX, int32_t aScreenY, int32_t aClientX,
                 int32_t aClientY, int32_t aRadiusX, int32_t aRadiusY,
                 float aRotationAngle, float aForce);
   already_AddRefed<mozilla::dom::TouchList> CreateTouchList();
   already_AddRefed<mozilla::dom::TouchList>
     CreateTouchList(mozilla::dom::Touch& aTouch,
                     const mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::Touch> >& aTouches);
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1381,17 +1381,17 @@ nsINode::GetContextForEventHandlers(nsre
 {
   return nsContentUtils::GetContextForEventHandlers(this, aRv);
 }
 
 nsPIDOMWindowOuter*
 nsINode::GetOwnerGlobalForBindings()
 {
   bool dummy;
-  auto* window = static_cast<nsGlobalWindow*>(OwnerDoc()->GetScriptHandlingObject(dummy));
+  auto* window = static_cast<nsGlobalWindowInner*>(OwnerDoc()->GetScriptHandlingObject(dummy));
   return window ? nsPIDOMWindowOuter::GetFromCurrentInner(window->AsInner()) : nullptr;
 }
 
 nsIGlobalObject*
 nsINode::GetOwnerGlobal() const
 {
   bool dummy;
   return OwnerDoc()->GetScriptHandlingObject(dummy);
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -406,17 +406,17 @@ NS_HandleScriptError(nsIScriptGlobalObje
 
     static int32_t errorDepth; // Recursion prevention
     ++errorDepth;
 
     if (errorDepth < 2) {
       // Dispatch() must be synchronous for the recursion block
       // (errorDepth) to work.
       RefPtr<ErrorEvent> event =
-        ErrorEvent::Constructor(nsGlobalWindow::Cast(win),
+        ErrorEvent::Constructor(nsGlobalWindowInner::Cast(win),
                                 NS_LITERAL_STRING("error"),
                                 aErrorEventInit);
       event->SetTrusted(true);
 
       EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
                                         aStatus);
       called = true;
     }
@@ -467,17 +467,17 @@ public:
         init.mError = mError;
       } else {
         NS_WARNING("Not same origin error!");
         init.mMessage = xoriginMsg;
         init.mLineno = 0;
       }
 
       RefPtr<ErrorEvent> event =
-        ErrorEvent::Constructor(nsGlobalWindow::Cast(win),
+        ErrorEvent::Constructor(nsGlobalWindowInner::Cast(win),
                                 NS_LITERAL_STRING("error"), init);
       event->SetTrusted(true);
 
       EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
                                         &status);
     }
 
     if (status != nsEventStatus_eConsumeNoDefault) {
@@ -509,24 +509,25 @@ DispatchScriptErrorEvent(nsPIDOMWindowIn
 {
   nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception));
 }
 
 } /* namespace xpc */
 
 #ifdef DEBUG
 // A couple of useful functions to call when you're debugging.
-nsGlobalWindow *
+nsGlobalWindowInner *
 JSObject2Win(JSObject *obj)
 {
   return xpc::WindowOrNull(obj);
 }
 
+template<typename T>
 void
-PrintWinURI(nsGlobalWindow *win)
+PrintWinURI(T *win)
 {
   if (!win) {
     printf("No window passed in.\n");
     return;
   }
 
   nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
   if (!doc) {
@@ -539,17 +540,30 @@ PrintWinURI(nsGlobalWindow *win)
     printf("Document doesn't have a URI.\n");
     return;
   }
 
   printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
-PrintWinCodebase(nsGlobalWindow *win)
+PrintWinURIInner(nsGlobalWindowInner* aWin)
+{
+  return PrintWinURI(aWin);
+}
+
+void
+PrintWinURIOuter(nsGlobalWindowOuter* aWin)
+{
+  return PrintWinURI(aWin);
+}
+
+template<typename T>
+void
+PrintWinCodebase(T *win)
 {
   if (!win) {
     printf("No window passed in.\n");
     return;
   }
 
   nsIPrincipal *prin = win->GetPrincipal();
   if (!prin) {
@@ -563,16 +577,28 @@ PrintWinCodebase(nsGlobalWindow *win)
     printf("No URI, maybe the system principal.\n");
     return;
   }
 
   printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
+PrintWinCodebaseInner(nsGlobalWindowInner* aWin)
+{
+  return PrintWinCodebase(aWin);
+}
+
+void
+PrintWinCodebaseOuter(nsGlobalWindowOuter* aWin)
+{
+  return PrintWinCodebase(aWin);
+}
+
+void
 DumpString(const nsAString &str)
 {
   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
 }
 #endif
 
 #define JS_OPTIONS_DOT_STR "javascript.options."
 
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -30,21 +30,21 @@ class nsJSScriptTimeoutHandler final : p
 {
 public:
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSScriptTimeoutHandler)
 
   nsJSScriptTimeoutHandler();
   // This will call SwapElements on aArguments with an empty array.
-  nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow* aWindow,
+  nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindowInner* aWindow,
                            Function& aFunction,
                            nsTArray<JS::Heap<JS::Value>>&& aArguments,
                            ErrorResult& aError);
-  nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow* aWindow,
+  nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindowInner* aWindow,
                            const nsAString& aExpression, bool* aAllowEval,
                            ErrorResult& aError);
   nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                            Function& aFunction,
                            nsTArray<JS::Heap<JS::Value>>&& aArguments);
   nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                            const nsAString& aExpression);
 
@@ -160,17 +160,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler)
 
 static bool
-CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
+CheckCSPForEval(JSContext* aCx, nsGlobalWindowInner* aWindow, ErrorResult& aError)
 {
   // if CSP is enabled, and setTimeout/setInterval was called with a string,
   // disable the registration and log an error
   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
   if (!doc) {
     // if there's no document, we don't have to do anything.
     return true;
   }
@@ -214,17 +214,17 @@ CheckCSPForEval(JSContext* aCx, nsGlobal
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
   : mLineNo(0)
   , mColumn(0)
 {
 }
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
-                                                   nsGlobalWindow *aWindow,
+                                                   nsGlobalWindowInner *aWindow,
                                                    Function& aFunction,
                                                    nsTArray<JS::Heap<JS::Value>>&& aArguments,
                                                    ErrorResult& aError)
   : mLineNo(0)
   , mColumn(0)
   , mFunction(&aFunction)
 {
   if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
@@ -233,17 +233,17 @@ nsJSScriptTimeoutHandler::nsJSScriptTime
     aError.Throw(NS_ERROR_NOT_INITIALIZED);
     return;
   }
 
   Init(aCx, Move(aArguments));
 }
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
-                                                   nsGlobalWindow *aWindow,
+                                                   nsGlobalWindowInner *aWindow,
                                                    const nsAString& aExpression,
                                                    bool* aAllowEval,
                                                    ErrorResult& aError)
   : mLineNo(0)
   , mColumn(0)
   , mExpr(aExpression)
 {
   if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
@@ -323,34 +323,34 @@ nsJSScriptTimeoutHandler::ReleaseJSObjec
 const nsAString&
 nsJSScriptTimeoutHandler::GetHandlerText()
 {
   NS_ASSERTION(!mFunction, "No expression, so no handler text!");
   return mExpr;
 }
 
 already_AddRefed<nsIScriptTimeoutHandler>
-NS_CreateJSTimeoutHandler(JSContext *aCx, nsGlobalWindow *aWindow,
+NS_CreateJSTimeoutHandler(JSContext *aCx, nsGlobalWindowInner *aWindow,
                           Function& aFunction,
                           const Sequence<JS::Value>& aArguments,
                           ErrorResult& aError)
 {
   nsTArray<JS::Heap<JS::Value>> args;
   if (!args.AppendElements(aArguments, fallible)) {
     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
 
   RefPtr<nsJSScriptTimeoutHandler> handler =
     new nsJSScriptTimeoutHandler(aCx, aWindow, aFunction, Move(args), aError);
   return aError.Failed() ? nullptr : handler.forget();
 }
 
 already_AddRefed<nsIScriptTimeoutHandler>
-NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
+NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindowInner *aWindow,
                           const nsAString& aExpression, ErrorResult& aError)
 {
   bool allowEval = false;
   RefPtr<nsJSScriptTimeoutHandler> handler =
     new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError);
   if (aError.Failed() || !allowEval) {
     return nullptr;
   }
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -78,17 +78,17 @@ nsJSUtils::GetStaticScriptContext(JSObje
 }
 
 uint64_t
 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
 {
   if (!aContext)
     return 0;
 
-  nsGlobalWindow* win = xpc::CurrentWindowOrNull(aContext);
+  nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aContext);
   return win ? win->WindowID() : 0;
 }
 
 nsresult
 nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
                            JS::AutoObjectVector& aScopeChain,
                            JS::CompileOptions& aOptions,
                            const nsACString& aName,
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -44,27 +44,26 @@ nsWindowMemoryReporter::~nsWindowMemoryR
 {
   KillCheckTimer();
 }
 
 NS_IMPL_ISUPPORTS(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver,
                   nsISupportsWeakReference)
 
 static nsresult
-AddNonJSSizeOfWindowAndItsDescendents(nsGlobalWindow* aWindow,
+AddNonJSSizeOfWindowAndItsDescendents(nsGlobalWindowOuter* aWindow,
                                       nsTabSizes* aSizes)
 {
   // Measure the window.
   SizeOfState state(moz_malloc_size_of);
   nsWindowSizes windowSizes(state);
   aWindow->AddSizeOfIncludingThis(windowSizes);
 
   // Measure the inner window, if there is one.
-  nsGlobalWindow* inner = aWindow->IsOuterWindow() ? aWindow->GetCurrentInnerWindowInternal()
-                                                   : nullptr;
+  nsGlobalWindowInner* inner = aWindow->GetCurrentInnerWindowInternal();
   if (inner) {
     inner->AddSizeOfIncludingThis(windowSizes);
   }
 
   windowSizes.addToTabSizes(aSizes);
 
   nsCOMPtr<nsIDOMWindowCollection> frames = aWindow->GetFrames();
 
@@ -74,28 +73,28 @@ AddNonJSSizeOfWindowAndItsDescendents(ns
 
   // Measure this window's descendents.
   for (uint32_t i = 0; i < length; i++) {
       nsCOMPtr<mozIDOMWindowProxy> child;
       rv = frames->Item(i, getter_AddRefs(child));
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ENSURE_STATE(child);
 
-      nsGlobalWindow* childWin = nsGlobalWindow::Cast(child);
+      nsGlobalWindowOuter* childWin = nsGlobalWindowOuter::Cast(child);
 
       rv = AddNonJSSizeOfWindowAndItsDescendents(childWin, aSizes);
       NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 static nsresult
 NonJSSizeOfTab(nsPIDOMWindowOuter* aWindow, size_t* aDomSize, size_t* aStyleSize, size_t* aOtherSize)
 {
-  nsGlobalWindow* window = nsGlobalWindow::Cast(aWindow);
+  nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow);
 
   nsTabSizes sizes;
   nsresult rv = AddNonJSSizeOfWindowAndItsDescendents(window, &sizes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aDomSize   = sizes.mDom;
   *aStyleSize = sizes.mStyle;
   *aOtherSize = sizes.mOther;
@@ -126,17 +125,17 @@ nsWindowMemoryReporter::Init()
 
 /* static */ nsWindowMemoryReporter*
 nsWindowMemoryReporter::Get()
 {
   return sWindowReporter;
 }
 
 static already_AddRefed<nsIURI>
-GetWindowURI(nsGlobalWindow* aWindow)
+GetWindowURI(nsGlobalWindowInner* aWindow)
 {
   NS_ENSURE_TRUE(aWindow, nullptr);
 
   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
   nsCOMPtr<nsIURI> uri;
 
   if (doc) {
     uri = doc->GetDocumentURI();
@@ -157,18 +156,26 @@ GetWindowURI(nsGlobalWindow* aWindow)
         principal->GetURI(getter_AddRefs(uri));
       }
     }
   }
 
   return uri.forget();
 }
 
+// Forward to the inner window if we need to when getting the window's URI.
+static already_AddRefed<nsIURI>
+GetWindowURI(nsGlobalWindowOuter* aWindow)
+{
+  NS_ENSURE_TRUE(aWindow, nullptr);
+  return GetWindowURI(aWindow->GetCurrentInnerWindowInternal());
+}
+
 static void
-AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
+AppendWindowURI(nsGlobalWindowInner *aWindow, nsACString& aStr, bool aAnonymize)
 {
   nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
 
   if (uri) {
     if (aAnonymize && !aWindow->IsChromeWindow()) {
       aStr.AppendPrintf("<anonymized-%" PRIu64 ">", aWindow->WindowID());
     } else {
       nsCString spec = uri->GetSpecOrDefault();
@@ -228,31 +235,31 @@ ReportCount(const nsCString& aBasePath, 
             nsISupports* aData)
 {
   ReportAmount(aBasePath, aPathTail, aAmount, aDescription,
                nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
                aHandleReport, aData);
 }
 
 static void
-CollectWindowReports(nsGlobalWindow *aWindow,
+CollectWindowReports(nsGlobalWindowInner *aWindow,
                      amIAddonManager *addonManager,
                      nsWindowSizes *aWindowTotalSizes,
                      nsTHashtable<nsUint64HashKey> *aGhostWindowIDs,
                      WindowPaths *aWindowPaths,
                      WindowPaths *aTopWindowPaths,
                      nsIHandleReportCallback *aHandleReport,
                      nsISupports *aData,
                      bool aAnonymize)
 {
   nsAutoCString windowPath("explicit/");
 
   // Avoid calling aWindow->GetTop() if there's no outer window.  It will work
   // just fine, but will spew a lot of warnings.
-  nsGlobalWindow *top = nullptr;
+  nsGlobalWindowOuter *top = nullptr;
   nsCOMPtr<nsIURI> location;
   if (aWindow->GetOuterWindow()) {
     // Our window should have a null top iff it has a null docshell.
     MOZ_ASSERT(!!aWindow->GetTopInternal() == !!aWindow->GetDocShell());
     top = aWindow->GetTopInternal();
     if (top) {
       location = GetWindowURI(top);
     }
@@ -271,17 +278,17 @@ CollectWindowReports(nsGlobalWindow *aWi
                     NS_LITERAL_CSTRING("/");
     }
   }
 
   windowPath += NS_LITERAL_CSTRING("window-objects/");
 
   if (top) {
     windowPath += NS_LITERAL_CSTRING("top(");
-    AppendWindowURI(top, windowPath, aAnonymize);
+    AppendWindowURI(top->GetCurrentInnerWindowInternal(), windowPath, aAnonymize);
     windowPath.AppendPrintf(", id=%" PRIu64 ")", top->WindowID());
 
     aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
 
     windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("/cached/")
                                       : NS_LITERAL_CSTRING("/active/");
   } else {
     if (aGhostWindowIDs->Contains(aWindow->WindowID())) {
@@ -533,46 +540,46 @@ CollectWindowReports(nsGlobalWindow *aWi
       "small to be shown individually.");
   }
 
 #undef REPORT_SIZE
 #undef REPORT_SUM_SIZE
 #undef REPORT_COUNT
 }
 
-typedef nsTArray< RefPtr<nsGlobalWindow> > WindowArray;
+typedef nsTArray< RefPtr<nsGlobalWindowInner> > WindowArray;
 
 NS_IMETHODIMP
 nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
                                        nsISupports* aData, bool aAnonymize)
 {
-  nsGlobalWindow::WindowByIdTable* windowsById =
-    nsGlobalWindow::GetWindowsTable();
+  nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+    nsGlobalWindowInner::GetWindowsTable();
   NS_ENSURE_TRUE(windowsById, NS_OK);
 
   // Hold on to every window in memory so that window objects can't be
   // destroyed while we're calling the memory reporter callback.
   WindowArray windows;
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     windows.AppendElement(iter.Data());
   }
 
   // Get the IDs of all the "ghost" windows, and call aHandleReport->Callback()
   // for each one.
   nsTHashtable<nsUint64HashKey> ghostWindows;
   CheckForGhostWindows(&ghostWindows);
   for (auto iter = ghostWindows.ConstIter(); !iter.Done(); iter.Next()) {
-    nsGlobalWindow::WindowByIdTable* windowsById =
-      nsGlobalWindow::GetWindowsTable();
+    nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+      nsGlobalWindowInner::GetWindowsTable();
     if (!windowsById) {
       NS_WARNING("Couldn't get window-by-id hashtable?");
       continue;
     }
 
-    nsGlobalWindow* window = windowsById->Get(iter.Get()->GetKey());
+    nsGlobalWindowInner* window = windowsById->Get(iter.Get()->GetKey());
     if (!window) {
       NS_WARNING("Could not look up window?");
       continue;
     }
 
     nsAutoCString path;
     path.AppendLiteral("ghost-windows/");
     AppendWindowURI(window, path, aAnonymize);
@@ -779,17 +786,17 @@ nsWindowMemoryReporter::Observe(nsISuppo
   } else {
     MOZ_ASSERT(false);
   }
 
   return NS_OK;
 }
 
 void
-nsWindowMemoryReporter::ObserveDOMWindowDetached(nsGlobalWindow* aWindow)
+nsWindowMemoryReporter::ObserveDOMWindowDetached(nsGlobalWindowInner* aWindow)
 {
   nsWeakPtr weakWindow = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aWindow));
   if (!weakWindow) {
     NS_WARNING("Couldn't take weak reference to a window?");
     return;
   }
 
   mDetachedWindows.Put(weakWindow, TimeStamp());
@@ -876,34 +883,34 @@ nsWindowMemoryReporter::CheckForGhostWin
 {
   nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(
     NS_EFFECTIVETLDSERVICE_CONTRACTID);
   if (!tldService) {
     NS_WARNING("Couldn't get TLDService.");
     return;
   }
 
-  nsGlobalWindow::WindowByIdTable *windowsById =
-    nsGlobalWindow::GetWindowsTable();
+  nsGlobalWindowInner::InnerWindowByIdTable *windowsById =
+    nsGlobalWindowInner::GetWindowsTable();
   if (!windowsById) {
     NS_WARNING("GetWindowsTable returned null");
     return;
   }
 
   mLastCheckForGhostWindows = TimeStamp::NowLoRes();
   KillCheckTimer();
 
   nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
   nsDataHashtable<nsISupportsHashKey, nsCString> domainMap;
 
   // Populate nonDetachedWindowDomains.
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     // Null outer window implies null top, but calling GetTop() when there's no
     // outer window causes us to spew debug warnings.
-    nsGlobalWindow* window = iter.UserData();
+    nsGlobalWindowInner* window = iter.UserData();
     if (!window->GetOuterWindow() || !window->GetTopInternal()) {
       // This window is detached, so we don't care about its domain.
       continue;
     }
 
     nsCOMPtr<nsIURI> uri = GetWindowURI(window);
     nsAutoCString domain;
     if (uri) {
@@ -943,17 +950,17 @@ nsWindowMemoryReporter::CheckForGhostWin
     }
 
     if (top) {
       // The window is no longer detached, so we no longer want to track it.
       iter.Remove();
       continue;
     }
 
-    nsCOMPtr<nsIURI> uri = GetWindowURI(nsGlobalWindow::Cast(window));
+    nsCOMPtr<nsIURI> uri = GetWindowURI(nsGlobalWindowInner::Cast(window));
 
     nsAutoCString domain;
     if (uri) {
       // GetBaseDomain works fine if |uri| is null, but it outputs a warning
       // which ends up overrunning the mochitest logs.
       tldService->GetBaseDomain(uri, 0, domain);
     }
 
@@ -999,38 +1006,38 @@ nsWindowMemoryReporter::KillCheckTimer()
 #ifdef DEBUG
 /* static */ void
 nsWindowMemoryReporter::UnlinkGhostWindows()
 {
   if (!sWindowReporter) {
     return;
   }
 
-  nsGlobalWindow::WindowByIdTable* windowsById =
-    nsGlobalWindow::GetWindowsTable();
+  nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+    nsGlobalWindowInner::GetWindowsTable();
   if (!windowsById) {
     return;
   }
 
   // Hold on to every window in memory so that window objects can't be
   // destroyed while we're calling the UnlinkGhostWindows callback.
   WindowArray windows;
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     windows.AppendElement(iter.Data());
   }
 
   // Get the IDs of all the "ghost" windows, and unlink them all.
   nsTHashtable<nsUint64HashKey> ghostWindows;
   sWindowReporter->CheckForGhostWindows(&ghostWindows);
   for (auto iter = ghostWindows.ConstIter(); !iter.Done(); iter.Next()) {
-    nsGlobalWindow::WindowByIdTable* windowsById =
-      nsGlobalWindow::GetWindowsTable();
+    nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+      nsGlobalWindowInner::GetWindowsTable();
     if (!windowsById) {
       continue;
     }
 
-    RefPtr<nsGlobalWindow> window = windowsById->Get(iter.Get()->GetKey());
+    RefPtr<nsGlobalWindowInner> window = windowsById->Get(iter.Get()->GetKey());
     if (window) {
       window->RiskyUnlink();
     }
   }
 }
 #endif
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -96,17 +96,17 @@ public:
   /**
    * Unlink all known ghost windows, to enable investigating what caused them
    * to become ghost windows in the first place.
    */
   static void UnlinkGhostWindows();
 #endif
 
   static nsWindowMemoryReporter* Get();
-  void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
+  void ObserveDOMWindowDetached(nsGlobalWindowInner* aWindow);
 
   static int64_t GhostWindowsDistinguishedAmount();
 
 private:
   ~nsWindowMemoryReporter();
 
   // Protect ctor, use Init() instead.
   nsWindowMemoryReporter();
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -290,17 +290,17 @@ nsWindowRoot::GetControllerForCommand(co
                                            getter_AddRefs(controller));
       if (controller) {
         controller.forget(_retval);
         return NS_OK;
       }
     }
 
     // XXXndeakin P3 is this casting safe?
-    nsGlobalWindow *win = nsGlobalWindow::Cast(focusedWindow);
+    nsGlobalWindowOuter *win = nsGlobalWindowOuter::Cast(focusedWindow);
     focusedWindow = win->GetPrivateParent();
   }
 
   return NS_OK;
 }
 
 void
 nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
@@ -362,17 +362,17 @@ nsWindowRoot::GetEnabledDisabledCommands
                                        getter_AddRefs(focusedWindow));
   while (focusedWindow) {
     focusedWindow->GetControllers(getter_AddRefs(controllers));
     if (controllers) {
       GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
                                                aEnabledCommands, aDisabledCommands);
     }
 
-    nsGlobalWindow* win = nsGlobalWindow::Cast(focusedWindow);
+    nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
     focusedWindow = win->GetPrivateParent();
   }
 }
 
 nsIDOMNode*
 nsWindowRoot::GetPopupNode()
 {
   nsCOMPtr<nsIDOMNode> popupNode = do_QueryReferent(mPopupNode);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2855,17 +2855,17 @@ HandlePrerenderingViolation(nsPIDOMWindo
 bool
 EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj)
 {
   JS::Rooted<JSObject*> thisObj(aCx, js::CheckedUnwrap(aObj));
   if (!thisObj) {
     // Without a this object, we cannot check the safety.
     return true;
   }
-  nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj);
+  nsGlobalWindowInner* window = xpc::WindowGlobalOrNull(thisObj);
   if (!window) {
     // Without a window, we cannot check the safety.
     return true;
   }
 
   if (window->GetIsPrerendered()) {
     HandlePrerenderingViolation(window->AsInner());
     // When the bindings layer sees a false return value, it returns false form
@@ -3146,17 +3146,17 @@ ConvertExceptionToPromise(JSContext* cx,
   }
 
   // Now make sure we rewrap promise back into the compartment we want
   return JS_WrapValue(cx, rval);
 }
 
 /* static */
 void
-CreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
+CreateGlobalOptions<nsGlobalWindowInner>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
 {
   xpc::TraceXPCGlobal(aTrc, aObj);
 }
 
 static bool sRegisteredDOMNames = false;
 
 nsresult
 RegisterDOMNames()
@@ -3176,18 +3176,18 @@ RegisterDOMNames()
 
   sRegisteredDOMNames = true;
 
   return NS_OK;
 }
 
 /* static */
 bool
-CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
-                                                      JS::Handle<JSObject*> aGlobal)
+CreateGlobalOptions<nsGlobalWindowInner>::PostCreateGlobal(JSContext* aCx,
+                                                           JS::Handle<JSObject*> aGlobal)
 {
   nsresult rv = RegisterDOMNames();
   if (NS_FAILED(rv)) {
     return Throw(aCx, rv);
   }
 
   // Invoking the XPCWrappedNativeScope constructor automatically hooks it
   // up to the compartment of aGlobal.
@@ -3529,17 +3529,17 @@ CustomElementReactionsStack*
 GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
 {
   // This might not be the right object, if there are wrappers. Unwrap if we can.
   JSObject* obj = js::CheckedUnwrap(aObj);
   if (!obj) {
     return nullptr;
   }
 
-  nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj);
+  nsGlobalWindowInner* window = xpc::WindowGlobalOrNull(obj);
   if (!window) {
     return nullptr;
   }
 
   DocGroup* docGroup = window->AsInner()->GetDocGroup();
   if (!docGroup) {
     return nullptr;
   }
@@ -3727,17 +3727,17 @@ AssertReflectorHasGivenProto(JSContext* 
              "How are we supposed to change the proto now?");
 }
 } // namespace binding_detail
 #endif // DEBUG
 
 void
 SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter)
 {
-  nsGlobalWindow* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
+  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
   if (win && win->GetDocument()) {
     win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
   }
 }
 
 namespace {
 
 // This runnable is used to write a deprecation message from a worker to the
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3092,17 +3092,17 @@ struct CreateGlobalOptions
   {
     MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
 
     return true;
   }
 };
 
 template <>
-struct CreateGlobalOptions<nsGlobalWindow>
+struct CreateGlobalOptions<nsGlobalWindowInner>
 {
   static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
     ProtoAndIfaceCache::WindowLike;
   static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 };
 
 nsresult
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1356,17 +1356,18 @@ DOMInterfaces = {
 'WebrtcGlobalInformation': {
     'nativeType': 'mozilla::dom::WebrtcGlobalInformation',
     'headerFile': 'WebrtcGlobalInformation.h',
     'wrapperCache': False,
     'concrete': False,
 },
 
 'Window': {
-    'nativeType': 'nsGlobalWindow',
+    'nativeType': 'nsGlobalWindowInner',
+    'headerFile': 'nsGlobalWindow.h',
     'binaryNames': {
         'postMessage': 'postMessageMoz',
     },
     'implicitJSContext': [
         'createImageBitmap',
         'requestIdleCallback'
     ],
 },
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -177,17 +177,17 @@ CallbackObject::CallSetup::CallSetup(Cal
           NS_LITERAL_CSTRING("Refusing to execute function from global in which "
                              "script is disabled."));
         return;
       }
     }
 
     // Now get the global for this callback. Note that for the case of
     // JS-implemented WebIDL we never have a window here.
-    nsGlobalWindow* win = mIsMainThread && !aIsJSImplementedWebIDL
+    nsGlobalWindowInner* win = mIsMainThread && !aIsJSImplementedWebIDL
                             ? xpc::WindowGlobalOrNull(realCallback)
                             : nullptr;
     if (win) {
       MOZ_ASSERT(win->IsInnerWindow());
       // We don't want to run script in windows that have been navigated away
       // from.
       if (!win->AsInner()->HasActiveDocument()) {
         aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -223,17 +223,17 @@ WebIDLGlobalNameHash::DefineIfEnabled(JS
   }
 
   {
     // It's safe to pass "&global" here, because we've already unwrapped it, but
     // for general sanity better to not have debug code even having the
     // appearance of mutating things that opt code uses.
 #ifdef DEBUG
     JS::Rooted<JSObject*> temp(aCx, global);
-    DebugOnly<nsGlobalWindow*> win;
+    DebugOnly<nsGlobalWindowInner*> win;
     MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, &temp, win)));
 #endif
   }
 
   if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
     return true;
   }
 
--- a/dom/bindings/nsScriptError.cpp
+++ b/dom/bindings/nsScriptError.cpp
@@ -56,18 +56,18 @@ nsScriptErrorBase::AddNote(nsIScriptErro
 
 void
 nsScriptErrorBase::InitializeOnMainThread()
 {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(!mInitializedOnMainThread);
 
     if (mInnerWindowID) {
-        nsGlobalWindow* window =
-          nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
+        nsGlobalWindowInner* window =
+          nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID);
         if (window) {
             nsPIDOMWindowOuter* outer = window->GetOuterWindow();
             if (outer)
                 mOuterWindowID = outer->WindowID();
 
             nsIDocShell* docShell = window->GetDocShell();
             nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5496,17 +5496,17 @@ CanvasRenderingContext2D::GetGlobalCompo
   else {
     aError.Throw(NS_ERROR_FAILURE);
   }
 
 #undef CANVAS_OP_TO_GFX_OP
 }
 
 void
-CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
+CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow, double aX,
                                      double aY, double aW, double aH,
                                      const nsAString& aBgColor,
                                      uint32_t aFlags, ErrorResult& aError)
 {
   MOZ_ASSERT(aWindow.IsInnerWindow());
 
   if (int32_t(aW) == 0 || int32_t(aH) == 0) {
     return;
@@ -6010,16 +6010,17 @@ CanvasRenderingContext2D::PutImageData_e
   // getImageData() and putImageData() methods.
   const gfx::Rect putRect(dirtyRect);
   EnsureTarget(&putRect);
 
   if (!IsTargetValid()) {
     return NS_ERROR_FAILURE;
   }
 
+  DataSourceSurface::MappedSurface map;
   RefPtr<DataSourceSurface> sourceSurface;
   uint8_t* lockedBits = nullptr;
   uint8_t* dstData;
   IntSize dstSize;
   int32_t dstStride;
   SurfaceFormat dstFormat;
   if (mTarget->LockBits(&lockedBits, &dstSize, &dstStride, &dstFormat)) {
     dstData = lockedBits + dirtyRect.y * dstStride + dirtyRect.x * 4;
@@ -6031,35 +6032,40 @@ CanvasRenderingContext2D::PutImageData_e
 
     // In certain scenarios, requesting larger than 8k image fails.  Bug 803568
     // covers the details of how to run into it, but the full detailed
     // investigation hasn't been done to determine the underlying cause.  We
     // will just handle the failure to allocate the surface to avoid a crash.
     if (!sourceSurface) {
       return NS_ERROR_FAILURE;
     }
-    dstData = sourceSurface->GetData();
+    if (!sourceSurface->Map(DataSourceSurface::READ_WRITE, &map)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    dstData = map.mData;
     if (!dstData) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    dstStride = sourceSurface->Stride();
+    dstStride = map.mStride;
     dstFormat = sourceSurface->GetFormat();
   }
 
   IntRect srcRect = dirtyRect - IntPoint(aX, aY);
   uint8_t* srcData = aArray->Data() + srcRect.y * (aW * 4) + srcRect.x * 4;
 
   PremultiplyData(srcData, aW * 4, SurfaceFormat::R8G8B8A8,
                   dstData, dstStride,
                   mOpaque ? SurfaceFormat::X8R8G8B8_UINT32 : SurfaceFormat::A8R8G8B8_UINT32,
                   dirtyRect.Size());
 
   if (lockedBits) {
     mTarget->ReleaseBits(lockedBits);
   } else if (sourceSurface) {
+    sourceSurface->Unmap();
     mTarget->CopySurface(sourceSurface, dirtyRect - dirtyRect.TopLeft(), dirtyRect.TopLeft());
   }
 
   Redraw(gfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
 
   return NS_OK;
 }
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -26,17 +26,17 @@
 #include "imgIEncoder.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/EnumeratedArray.h"
 #include "FilterSupport.h"
 #include "SVGObserverUtils.h"
 #include "Layers.h"
 #include "nsBidi.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 class nsXULElement;
 
 namespace mozilla {
 namespace gl {
 class SourceSurface;
 } // namespace gl
 
 namespace dom {
@@ -403,17 +403,17 @@ public:
 
   void SetImageSmoothingEnabled(bool aImageSmoothingEnabled) override
   {
     if (aImageSmoothingEnabled != CurrentState().imageSmoothingEnabled) {
       CurrentState().imageSmoothingEnabled = aImageSmoothingEnabled;
     }
   }
 
-  void DrawWindow(nsGlobalWindow& aWindow, double aX, double aY,
+  void DrawWindow(nsGlobalWindowInner& aWindow, double aX, double aY,
                   double aW, double aH,
                   const nsAString& aBgColor, uint32_t aFlags,
                   mozilla::ErrorResult& aError);
 
   enum RenderingMode {
     SoftwareBackendMode,
     OpenGLBackendMode,
     DefaultBackendMode
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -218,27 +218,29 @@ CreateImageFromRawData(const gfx::IntSiz
                              aBuffer, aBufferLength,
                              aCropRect);
 
   if (NS_WARN_IF(!rgbaSurface)) {
     return nullptr;
   }
 
   // Convert RGBA to BGRA
+  DataSourceSurface::MappedSurface rgbaMap;
   RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface();
+  if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap))) {
+    return nullptr;
+  }
+
   RefPtr<DataSourceSurface> bgraDataSurface =
     Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(),
                                                SurfaceFormat::B8G8R8A8,
-                                               rgbaDataSurface->Stride());
+                                               rgbaMap.mStride);
 
-  DataSourceSurface::MappedSurface rgbaMap;
   DataSourceSurface::MappedSurface bgraMap;
-
-  if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap)) ||
-      NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) {
+  if (NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) {
     return nullptr;
   }
 
   SwizzleData(rgbaMap.mData, rgbaMap.mStride, SurfaceFormat::R8G8B8A8,
               bgraMap.mData, bgraMap.mStride, SurfaceFormat::B8G8R8A8,
               bgraDataSurface->GetSize());
 
   rgbaDataSurface->Unmap();
--- a/dom/canvas/ImageUtils.cpp
+++ b/dom/canvas/ImageUtils.cpp
@@ -112,17 +112,18 @@ public:
   GetFormat() const
   {
     return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
   }
 
   virtual uint32_t
   GetBufferLength() const
   {
-    const uint32_t stride = Surface()->Stride();
+    DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ);
+    const uint32_t stride = map.GetStride();
     const IntSize size = Surface()->GetSize();
     return (uint32_t)(size.height * stride);
   }
 
   virtual UniquePtr<ImagePixelLayout>
   MapDataInto(uint8_t* aBuffer,
               uint32_t aOffset,
               uint32_t aBufferLength,
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -370,17 +370,17 @@ protected:
   void
   RunWithWindow(nsPIDOMWindowInner* aWindow)
   {
     AssertIsOnMainThread();
 
     AutoJSAPI jsapi;
     MOZ_ASSERT(aWindow);
 
-    RefPtr<nsGlobalWindow> win = nsGlobalWindow::Cast(aWindow);
+    RefPtr<nsGlobalWindowInner> win = nsGlobalWindowInner::Cast(aWindow);
     if (NS_WARN_IF(!jsapi.Init(win))) {
       return;
     }
 
     MOZ_ASSERT(aWindow->IsInnerWindow());
     nsPIDOMWindowOuter* outerWindow = aWindow->GetOuterWindow();
     if (NS_WARN_IF(!outerWindow)) {
       return;
@@ -1291,17 +1291,17 @@ Console::MethodInternal(JSContext* aCx, 
 
   DOMHighResTimeStamp monotonicTimer;
 
   // Monotonic timer for 'time' and 'timeEnd'
   if (aMethodName == MethodTime ||
       aMethodName == MethodTimeEnd ||
       aMethodName == MethodTimeStamp) {
     if (mWindow) {
-      nsGlobalWindow *win = nsGlobalWindow::Cast(mWindow);
+      nsGlobalWindowInner *win = nsGlobalWindowInner::Cast(mWindow);
       MOZ_ASSERT(win);
 
       RefPtr<Performance> performance = win->GetPerformance();
       if (!performance) {
         return;
       }
 
       monotonicTimer = performance->Now();
@@ -2453,17 +2453,17 @@ Console::GetConsoleInternal(const Global
   // Window
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindowInner> innerWindow =
       do_QueryInterface(aGlobal.GetAsSupports());
     if (NS_WARN_IF(!innerWindow)) {
       return nullptr;
     }
 
-    nsGlobalWindow* window = nsGlobalWindow::Cast(innerWindow);
+    nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(innerWindow);
     return window->GetConsole(aRv);
   }
 
   // Workers
   MOZ_ASSERT(!NS_IsMainThread());
 
   JSContext* cx = aGlobal.Context();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
--- a/dom/events/CompositionEvent.cpp
+++ b/dom/events/CompositionEvent.cpp
@@ -76,17 +76,17 @@ CompositionEvent::GetLocale(nsAString& a
 {
   aLocale = mLocale;
 }
 
 void
 CompositionEvent::InitCompositionEvent(const nsAString& aType,
                                        bool aCanBubble,
                                        bool aCancelable,
-                                       nsGlobalWindow* aView,
+                                       nsGlobalWindowInner* aView,
                                        const nsAString& aData,
                                        const nsAString& aLocale)
 {
   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
 
   UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);
   mData = aData;
   mLocale = aLocale;
--- a/dom/events/CompositionEvent.h
+++ b/dom/events/CompositionEvent.h
@@ -37,17 +37,17 @@ public:
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return CompositionEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   void InitCompositionEvent(const nsAString& aType,
                             bool aCanBubble,
                             bool aCancelable,
-                            nsGlobalWindow* aView,
+                            nsGlobalWindowInner* aView,
                             const nsAString& aData,
                             const nsAString& aLocale);
   void GetData(nsAString&) const;
   void GetLocale(nsAString&) const;
   void GetRanges(TextClauseArray& aRanges);
 
 protected:
   ~CompositionEvent() {}
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -85,17 +85,17 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEvent
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
                                                    LastRelease())
 
 NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
 
 DOMEventTargetHelper::~DOMEventTargetHelper()
 {
   if (nsPIDOMWindowInner* owner = GetOwner()) {
-    nsGlobalWindow::Cast(owner)->RemoveEventTargetObject(this);
+    nsGlobalWindowInner::Cast(owner)->RemoveEventTargetObject(this);
   }
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
   ReleaseWrapper(this);
 }
 
 void
@@ -106,53 +106,53 @@ DOMEventTargetHelper::BindToOwner(nsPIDO
 }
 
 void
 DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
 {
   nsCOMPtr<nsIGlobalObject> parentObject = do_QueryReferent(mParentObject);
   if (parentObject) {
     if (mOwnerWindow) {
-      nsGlobalWindow::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
+      nsGlobalWindowInner::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
       mOwnerWindow = nullptr;
     }
     mParentObject = nullptr;
     mHasOrHasHadOwnerWindow = false;
   }
   if (aOwner) {
     mParentObject = do_GetWeakReference(aOwner);
     MOZ_ASSERT(mParentObject, "All nsIGlobalObjects must support nsISupportsWeakReference");
     // Let's cache the result of this QI for fast access and off main thread usage
     mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(aOwner)).get();
     if (mOwnerWindow) {
       mHasOrHasHadOwnerWindow = true;
-      nsGlobalWindow::Cast(mOwnerWindow)->AddEventTargetObject(this);
+      nsGlobalWindowInner::Cast(mOwnerWindow)->AddEventTargetObject(this);
     }
   }
 }
 
 void
 DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
 {
   if (mOwnerWindow) {
-    nsGlobalWindow::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
+    nsGlobalWindowInner::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
     mOwnerWindow = nullptr;
     mParentObject = nullptr;
     mHasOrHasHadOwnerWindow = false;
   }
   if (aOther) {
     mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
     if (aOther->GetParentObject()) {
       mParentObject = do_GetWeakReference(aOther->GetParentObject());
       MOZ_ASSERT(mParentObject, "All nsIGlobalObjects must support nsISupportsWeakReference");
       // Let's cache the result of this QI for fast access and off main thread usage
       mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(aOther->GetParentObject())).get();
       if (mOwnerWindow) {
         mHasOrHasHadOwnerWindow = true;
-        nsGlobalWindow::Cast(mOwnerWindow)->AddEventTargetObject(this);
+        nsGlobalWindowInner::Cast(mOwnerWindow)->AddEventTargetObject(this);
       }
     }
   }
 }
 
 void
 DOMEventTargetHelper::DisconnectFromOwner()
 {
@@ -336,17 +336,17 @@ DOMEventTargetHelper::GetExistingListene
 nsIScriptContext*
 DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = CheckInnerWindowCorrectness();
   if (NS_FAILED(*aRv)) {
     return nullptr;
   }
   nsPIDOMWindowInner* owner = GetOwner();
-  return owner ? nsGlobalWindow::Cast(owner)->GetContextInternal()
+  return owner ? nsGlobalWindowInner::Cast(owner)->GetContextInternal()
                : nullptr;
 }
 
 nsresult
 DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
 {
   nsresult rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/events/DragEvent.cpp
+++ b/dom/events/DragEvent.cpp
@@ -36,17 +36,17 @@ NS_IMPL_RELEASE_INHERITED(DragEvent, Mou
 NS_INTERFACE_MAP_BEGIN(DragEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDragEvent)
 NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
 
 void
 DragEvent::InitDragEvent(const nsAString& aType,
                          bool aCanBubble,
                          bool aCancelable,
-                         nsGlobalWindow* aView,
+                         nsGlobalWindowInner* aView,
                          int32_t aDetail,
                          int32_t aScreenX,
                          int32_t aScreenY,
                          int32_t aClientX,
                          int32_t aClientY,
                          bool aCtrlKey,
                          bool aAltKey,
                          bool aShiftKey,
--- a/dom/events/DragEvent.h
+++ b/dom/events/DragEvent.h
@@ -35,17 +35,17 @@ public:
   {
     return DragEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   DataTransfer* GetDataTransfer();
 
   void InitDragEvent(const nsAString& aType,
                      bool aCanBubble, bool aCancelable,
-                     nsGlobalWindow* aView, int32_t aDetail,
+                     nsGlobalWindowInner* aView, int32_t aDetail,
                      int32_t aScreenX, int32_t aScreenY,
                      int32_t aClientX, int32_t aClientY,
                      bool aCtrlKey, bool aAltKey, bool aShiftKey,
                      bool aMetaKey, uint16_t aButton,
                      EventTarget* aRelatedTarget,
                      DataTransfer* aDataTransfer);
 
   static already_AddRefed<DragEvent> Constructor(const GlobalObject& aGlobal,
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -47,17 +47,17 @@ Event::Event(EventTarget* aOwner,
              nsPresContext* aPresContext,
              WidgetEvent* aEvent)
 {
   ConstructorInit(aOwner, aPresContext, aEvent);
 }
 
 Event::Event(nsPIDOMWindowInner* aParent)
 {
-  ConstructorInit(nsGlobalWindow::Cast(aParent), nullptr, nullptr);
+  ConstructorInit(nsGlobalWindowInner::Cast(aParent), nullptr, nullptr);
 }
 
 void
 Event::ConstructorInit(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetEvent* aEvent)
 {
   SetOwner(aOwner);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2079,17 +2079,18 @@ EventStateManager::GetContentViewer(nsIC
 
     nsCOMPtr<mozIDOMWindowProxy> activeWindow;
     fm->GetActiveWindow(getter_AddRefs(activeWindow));
     if (rootWindow != activeWindow) return NS_OK;
   } else {
     if (!tabChild->ParentIsActive()) return NS_OK;
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
+  nsCOMPtr<nsPIDOMWindowOuter> contentWindow =
+    nsGlobalWindowOuter::Cast(rootWindow)->GetContent();
   if (!contentWindow) return NS_ERROR_FAILURE;
 
   nsIDocument *doc = contentWindow->GetDoc();
   if (!doc) return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsISupports> container = doc->GetContainer();
   if (!container) return NS_ERROR_FAILURE;
 
--- a/dom/events/FocusEvent.cpp
+++ b/dom/events/FocusEvent.cpp
@@ -41,17 +41,17 @@ FocusEvent::GetRelatedTarget()
   return
     EnsureWebAccessibleRelatedTarget(mEvent->AsFocusEvent()->mRelatedTarget);
 }
 
 void
 FocusEvent::InitFocusEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            EventTarget* aRelatedTarget)
 {
   MOZ_ASSERT(!mEvent->mFlags.mIsBeingDispatched);
 
   UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
   mEvent->AsFocusEvent()->mRelatedTarget = aRelatedTarget;
 }
--- a/dom/events/FocusEvent.h
+++ b/dom/events/FocusEvent.h
@@ -40,17 +40,17 @@ public:
                                                   const FocusEventInit& aParam,
                                                   ErrorResult& aRv);
 protected:
   ~FocusEvent() {}
 
   void InitFocusEvent(const nsAString& aType,
                       bool aCanBubble,
                       bool aCancelable,
-                      nsGlobalWindow* aView,
+                      nsGlobalWindowInner* aView,
                       int32_t aDetail,
                       EventTarget* aRelatedTarget);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 already_AddRefed<mozilla::dom::FocusEvent>
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -340,17 +340,17 @@ KeyboardEvent::InitKeyEvent(const nsAStr
 
   return NS_OK;
 }
 
 void
 KeyboardEvent::InitKeyboardEvent(const nsAString& aType,
                                  bool aCanBubble,
                                  bool aCancelable,
-                                 nsGlobalWindow* aView,
+                                 nsGlobalWindowInner* aView,
                                  const nsAString& aKey,
                                  uint32_t aLocation,
                                  bool aCtrlKey,
                                  bool aAltKey,
                                  bool aShiftKey,
                                  bool aMetaKey,
                                  ErrorResult& aRv)
 {
--- a/dom/events/KeyboardEvent.h
+++ b/dom/events/KeyboardEvent.h
@@ -58,28 +58,28 @@ public:
   uint32_t KeyCode();
   virtual uint32_t Which() override;
   uint32_t Location();
 
   void GetCode(nsAString& aCode);
   void GetInitDict(KeyboardEventInit& aParam);
 
   void InitKeyEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
-                    nsGlobalWindow* aView, bool aCtrlKey, bool aAltKey,
+                    nsGlobalWindowInner* aView, bool aCtrlKey, bool aAltKey,
                     bool aShiftKey, bool aMetaKey,
                     uint32_t aKeyCode, uint32_t aCharCode)
   {
     auto* view = aView ? aView->AsInner() : nullptr;
     InitKeyEvent(aType, aCanBubble, aCancelable, view, aCtrlKey, aAltKey,
                  aShiftKey, aMetaKey, aKeyCode, aCharCode);
   }
 
   void InitKeyboardEvent(const nsAString& aType,
                          bool aCanBubble, bool aCancelable,
-                         nsGlobalWindow* aView, const nsAString& aKey,
+                         nsGlobalWindowInner* aView, const nsAString& aKey,
                          uint32_t aLocation, bool aCtrlKey, bool aAltKey,
                          bool aShiftKey, bool aMetaKey, ErrorResult& aRv);
 
 protected:
   ~KeyboardEvent() {}
 
   void InitWithKeyboardEventInit(EventTarget* aOwner,
                                  const nsAString& aType,
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -49,17 +49,17 @@ NS_IMPL_RELEASE_INHERITED(MouseEvent, UI
 NS_INTERFACE_MAP_BEGIN(MouseEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMouseEvent)
 NS_INTERFACE_MAP_END_INHERITING(UIEvent)
 
 void
 MouseEvent::InitMouseEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            int32_t aScreenX,
                            int32_t aScreenY,
                            int32_t aClientX,
                            int32_t aClientY,
                            bool aCtrlKey,
                            bool aAltKey,
                            bool aShiftKey,
@@ -111,31 +111,31 @@ MouseEvent::InitMouseEvent(const nsAStri
                            bool aCtrlKey,
                            bool aAltKey,
                            bool aShiftKey,
                            bool aMetaKey,
                            uint16_t aButton,
                            nsIDOMEventTarget* aRelatedTarget)
 {
   MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable,
-                             nsGlobalWindow::Cast(aView), aDetail,
+                             nsGlobalWindowInner::Cast(aView), aDetail,
                              aScreenX, aScreenY,
                              aClientX, aClientY,
                              aCtrlKey, aAltKey, aShiftKey,
                              aMetaKey, aButton,
                              static_cast<EventTarget *>(aRelatedTarget));
 
   return NS_OK;
 }
 
 void
 MouseEvent::InitMouseEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            int32_t aScreenX,
                            int32_t aScreenY,
                            int32_t aClientX,
                            int32_t aClientY,
                            int16_t aButton,
                            EventTarget* aRelatedTarget,
                            const nsAString& aModifiersList)
@@ -194,17 +194,17 @@ MouseEvent::Constructor(const GlobalObje
   e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 void
 MouseEvent::InitNSMouseEvent(const nsAString& aType,
                              bool aCanBubble,
                              bool aCancelable,
-                             nsGlobalWindow* aView,
+                             nsGlobalWindowInner* aView,
                              int32_t aDetail,
                              int32_t aScreenX,
                              int32_t aScreenY,
                              int32_t aClientX,
                              int32_t aClientY,
                              bool aCtrlKey,
                              bool aAltKey,
                              bool aShiftKey,
--- a/dom/events/MouseEvent.h
+++ b/dom/events/MouseEvent.h
@@ -53,17 +53,17 @@ public:
   bool ShiftKey();
   bool AltKey();
   bool MetaKey();
   int16_t Button();
   uint16_t Buttons();
   already_AddRefed<EventTarget> GetRelatedTarget();
   void GetRegion(nsAString& aRegion);
   void InitMouseEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
-                      nsGlobalWindow* aView, int32_t aDetail, int32_t aScreenX,
+                      nsGlobalWindowInner* aView, int32_t aDetail, int32_t aScreenX,
                       int32_t aScreenY, int32_t aClientX, int32_t aClientY,
                       bool aCtrlKey, bool aAltKey, bool aShiftKey,
                       bool aMetaKey, uint16_t aButton,
                       EventTarget* aRelatedTarget);
 
   void InitializeExtraMouseEventDictionaryMembers(const MouseEventInit& aParam);
 
   bool GetModifierState(const nsAString& aKeyArg)
@@ -82,31 +82,31 @@ public:
   {
     return GetMovementPoint().y;
   }
   float MozPressure() const;
   bool HitCluster() const;
   uint16_t MozInputSource() const;
   void InitNSMouseEvent(const nsAString& aType,
                         bool aCanBubble, bool aCancelable,
-                        nsGlobalWindow* aView, int32_t aDetail,
+                        nsGlobalWindowInner* aView, int32_t aDetail,
                         int32_t aScreenX, int32_t aScreenY,
                         int32_t aClientX, int32_t aClientY,
                         bool aCtrlKey, bool aAltKey, bool aShiftKey,
                         bool aMetaKey, uint16_t aButton,
                         EventTarget* aRelatedTarget,
                         float aPressure, uint16_t aInputSource);
 
 protected:
   ~MouseEvent() {}
 
   void InitMouseEvent(const nsAString& aType,
                       bool aCanBubble,
                       bool aCancelable,
-                      nsGlobalWindow* aView,
+                      nsGlobalWindowInner* aView,
                       int32_t aDetail,
                       int32_t aScreenX,
                       int32_t aScreenY,
                       int32_t aClientX,
                       int32_t aClientY,
                       int16_t aButton,
                       EventTarget* aRelatedTarget,
                       const nsAString& aModifiersList);
--- a/dom/events/MouseScrollEvent.cpp
+++ b/dom/events/MouseScrollEvent.cpp
@@ -37,17 +37,17 @@ NS_IMPL_RELEASE_INHERITED(MouseScrollEve
 
 NS_INTERFACE_MAP_BEGIN(MouseScrollEvent)
 NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
 
 void
 MouseScrollEvent::InitMouseScrollEvent(const nsAString& aType,
                                        bool aCanBubble,
                                        bool aCancelable,
-                                       nsGlobalWindow* aView,
+                                       nsGlobalWindowInner* aView,
                                        int32_t aDetail,
                                        int32_t aScreenX,
                                        int32_t aScreenY,
                                        int32_t aClientX,
                                        int32_t aClientY,
                                        bool aCtrlKey,
                                        bool aAltKey,
                                        bool aShiftKey,
--- a/dom/events/MouseScrollEvent.h
+++ b/dom/events/MouseScrollEvent.h
@@ -28,17 +28,17 @@ public:
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return MouseScrollEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   int32_t Axis();
 
   void InitMouseScrollEvent(const nsAString& aType, bool aCanBubble,
-                            bool aCancelable, nsGlobalWindow* aView,
+                            bool aCancelable, nsGlobalWindowInner* aView,
                             int32_t aDetail, int32_t aScreenX, int32_t aScreenY,
                             int32_t aClientX, int32_t aClientY,
                             bool aCtrlKey, bool aAltKey, bool aShiftKey,
                             bool aMetaKey, uint16_t aButton,
                             EventTarget* aRelatedTarget,
                             int32_t aAxis);
 
 protected:
--- a/dom/events/ScrollAreaEvent.cpp
+++ b/dom/events/ScrollAreaEvent.cpp
@@ -30,17 +30,17 @@ NS_IMPL_RELEASE_INHERITED(ScrollAreaEven
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScrollAreaEvent)
 NS_INTERFACE_MAP_END_INHERITING(UIEvent)
 
 void
 ScrollAreaEvent::InitScrollAreaEvent(const nsAString& aEventType,
                                      bool aCanBubble,
                                      bool aCancelable,
-                                     nsGlobalWindow* aView,
+                                     nsGlobalWindowInner* aView,
                                      int32_t aDetail,
                                      float aX,
                                      float aY,
                                      float aWidth,
                                      float aHeight)
 {
   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
 
--- a/dom/events/ScrollAreaEvent.h
+++ b/dom/events/ScrollAreaEvent.h
@@ -58,17 +58,17 @@ public:
   float Height() const
   {
     return mClientArea->Height();
   }
 
   void InitScrollAreaEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            float aX, float aY,
                            float aWidth, float aHeight);
 
 protected:
   ~ScrollAreaEvent() {}
 
   RefPtr<DOMRect> mClientArea;
--- a/dom/events/SimpleGestureEvent.cpp
+++ b/dom/events/SimpleGestureEvent.cpp
@@ -102,17 +102,17 @@ SimpleGestureEvent::GetClickCount(uint32
   *aClickCount = ClickCount();
   return NS_OK;
 }
 
 void
 SimpleGestureEvent::InitSimpleGestureEvent(const nsAString& aTypeArg,
                                            bool aCanBubbleArg,
                                            bool aCancelableArg,
-                                           nsGlobalWindow* aViewArg,
+                                           nsGlobalWindowInner* aViewArg,
                                            int32_t aDetailArg,
                                            int32_t aScreenX,
                                            int32_t aScreenY,
                                            int32_t aClientX,
                                            int32_t aClientY,
                                            bool aCtrlKeyArg,
                                            bool aAltKeyArg,
                                            bool aShiftKeyArg,
--- a/dom/events/SimpleGestureEvent.h
+++ b/dom/events/SimpleGestureEvent.h
@@ -40,17 +40,17 @@ public:
   uint32_t AllowedDirections();
   uint32_t Direction();
   double Delta();
   uint32_t ClickCount();
 
   void InitSimpleGestureEvent(const nsAString& aType,
                               bool aCanBubble,
                               bool aCancelable,
-                              nsGlobalWindow* aView,
+                              nsGlobalWindowInner* aView,
                               int32_t aDetail,
                               int32_t aScreenX,
                               int32_t aScreenY,
                               int32_t aClientX,
                               int32_t aClientY,
                               bool aCtrlKey,
                               bool aAltKey,
                               bool aShiftKey,
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -79,17 +79,17 @@ NS_INTERFACE_MAP_END_INHERITING(UIEvent)
 
 NS_IMPL_ADDREF_INHERITED(TouchEvent, UIEvent)
 NS_IMPL_RELEASE_INHERITED(TouchEvent, UIEvent)
 
 void
 TouchEvent::InitTouchEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            bool aCtrlKey,
                            bool aAltKey,
                            bool aShiftKey,
                            bool aMetaKey,
                            TouchList* aTouches,
                            TouchList* aTargetTouches,
                            TouchList* aChangedTouches)
@@ -166,17 +166,17 @@ TouchEvent::ChangedTouches()
 }
 
 // static
 bool
 TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
 {
   nsIDocShell* docShell = nullptr;
   if (aGlobal) {
-    nsGlobalWindow* win = xpc::WindowOrNull(aGlobal);
+    nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobal);
     if (win) {
       docShell = win->GetDocShell();
     }
   }
   return PrefEnabled(docShell);
 }
 
 // static
--- a/dom/events/TouchEvent.h
+++ b/dom/events/TouchEvent.h
@@ -102,17 +102,17 @@ public:
   bool AltKey();
   bool MetaKey();
   bool CtrlKey();
   bool ShiftKey();
 
   void InitTouchEvent(const nsAString& aType,
                       bool aCanBubble,
                       bool aCancelable,
-                      nsGlobalWindow* aView,
+                      nsGlobalWindowInner* aView,
                       int32_t aDetail,
                       bool aCtrlKey,
                       bool aAltKey,
                       bool aShiftKey,
                       bool aMetaKey,
                       TouchList* aTouches,
                       TouchList* aTargetTouches,
                       TouchList* aChangedTouches);
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -150,17 +150,17 @@ UIEvent::GetDetail(int32_t* aDetail)
   *aDetail = mDetail;
   return NS_OK;
 }
 
 void
 UIEvent::InitUIEvent(const nsAString& typeArg,
                      bool canBubbleArg,
                      bool cancelableArg,
-                     nsGlobalWindow* viewArg,
+                     nsGlobalWindowInner* viewArg,
                      int32_t detailArg)
 {
   auto* view = viewArg ? viewArg->AsInner() : nullptr;
   InitUIEvent(typeArg, canBubbleArg, cancelableArg, view, detailArg);
 }
 
 NS_IMETHODIMP
 UIEvent::InitUIEvent(const nsAString& typeArg,
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -49,17 +49,17 @@ public:
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return UIEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   void InitUIEvent(const nsAString& typeArg,
                    bool canBubbleArg,
                    bool cancelableArg,
-                   nsGlobalWindow* viewArg,
+                   nsGlobalWindowInner* viewArg,
                    int32_t detailArg);
 
   nsPIDOMWindowOuter* GetView() const
   {
     return mView;
   }
 
   int32_t Detail() const
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -41,17 +41,17 @@ NS_IMPL_RELEASE_INHERITED(WheelEvent, Mo
 
 NS_INTERFACE_MAP_BEGIN(WheelEvent)
 NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
 
 void
 WheelEvent::InitWheelEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
-                           nsGlobalWindow* aView,
+                           nsGlobalWindowInner* aView,
                            int32_t aDetail,
                            int32_t aScreenX,
                            int32_t aScreenY,
                            int32_t aClientX,
                            int32_t aClientY,
                            uint16_t aButton,
                            EventTarget* aRelatedTarget,
                            const nsAString& aModifiersList,
--- a/dom/events/WheelEvent.h
+++ b/dom/events/WheelEvent.h
@@ -42,17 +42,17 @@ public:
   //       if it's dispatched by widget)
   double DeltaX();
   double DeltaY();
   double DeltaZ();
   uint32_t DeltaMode();
 
   void
   InitWheelEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
-                 nsGlobalWindow* aView, int32_t aDetail,
+                 nsGlobalWindowInner* aView, int32_t aDetail,
                  int32_t aScreenX, int32_t aScreenY,
                  int32_t aClientX, int32_t aClientY, uint16_t aButton,
                  EventTarget* aRelatedTarget, const nsAString& aModifiersList,
                  double aDeltaX, double aDeltaY, double aDeltaZ,
                  uint32_t aDeltaMode);
 
 protected:
   ~WheelEvent() {}
--- a/dom/events/XULCommandEvent.cpp
+++ b/dom/events/XULCommandEvent.cpp
@@ -125,17 +125,17 @@ XULCommandEvent::InitCommandEvent(const 
                                   bool aAltKey,
                                   bool aShiftKey,
                                   bool aMetaKey,
                                   nsIDOMEvent* aSourceEvent,
                                   uint16_t aInputSource)
 {
   NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
 
-  auto* view = nsGlobalWindow::Cast(nsPIDOMWindowInner::From(aView));
+  auto* view = nsGlobalWindowInner::Cast(nsPIDOMWindowInner::From(aView));
   UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, view, aDetail);
 
   mEvent->AsInputEvent()->InitBasicModifiers(aCtrlKey, aAltKey,
                                              aShiftKey, aMetaKey);
   mSourceEvent = aSourceEvent;
   mInputSource = aInputSource;
 
   return NS_OK;
--- a/dom/events/XULCommandEvent.h
+++ b/dom/events/XULCommandEvent.h
@@ -46,17 +46,17 @@ public:
   {
     RefPtr<Event> e =
       mSourceEvent ? mSourceEvent->InternalDOMEvent() : nullptr;
     return e.forget();
   }
 
   void InitCommandEvent(const nsAString& aType,
                         bool aCanBubble, bool aCancelable,
-                        nsGlobalWindow* aView,
+                        nsGlobalWindowInner* aView,
                         int32_t aDetail,
                         bool aCtrlKey, bool aAltKey,
                         bool aShiftKey, bool aMetaKey,
                         Event* aSourceEvent,
                         uint16_t aInputSource)
   {
     InitCommandEvent(aType, aCanBubble, aCancelable, aView->AsInner(),
                      aDetail, aCtrlKey, aAltKey, aShiftKey, aMetaKey,
--- a/dom/flyweb/FlyWebPublishedServer.cpp
+++ b/dom/flyweb/FlyWebPublishedServer.cpp
@@ -135,17 +135,17 @@ FlyWebPublishedServer::OnWebSocketAccept
                               aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(provider);
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetOwner());
   AutoJSContext cx;
-  GlobalObject global(cx, nsGlobalWindow::Cast(window)->FastGetGlobalJSObject());
+  GlobalObject global(cx, nsGlobalWindowInner::Cast(window)->FastGetGlobalJSObject());
 
   nsAutoCString extensions, negotiatedExtensions;
   aConnectRequest->Headers()->
     GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv);
   mozilla::net::ProcessServerWebSocketExtensions(extensions,
                                                  negotiatedExtensions);
 
   nsCString url;
--- a/dom/flyweb/FlyWebService.cpp
+++ b/dom/flyweb/FlyWebService.cpp
@@ -63,17 +63,18 @@ public:
   {
     return mWindowID;
   }
 
   NS_IMETHOD Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+    nsGlobalWindowInner* globalWindow =
+      nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
     if (!globalWindow) {
       return Cancel();
     }
     mWindow = globalWindow->AsInner();
     if (NS_WARN_IF(!mWindow)) {
       return Cancel();
     }
 
--- a/dom/gamepad/GamepadManager.cpp
+++ b/dom/gamepad/GamepadManager.cpp
@@ -41,18 +41,18 @@ namespace mozilla {
 namespace dom {
 
 namespace {
 
 const char* kGamepadEnabledPref = "dom.gamepad.enabled";
 const char* kGamepadEventsEnabledPref =
   "dom.gamepad.non_standard_events.enabled";
 
-const nsTArray<RefPtr<nsGlobalWindow>>::index_type NoIndex =
-  nsTArray<RefPtr<nsGlobalWindow>>::NoIndex;
+const nsTArray<RefPtr<nsGlobalWindowInner>>::index_type NoIndex =
+  nsTArray<RefPtr<nsGlobalWindowInner>>::NoIndex;
 
 bool sShutdown = false;
 
 StaticRefPtr<GamepadManager> gGamepadManagerSingleton;
 const uint32_t VR_GAMEPAD_IDX_OFFSET = 0x01 << 16;
 
 } // namespace
 
@@ -127,17 +127,17 @@ GamepadManager::BeginShutdown()
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->SetHasGamepadEventListener(false);
   }
   mListeners.Clear();
   sShutdown = true;
 }
 
 void
-GamepadManager::AddListener(nsGlobalWindow* aWindow)
+GamepadManager::AddListener(nsGlobalWindowInner* aWindow)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
   MOZ_ASSERT(NS_IsMainThread());
 
   // IPDL child has not been created
   if (mChannelChildren.IsEmpty()) {
     PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
@@ -173,17 +173,17 @@ GamepadManager::AddListener(nsGlobalWind
   if (mListeners.IndexOf(aWindow) != NoIndex) {
     return; // already exists
   }
 
   mListeners.AppendElement(aWindow);
 }
 
 void
-GamepadManager::RemoveListener(nsGlobalWindow* aWindow)
+GamepadManager::RemoveListener(nsGlobalWindowInner* aWindow)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
   if (mShuttingDown) {
     // Doesn't matter at this point. It's possible we're being called
     // as a result of our own destructor here, so just bail out.
     return;
@@ -344,17 +344,17 @@ GamepadManager::NewConnectionEvent(uint3
 
   RefPtr<Gamepad> gamepad = GetGamepad(aIndex);
   if (!gamepad) {
     return;
   }
 
   // Hold on to listeners in a separate array because firing events
   // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
+  nsTArray<RefPtr<nsGlobalWindowInner>> listeners(mListeners);
 
   if (aConnected) {
     for (uint32_t i = 0; i < listeners.Length(); i++) {
 
       MOZ_ASSERT(listeners[i]->IsInnerWindow());
 
       // Only send events to non-background windows
       if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
@@ -463,36 +463,36 @@ GamepadManager::GetService()
 
 // static
 bool
 GamepadManager::IsAPIEnabled() {
   return Preferences::GetBool(kGamepadEnabledPref, false);
 }
 
 bool
-GamepadManager::MaybeWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex)
+GamepadManager::MaybeWindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex)
 {
   if (!WindowHasSeenGamepad(aWindow, aIndex)) {
     // This window hasn't seen this gamepad before, so
     // send a connection event first.
     SetWindowHasSeenGamepad(aWindow, aIndex);
     return true;
   }
   return false;
 }
 
 bool
-GamepadManager::WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex) const
+GamepadManager::WindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex) const
 {
   RefPtr<Gamepad> gamepad = aWindow->GetGamepad(aIndex);
   return gamepad != nullptr;
 }
 
 void
-GamepadManager::SetWindowHasSeenGamepad(nsGlobalWindow* aWindow,
+GamepadManager::SetWindowHasSeenGamepad(nsGlobalWindowInner* aWindow,
                                         uint32_t aIndex,
                                         bool aHasSeen)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
   if (mListeners.IndexOf(aWindow) == NoIndex) {
     // This window isn't even listening for gamepad events.
@@ -541,17 +541,17 @@ GamepadManager::Update(const GamepadChan
   }
 
   if (!SetGamepadByEvent(aEvent)) {
     return;
   }
 
   // Hold on to listeners in a separate array because firing events
   // can mutate the mListeners array.
-  nsTArray<RefPtr<nsGlobalWindow>> listeners(mListeners);
+  nsTArray<RefPtr<nsGlobalWindowInner>> listeners(mListeners);
 
   for (uint32_t i = 0; i < listeners.Length(); i++) {
     MOZ_ASSERT(listeners[i]->IsInnerWindow());
 
     // Only send events to non-background windows
     if (!listeners[i]->AsInner()->IsCurrentInnerWindow() ||
         listeners[i]->GetOuterWindow()->IsBackground()) {
       continue;
@@ -559,17 +559,17 @@ GamepadManager::Update(const GamepadChan
 
     SetGamepadByEvent(aEvent, listeners[i]);
     MaybeConvertToNonstandardGamepadEvent(aEvent, listeners[i]);
   }
 }
 
 void
 GamepadManager::MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
-                                                      nsGlobalWindow* aWindow)
+                                                      nsGlobalWindowInner* aWindow)
 {
   MOZ_ASSERT(aWindow);
 
   if (!mNonstandardEventsEnabled) {
     return;
   }
 
   const uint32_t index = GetGamepadIndexWithServiceType(aEvent.index(),
@@ -593,17 +593,17 @@ GamepadManager::MaybeConvertToNonstandar
       }
       default:
         break;
     }
   }
 }
 
 bool
-GamepadManager::SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindow *aWindow)
+GamepadManager::SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindowInner *aWindow)
 {
   bool ret = false;
   bool firstTime = false;
   const uint32_t index = GetGamepadIndexWithServiceType(aEvent.index(),
                                                         aEvent.service_type());
   if (aWindow) {
     firstTime = MaybeWindowHasSeenGamepad(aWindow, index);
   }
--- a/dom/gamepad/GamepadManager.h
+++ b/dom/gamepad/GamepadManager.h
@@ -7,17 +7,17 @@
 #ifndef mozilla_dom_GamepadManager_h_
 #define mozilla_dom_GamepadManager_h_
 
 #include "nsIObserver.h"
 // Needed for GamepadMappingType
 #include "mozilla/dom/GamepadBinding.h"
 #include "mozilla/dom/GamepadServiceType.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace gfx {
 class VRManagerChild;
 } // namespace gfx
 namespace dom {
 
 class EventTarget;
@@ -37,19 +37,19 @@ class GamepadManager final : public nsIO
   static already_AddRefed<GamepadManager> GetService();
   // Return true if the API is preffed on.
   static bool IsAPIEnabled();
 
   void BeginShutdown();
   void StopMonitoring();
 
   // Indicate that |aWindow| wants to receive gamepad events.
-  void AddListener(nsGlobalWindow* aWindow);
+  void AddListener(nsGlobalWindowInner* aWindow);
   // Indicate that |aWindow| should no longer receive gamepad events.
-  void RemoveListener(nsGlobalWindow* aWindow);
+  void RemoveListener(nsGlobalWindowInner* aWindow);
 
   // Add a gamepad to the list of known gamepads.
   void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping,
                   GamepadHand aHand, GamepadServiceType aServiceType, uint32_t aDisplayID,
                   uint32_t aNumButtons, uint32_t aNumAxes, uint32_t aNumHaptics);
 
   // Remove the gamepad at |aIndex| from the list of known gamepads.
   void RemoveGamepad(uint32_t aIndex, GamepadServiceType aServiceType);
@@ -111,38 +111,39 @@ class GamepadManager final : public nsIO
   // don't need to refcount it here.
   nsTArray<GamepadEventChannelChild *> mChannelChildren;
 
  private:
 
   nsresult Init();
 
   void MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
-                                             nsGlobalWindow* aWindow);
+                                             nsGlobalWindowInner* aWindow);
 
-  bool SetGamepadByEvent(const GamepadChangeEvent& aEvent, nsGlobalWindow* aWindow = nullptr);
+  bool SetGamepadByEvent(const GamepadChangeEvent& aEvent,
+                         nsGlobalWindowInner* aWindow = nullptr);
 
-  bool MaybeWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex);
+  bool MaybeWindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex);
   // Returns true if we have already sent data from this gamepad
   // to this window. This should only return true if the user
   // explicitly interacted with a gamepad while this window
   // was focused, by pressing buttons or similar actions.
-  bool WindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex) const;
+  bool WindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex) const;
   // Indicate that a window has received data from a gamepad.
-  void SetWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex,
+  void SetWindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex,
                                bool aHasSeen = true);
   // Our gamepad index has VR_GAMEPAD_IDX_OFFSET while GamepadChannelType
   // is from VRManager.
   uint32_t GetGamepadIndexWithServiceType(uint32_t aIndex, GamepadServiceType aServiceType);
 
   // Gamepads connected to the system. Copies of these are handed out
   // to each window.
   nsRefPtrHashtable<nsUint32HashKey, Gamepad> mGamepads;
   // Inner windows that are listening for gamepad events.
   // has been sent to that window.
-  nsTArray<RefPtr<nsGlobalWindow>> mListeners;
+  nsTArray<RefPtr<nsGlobalWindowInner>> mListeners;
   uint32_t mPromiseID;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GamepadManager_h_
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -1190,17 +1190,17 @@ Geolocation::ShouldBlockInsecureRequests
     return false;
   }
 
   nsCOMPtr<nsIDocument> doc = win->GetDoc();
   if (!doc) {
     return false;
   }
 
-  if (!nsGlobalWindow::Cast(win)->IsSecureContextIfOpenerIgnored()) {
+  if (!nsGlobalWindowInner::Cast(win)->IsSecureContextIfOpenerIgnored()) {
     nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
                                     NS_LITERAL_CSTRING("DOM"), doc,
                                     nsContentUtils::eDOM_PROPERTIES,
                                     "GeolocationInsecureRequestIsForbidden");
     return true;
   }
 
   return false;
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -343,30 +343,30 @@ HTMLBodyElement::AfterSetAttr(int32_t aN
 // nsGenericHTMLElement::GetOnError returns
 // already_AddRefed<EventHandlerNonNull> while other getters return
 // EventHandlerNonNull*, so allow passing in the type to use here.
 #define WINDOW_EVENT_HELPER(name_, type_)                                      \
   type_*                                                                       \
   HTMLBodyElement::GetOn##name_()                                              \
   {                                                                            \
     if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {              \
-      nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                   \
+      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);         \
       return globalWin->GetOn##name_();                                        \
     }                                                                          \
     return nullptr;                                                            \
   }                                                                            \
   void                                                                         \
   HTMLBodyElement::SetOn##name_(type_* handler)                                \
   {                                                                            \
     nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();                    \
     if (!win) {                                                                \
       return;                                                                  \
     }                                                                          \
                                                                                \
-    nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                     \
+    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);           \
     return globalWin->SetOn##name_(handler);                                   \
   }
 #define WINDOW_EVENT(name_, id_, type_, struct_)                               \
   WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                         \
   WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
 #include "mozilla/EventNameList.h" // IWYU pragma: keep
 #undef BEFOREUNLOAD_EVENT
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -314,30 +314,30 @@ HTMLFrameSetElement::IsEventAttributeNam
 // nsGenericHTMLElement::GetOnError returns
 // already_AddRefed<EventHandlerNonNull> while other getters return
 // EventHandlerNonNull*, so allow passing in the type to use here.
 #define WINDOW_EVENT_HELPER(name_, type_)                                      \
   type_*                                                                       \
   HTMLFrameSetElement::GetOn##name_()                                          \
   {                                                                            \
     if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {              \
-      nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                   \
+      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);         \
       return globalWin->GetOn##name_();                                        \
     }                                                                          \
     return nullptr;                                                            \
   }                                                                            \
   void                                                                         \
   HTMLFrameSetElement::SetOn##name_(type_* handler)                            \
   {                                                                            \
     nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();                    \
     if (!win) {                                                                \
       return;                                                                  \
     }                                                                          \
                                                                                \
-    nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                     \
+    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);           \
     return globalWin->SetOn##name_(handler);                                   \
   }
 #define WINDOW_EVENT(name_, id_, type_, struct_)                               \
   WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                         \
   WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
 #include "mozilla/EventNameList.h" // IWYU pragma: keep
 #undef BEFOREUNLOAD_EVENT
--- a/dom/html/TextTrackManager.cpp
+++ b/dom/html/TextTrackManager.cpp
@@ -633,17 +633,17 @@ private:
 void
 TextTrackManager::DispatchUpdateCueDisplay()
 {
   if (!mUpdateCueDisplayDispatched && !IsShutdown() &&
       (mMediaElement->GetHasUserInteraction() || mMediaElement->IsCurrentlyPlaying())) {
     WEBVTT_LOG("DispatchUpdateCueDisplay");
     nsPIDOMWindowInner* win = mMediaElement->OwnerDoc()->GetInnerWindow();
     if (win) {
-      nsGlobalWindow::Cast(win)->Dispatch(
+      nsGlobalWindowInner::Cast(win)->Dispatch(
         TaskCategory::Other,
         NewRunnableMethod("dom::TextTrackManager::UpdateCueDisplay",
                           this,
                           &TextTrackManager::UpdateCueDisplay));
       mUpdateCueDisplayDispatched = true;
     }
   }
 }
@@ -655,17 +655,17 @@ TextTrackManager::DispatchTimeMarchesOn(
   // enqueue the current playback position and whether only that changed
   // through its usual monotonic increase during normal playback; current
   // executing call upon completion will check queue for further 'work'.
   if (!mTimeMarchesOnDispatched && !IsShutdown() &&
       (mMediaElement->GetHasUserInteraction() || mMediaElement->IsCurrentlyPlaying())) {
     WEBVTT_LOG("DispatchTimeMarchesOn");
     nsPIDOMWindowInner* win = mMediaElement->OwnerDoc()->GetInnerWindow();
     if (win) {
-      nsGlobalWindow::Cast(win)->Dispatch(
+      nsGlobalWindowInner::Cast(win)->Dispatch(
         TaskCategory::Other,
         NewRunnableMethod("dom::TextTrackManager::TimeMarchesOn",
                           this,
                           &TextTrackManager::TimeMarchesOn));
       mTimeMarchesOnDispatched = true;
     }
   }
 }
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -842,47 +842,47 @@ nsGenericHTMLElement::GetEventListenerMa
 #define EVENT(name_, id_, type_, struct_) /* nothing; handled by nsINode */
 #define FORWARDED_EVENT(name_, id_, type_, struct_)                           \
 EventHandlerNonNull*                                                          \
 nsGenericHTMLElement::GetOn##name_()                                          \
 {                                                                             \
   if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) {            \
     /* XXXbz note to self: add tests for this! */                             \
     if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {             \
-      nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                  \
+      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);        \
       return globalWin->GetOn##name_();                                       \
     }                                                                         \
     return nullptr;                                                           \
   }                                                                           \
                                                                               \
   return nsINode::GetOn##name_();                                             \
 }                                                                             \
 void                                                                          \
 nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler)              \
 {                                                                             \
   if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) {            \
     nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();                   \
     if (!win) {                                                               \
       return;                                                                 \
     }                                                                         \
                                                                               \
-    nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                    \
+    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);          \
     return globalWin->SetOn##name_(handler);                                  \
   }                                                                           \
                                                                               \
   return nsINode::SetOn##name_(handler);                                      \
 }
 #define ERROR_EVENT(name_, id_, type_, struct_)                               \
 already_AddRefed<EventHandlerNonNull>                                         \
 nsGenericHTMLElement::GetOn##name_()                                          \
 {                                                                             \
   if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) {            \
     /* XXXbz note to self: add tests for this! */                             \
     if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) {             \
-      nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                  \
+      nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);        \
       OnErrorEventHandlerNonNull* errorHandler = globalWin->GetOn##name_();   \
       if (errorHandler) {                                                     \
         RefPtr<EventHandlerNonNull> handler =                                 \
           new EventHandlerNonNull(errorHandler);                              \
         return handler.forget();                                              \
       }                                                                       \
     }                                                                         \
     return nullptr;                                                           \
@@ -895,17 +895,17 @@ void                                    
 nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler)              \
 {                                                                             \
   if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) {            \
     nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();                   \
     if (!win) {                                                               \
       return;                                                                 \
     }                                                                         \
                                                                               \
-    nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win);                    \
+    nsGlobalWindowInner* globalWin = nsGlobalWindowInner::Cast(win);          \
     RefPtr<OnErrorEventHandlerNonNull> errorHandler;                          \
     if (handler) {                                                            \
       errorHandler = new OnErrorEventHandlerNonNull(handler);                 \
     }                                                                         \
     return globalWin->SetOn##name_(errorHandler);                             \
   }                                                                           \
                                                                               \
   return nsINode::SetOn##name_(handler);                                      \
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1473,17 +1473,17 @@ nsHTMLDocument::Open(JSContext* /* unuse
     return nullptr;
   }
   nsCOMPtr<nsPIDOMWindowOuter> outer =
     nsPIDOMWindowOuter::GetFromCurrentInner(window);
   if (!outer) {
     rv.Throw(NS_ERROR_NOT_INITIALIZED);
     return nullptr;
   }
-  RefPtr<nsGlobalWindow> win = nsGlobalWindow::Cast(outer);
+  RefPtr<nsGlobalWindowOuter> win = nsGlobalWindowOuter::Cast(outer);
   nsCOMPtr<nsPIDOMWindowOuter> newWindow;
   // XXXbz We ignore aReplace for now.
   rv = win->OpenJS(aURL, aName, aFeatures, getter_AddRefs(newWindow));
   return newWindow.forget();
 }
 
 already_AddRefed<nsIDocument>
 nsHTMLDocument::Open(JSContext* cx,
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -138,17 +138,17 @@ IDBFactory::CreateForWindow(nsPIDOMWindo
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
 
   RefPtr<IDBFactory> factory = new IDBFactory();
   factory->mPrincipalInfo = Move(principalInfo);
   factory->mWindow = aWindow;
   factory->mTabChild = TabChild::GetFrom(aWindow);
   factory->mEventTarget =
-    nsGlobalWindow::Cast(aWindow)->EventTargetFor(TaskCategory::Other);
+    nsGlobalWindowInner::Cast(aWindow)->EventTargetFor(TaskCategory::Other);
   factory->mInnerWindowID = aWindow->WindowID();
   factory->mPrivateBrowsingMode =
     loadContext && loadContext->UsePrivateBrowsing();
 
   factory.forget(aFactory);
   return NS_OK;
 }
 
@@ -736,17 +736,17 @@ IDBFactory::OpenInternal(JSContext* aCx,
       threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
     }
   }
 
   RefPtr<IDBOpenDBRequest> request;
 
   if (mWindow) {
     JS::Rooted<JSObject*> scriptOwner(aCx,
-                                      nsGlobalWindow::Cast(mWindow.get())->FastGetGlobalJSObject());
+                                      nsGlobalWindowInner::Cast(mWindow.get())->FastGetGlobalJSObject());
     MOZ_ASSERT(scriptOwner);
 
     request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner);
   } else {
     JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject);
 
     request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner);
     if (!request) {
--- a/dom/interfaces/base/nsIRemoteBrowser.idl
+++ b/dom/interfaces/base/nsIRemoteBrowser.idl
@@ -1,14 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
+interface nsIPrincipal;
+
 [scriptable, uuid(C8379366-F79F-4D25-89A6-22BEC0A93D16)]
 interface nsIRemoteBrowser : nsISupports
 {
   /*
    * Called by the child to inform the parent that a command update has occurred
    * and the supplied set of commands are now enabled and disabled.
    *
    * @param action command updater action
@@ -17,9 +19,11 @@ interface nsIRemoteBrowser : nsISupports
    * @param disabledLength length of disabledCommands array
    * @param disabledCommand commands to disable
    */
   void enableDisableCommands(in AString action,
                              in unsigned long enabledLength,
                              [array, size_is(enabledLength)] in string enabledCommands,
                              in unsigned long disabledLength,
                              [array, size_is(disabledLength)] in string disabledCommands);
+
+  readonly attribute nsIPrincipal contentPrincipal;
 };
deleted file mode 100644
--- a/dom/interfaces/json/moz.build
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-with Files("**"):
-    BUG_COMPONENT = ("Core", "JavaScript Engine")
-
-XPIDL_SOURCES += [
-    'nsIJSON.idl',
-]
-
-XPIDL_MODULE = 'dom_json'
-
deleted file mode 100644
--- a/dom/interfaces/json/nsIJSON.idl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-interface nsIInputStream;
-interface nsIScriptGlobalObject;
-
-[ptr] native JSValPtr(JS::Value);
-[ptr] native JSContext(JSContext);
-
-%{C++
-#include "js/TypeDecls.h"
-%}
-
-/**
- * Don't use this!  Use JSON.parse and JSON.stringify directly.
- */
-[scriptable, uuid(083aebb0-7790-43b2-ae81-9e404e626236)]
-interface nsIJSON : nsISupports
-{
-  [implicit_jscontext]
-  jsval decodeFromStream(in nsIInputStream stream,
-                         in long contentLength);
-
-  [noscript] AString  encodeFromJSVal(in JSValPtr value, in JSContext cx);
-
-  // Make sure you GCroot the result of this function before using it.
-  [noscript] jsval    decodeToJSVal(in AString str, in JSContext cx);
-};
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -544,24 +544,24 @@ NS_INTERFACE_MAP_BEGIN(ContentChild)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentChild)
 NS_INTERFACE_MAP_END
 
 
 mozilla::ipc::IPCResult
 ContentChild::RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
                                             const StructuredCloneData& aInitialData,
                                             nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
-                                            nsTArray<FontFamilyListEntry>&& aFontFamilyList)
+                                            nsTArray<SystemFontListEntry>&& aFontList)
 {
   if (!sShutdownCanary) {
     return IPC_OK();
   }
 
   mLookAndFeelCache = Move(aLookAndFeelIntCache);
-  mFontFamilies = Move(aFontFamilyList);
+  mFontList = Move(aFontList);
   gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
   InitXPCOM(aXPCOMInit, aInitialData);
   InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
 
   return IPC_OK();
 }
 
 bool
@@ -2537,16 +2537,24 @@ mozilla::ipc::IPCResult
 ContentChild::RecvUpdateDictionaryList(InfallibleTArray<nsString>&& aDictionaries)
 {
   mAvailableDictionaries = aDictionaries;
   mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+ContentChild::RecvUpdateFontList(InfallibleTArray<SystemFontListEntry>&& aFontList)
+{
+  mFontList = Move(aFontList);
+  gfxPlatform::GetPlatform()->UpdateFontList();
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 ContentChild::RecvUpdateAppLocales(nsTArray<nsCString>&& aAppLocales)
 {
   LocaleService::GetInstance()->AssignAppLocales(aAppLocales);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentChild::RecvUpdateRequestedLocales(nsTArray<nsCString>&& aRequestedLocales)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -394,16 +394,18 @@ public:
                                                    const ClonedMessageData& aData) override;
 
   virtual mozilla::ipc::IPCResult RecvGeolocationUpdate(const GeoPosition& somewhere) override;
 
   virtual mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode) override;
 
   virtual mozilla::ipc::IPCResult RecvUpdateDictionaryList(InfallibleTArray<nsString>&& aDictionaries) override;
 
+  virtual mozilla::ipc::IPCResult RecvUpdateFontList(InfallibleTArray<SystemFontListEntry>&& aFontList) override;
+
   virtual mozilla::ipc::IPCResult RecvUpdateAppLocales(nsTArray<nsCString>&& aAppLocales) override;
   virtual mozilla::ipc::IPCResult RecvUpdateRequestedLocales(nsTArray<nsCString>&& aRequestedLocales) override;
 
   virtual mozilla::ipc::IPCResult RecvAddPermission(const IPC::Permission& permission) override;
 
   virtual mozilla::ipc::IPCResult RecvFlushMemory(const nsString& reason) override;
 
   virtual mozilla::ipc::IPCResult RecvActivateA11y(const uint32_t& aMainChromeTid,
@@ -598,17 +600,17 @@ public:
           const bool& anonymize,
           const bool& minimizeMemoryUsage,
           const MaybeFileDesc& DMDFile) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
                                 const StructuredCloneData& aInitialData,
                                 nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
-                                nsTArray<FontFamilyListEntry>&& aFontFamilyList) override;
+                                nsTArray<SystemFontListEntry>&& aFontList) override;
 
   virtual mozilla::ipc::IPCResult
   RecvProvideAnonymousTemporaryFile(const uint64_t& aID, const FileDescOrError& aFD) override;
 
   mozilla::ipc::IPCResult
   RecvSetPermissionsWithKey(const nsCString& aPermissionKey,
                             nsTArray<IPC::Permission>&& aPerms) override;
 
@@ -636,21 +638,21 @@ public:
   virtual mozilla::ipc::IPCResult
   RecvAddDynamicScalars(nsTArray<DynamicScalarDefinition>&& aDefs) override;
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   bool
   SendGetA11yContentId();
 #endif // defined(XP_WIN) && defined(ACCESSIBILITY)
 
-  // Get a reference to the font family list passed from the chrome process,
+  // Get a reference to the font list passed from the chrome process,
   // for use during gfx initialization.
-  InfallibleTArray<mozilla::dom::FontFamilyListEntry>&
-  SystemFontFamilyList() {
-    return mFontFamilies;
+  InfallibleTArray<mozilla::dom::SystemFontListEntry>&
+  SystemFontList() {
+    return mFontList;
   }
 
   // PURLClassifierChild
   virtual PURLClassifierChild*
   AllocPURLClassifierChild(const Principal& aPrincipal,
                            const bool& aUseTrackingProtection,
                            bool* aSuccess) override;
   virtual bool
@@ -744,20 +746,20 @@ private:
 
   InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
   RefPtr<ConsoleListener> mConsoleListener;
 
   nsTHashtable<nsPtrHashKey<nsIObserver>> mIdleObservers;
 
   InfallibleTArray<nsString> mAvailableDictionaries;
 
-  // Temporary storage for a list of available font families, passed from the
+  // Temporary storage for a list of available fonts, passed from the
   // parent process and used to initialize gfx in the child. Currently used
-  // only on MacOSX.
-  InfallibleTArray<mozilla::dom::FontFamilyListEntry> mFontFamilies;
+  // only on MacOSX and Linux.
+  InfallibleTArray<mozilla::dom::SystemFontListEntry> mFontList;
   // Temporary storage for nsXPLookAndFeel flags.
   nsTArray<LookAndFeelInt> mLookAndFeelCache;
 
   /**
    * An ID unique to the process containing our corresponding
    * content parent.
    *
    * We expect our content parent to set this ID immediately after opening a
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -166,16 +166,17 @@
 #include "SourceSurfaceRawData.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "nsDocShell.h"
 #include "nsOpenURIInFrameParams.h"
 #include "mozilla/net/NeckoMessageUtils.h"
+#include "gfxPlatform.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
 #include "ContentProcessManager.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "nsPluginHost.h"
 #include "nsPluginTags.h"
@@ -2219,19 +2220,20 @@ ContentParent::InitInternal(ProcessPrior
       ErrorResult rv;
       initialData.Write(jsapi.cx(), init, rv);
       if (NS_WARN_IF(rv.Failed())) {
         rv.SuppressException();
         MOZ_CRASH();
       }
     }
   }
-  // This is only implemented (returns a non-empty list) by MacOSX at present.
-  nsTArray<FontFamilyListEntry> fontFamilies;
-  gfxPlatform::GetPlatform()->GetSystemFontFamilyList(&fontFamilies);
+  // This is only implemented (returns a non-empty list) by MacOSX and Linux
+  // at present.
+  nsTArray<SystemFontListEntry> fontList;
+  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
   nsTArray<LookAndFeelInt> lnfCache = LookAndFeel::GetIntCache();
 
   // Content processes have no permission to access profile directory, so we
   // send the file URL instead.
   StyleSheet* ucs = nsLayoutStylesheetCache::For(StyleBackendType::Gecko)->UserContentSheet();
   if (ucs) {
     SerializeURI(ucs->GetSheetURI(), xpcomInit.userContentSheetURL());
   } else {
@@ -2264,17 +2266,17 @@ ContentParent::InitInternal(ProcessPrior
   // Send the dynamic scalar definitions to the new process.
   TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
 
   // Must send screen info before send initialData
   ScreenManager& screenManager = ScreenManager::GetSingleton();
   screenManager.CopyScreensToRemote(this);
 
   Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache,
-                                          fontFamilies);
+                                          fontList);
 
   if (aSendRegisteredChrome) {
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryChrome* chromeRegistry =
       static_cast<nsChromeRegistryChrome*>(registrySvc.get());
     chromeRegistry->SendRegisteredChrome(this);
   }
 
@@ -4258,16 +4260,27 @@ ContentParent::NotifyUpdatedDictionaries
   InfallibleTArray<nsString> dictionaries;
   spellChecker->GetDictionaryList(&dictionaries);
 
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendUpdateDictionaryList(dictionaries);
   }
 }
 
+void
+ContentParent::NotifyUpdatedFonts()
+{
+  InfallibleTArray<SystemFontListEntry> fontList;
+  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
+
+  for (auto* cp : AllProcesses(eLive)) {
+    Unused << cp->SendUpdateFontList(fontList);
+  }
+}
+
 /*static*/ void
 ContentParent::UnregisterRemoteFrame(const TabId& aTabId,
                                const ContentParentId& aCpId,
                                bool aMarkedDestroying)
 {
   if (XRE_IsParentProcess()) {
     ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
     ContentParent* cp = cpm->GetContentProcessById(aCpId);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -264,16 +264,18 @@ public:
       sContentParents ? sContentParents->getFirst() : nullptr;
     return ContentParentIterator(aPolicy, first);
   }
 
   static bool IgnoreIPCPrincipal();
 
   static void NotifyUpdatedDictionaries();
 
+  static void NotifyUpdatedFonts();
+
 #if defined(XP_WIN)
   /**
    * Windows helper for firing off an update window request to a plugin
    * instance.
    *
    * aWidget - the eWindowType_plugin_ipc_chrome widget associated with
    *           this plugin window.
    */
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -127,16 +127,29 @@ struct FontListEntry {
 // from chrome to content processes.
 // The entryType field distinguishes several types of font family
 // record; see gfxMacPlatformFontList.h for values and meaning.
 struct FontFamilyListEntry {
     nsString familyName;
     uint8_t  entryType;
 };
 
+// Used on Linux to pass list of font patterns from chrome to content.
+struct FontPatternListEntry {
+    nsCString pattern;
+    bool      appFontFamily;
+};
+
+// Wrap the Font*ListEntry records in a union so the SetXPCOMProcessAttributes
+// message can pass an array of either type.
+union SystemFontListEntry {
+    FontFamilyListEntry;
+    FontPatternListEntry;
+};
+
 union PrefValue {
   nsCString;
   int32_t;
   bool;
 };
 
 union MaybePrefValue {
   PrefValue;
@@ -424,16 +437,18 @@ child:
     async NotifyAlertsObserver(nsCString topic, nsString data);
 
     async GeolocationUpdate(GeoPosition somewhere);
 
     async GeolocationError(uint16_t errorCode);
 
     async UpdateDictionaryList(nsString[] dictionaries);
 
+    async UpdateFontList(SystemFontListEntry[] fontList);
+
     async UpdateAppLocales(nsCString[] appLocales);
     async UpdateRequestedLocales(nsCString[] requestedLocales);
 
     // nsIPermissionManager messages
     async AddPermission(Permission permission);
 
     async FlushMemory(nsString reason);
 
@@ -471,18 +486,18 @@ child:
     /**
      * Send BlobURLRegistrationData to child process.
      */
     async InitBlobURLs(BlobURLRegistrationData[] registrations);
 
     async SetXPCOMProcessAttributes(XPCOMInitData xpcomInit,
                                     StructuredCloneData initialData,
                                     LookAndFeelInt[] lookAndFeelIntCache,
-                                    /* used on MacOSX only: */
-                                    FontFamilyListEntry[] fontFamilyList);
+                                    /* used on MacOSX and Linux only: */
+                                    SystemFontListEntry[] systemFontList);
 
     // Notify child that last-pb-context-exited notification was observed
     async LastPrivateDocShellDestroyed();
 
     async NotifyProcessPriorityChanged(ProcessPriority priority);
     async MinimizeMemoryUsage();
 
     /**
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2550,18 +2550,18 @@ TabChild::RecvSetUseGlobalHistory(const 
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvPrint(const uint64_t& aOuterWindowID, const PrintData& aPrintData)
 {
 #ifdef NS_PRINTING
-  nsGlobalWindow* outerWindow =
-    nsGlobalWindow::GetOuterWindowWithId(aOuterWindowID);
+  nsGlobalWindowOuter* outerWindow =
+    nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowID);
   if (NS_WARN_IF(!outerWindow)) {
     return IPC_OK();
   }
 
   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
     do_GetInterface(outerWindow->AsOuter());
   if (NS_WARN_IF(!webBrowserPrint)) {
     return IPC_OK();
deleted file mode 100644
--- a/dom/json/moz.build
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-with Files("**"):
-    BUG_COMPONENT = ("Core", "JavaScript Engine")
-
-EXPORTS += [
-    'nsJSON.h',
-]
-
-UNIFIED_SOURCES += [
-    'nsJSON.cpp',
-]
-
-LOCAL_INCLUDES += [
-    '/dom/base',
-]
-
-FINAL_LIBRARY = 'xul'
-
-XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
-MOCHITEST_MANIFESTS += ['test/mochitest.ini']
deleted file mode 100644
--- a/dom/json/nsJSON.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsJSON.h"
-
-#include "jsapi.h"
-#include "js/CharacterEncoding.h"
-#include "nsIXPConnect.h"
-#include "nsIXPCScriptable.h"
-#include "nsStreamUtils.h"
-#include "nsIInputStream.h"
-#include "nsStringStream.h"
-#include "nsNetUtil.h"
-#include "nsIURI.h"
-#include "nsComponentManagerUtils.h"
-#include "nsContentUtils.h"
-#include "nsIScriptError.h"
-#include "nsCRTGlue.h"
-#include "nsIScriptSecurityManager.h"
-#include "NullPrincipal.h"
-#include "mozilla/Maybe.h"
-#include <algorithm>
-
-using namespace mozilla;
-
-#define JSON_STREAM_BUFSIZE 4096
-
-NS_INTERFACE_MAP_BEGIN(nsJSON)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSON)
-  NS_INTERFACE_MAP_ENTRY(nsIJSON)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(nsJSON)
-NS_IMPL_RELEASE(nsJSON)
-
-nsJSON::nsJSON()
-{
-}
-
-nsJSON::~nsJSON()
-{
-}
-
-static bool
-WriteCallback(const char16_t *buf, uint32_t len, void *data)
-{
-  nsJSONWriter *writer = static_cast<nsJSONWriter*>(data);
-  nsresult rv =  writer->Write((const char16_t*)buf, (uint32_t)len);
-  if (NS_FAILED(rv))
-    return false;
-
-  return true;
-}
-
-NS_IMETHODIMP
-nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
-{
-  result.Truncate();
-
-  mozilla::Maybe<JSAutoCompartment> ac;
-  if (value->isObject()) {
-    JS::Rooted<JSObject*> obj(cx, &value->toObject());
-    ac.emplace(cx, obj);
-  }
-
-  nsJSONWriter writer;
-  JS::Rooted<JS::Value> vp(cx, *value);
-  if (!JS_Stringify(cx, &vp, nullptr, JS::NullHandleValue, WriteCallback, &writer)) {
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-  }
-  *value = vp;
-
-  NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
-  writer.FlushBuffer();
-  result.Assign(writer.mOutputString);
-  return NS_OK;
-}
-
-
-nsJSONWriter::nsJSONWriter() : mStream(nullptr),
-                               mBuffer(nullptr),
-                               mBufferCount(0),
-                               mDidWrite(false),
-                               mEncoder(nullptr)
-{
-}
-
-nsJSONWriter::nsJSONWriter(nsIOutputStream* aStream)
-  : mStream(aStream)
-  , mBuffer(nullptr)
-  , mBufferCount(0)
-  , mDidWrite(false)
-  , mEncoder(UTF_8_ENCODING->NewEncoder())
-{
-}
-
-nsJSONWriter::~nsJSONWriter()
-{
-  delete [] mBuffer;
-}
-
-nsresult
-nsJSONWriter::Write(const char16_t *aBuffer, uint32_t aLength)
-{
-  if (mStream) {
-    return WriteToStream(mStream, mEncoder.get(), aBuffer, aLength);
-  }
-
-  if (!mDidWrite) {
-    mBuffer = new char16_t[JSON_STREAM_BUFSIZE];
-    mDidWrite = true;
-  }
-
-  if (JSON_STREAM_BUFSIZE <= aLength + mBufferCount) {
-    mOutputString.Append(mBuffer, mBufferCount);
-    mBufferCount = 0;
-  }
-
-  if (JSON_STREAM_BUFSIZE <= aLength) {
-    // we know mBufferCount is 0 because we know we hit the if above
-    mOutputString.Append(aBuffer, aLength);
-  } else {
-    memcpy(&mBuffer[mBufferCount], aBuffer, aLength * sizeof(char16_t));
-    mBufferCount += aLength;
-  }
-
-  return NS_OK;
-}
-
-bool nsJSONWriter::DidWrite()
-{
-  return mDidWrite;
-}
-
-void
-nsJSONWriter::FlushBuffer()
-{
-  mOutputString.Append(mBuffer, mBufferCount);
-}
-
-nsresult
-nsJSONWriter::WriteToStream(nsIOutputStream* aStream,
-                            Encoder* encoder,
-                            const char16_t* aBuffer,
-                            uint32_t aLength)
-{
-  uint8_t buffer[1024];
-  auto dst = MakeSpan(buffer);
-  auto src = MakeSpan(aBuffer, aLength);
-
-  for (;;) {
-    uint32_t result;
-    size_t read;
-    size_t written;
-    bool hadErrors;
-    Tie(result, read, written, hadErrors) =
-      encoder->EncodeFromUTF16(src, dst, false);
-    Unused << hadErrors;
-    src = src.From(read);
-    uint32_t ignored;
-    nsresult rv =
-      aStream->Write(reinterpret_cast<const char*>(buffer), written, &ignored);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    if (result == kInputEmpty) {
-      mDidWrite = true;
-      return NS_OK;
-    }
-  }
-}
-
-NS_IMETHODIMP
-nsJSON::DecodeFromStream(nsIInputStream *aStream, int32_t aContentLength,
-                         JSContext* cx, JS::MutableHandle<JS::Value> aRetval)
-{
-  return DecodeInternal(cx, aStream, aContentLength, true, aRetval);
-}
-
-NS_IMETHODIMP
-nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx,
-                      JS::MutableHandle<JS::Value> result)
-{
-  if (!JS_ParseJSON(cx, static_cast<const char16_t*>(PromiseFlatString(str).get()),
-                    str.Length(), result)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-  return NS_OK;
-}
-
-nsresult
-nsJSON::DecodeInternal(JSContext* cx,
-                       nsIInputStream *aStream,
-                       int32_t aContentLength,
-                       bool aNeedsConverter,
-                       JS::MutableHandle<JS::Value> aRetval)
-{
-  // Consume the stream
-  nsCOMPtr<nsIChannel> jsonChannel;
-  if (!mURI) {
-    NS_NewURI(getter_AddRefs(mURI), NS_LITERAL_CSTRING("about:blank"), 0, 0 );
-    if (!mURI)
-      return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsresult rv;
-  nsCOMPtr<nsIPrincipal> nullPrincipal = NullPrincipal::Create();
-
-  // The ::Decode function is deprecated [Bug 675797] and the following
-  // channel is never openend, so it does not matter what securityFlags
-  // we pass to NS_NewInputStreamChannel here.
-  rv = NS_NewInputStreamChannel(getter_AddRefs(jsonChannel),
-                                mURI,
-                                aStream,
-                                nullPrincipal,
-                                nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
-                                nsIContentPolicy::TYPE_OTHER,
-                                NS_LITERAL_CSTRING("application/json"));
-
-  if (!jsonChannel || NS_FAILED(rv))
-    return NS_ERROR_FAILURE;
-
-  RefPtr<nsJSONListener> jsonListener =
-    new nsJSONListener(cx, aRetval.address(), aNeedsConverter);
-
-  //XXX this stream pattern should be consolidated in netwerk
-  rv = jsonListener->OnStartRequest(jsonChannel, nullptr);
-  if (NS_FAILED(rv)) {
-    jsonChannel->Cancel(rv);
-    return rv;
-  }
-
-  nsresult status;
-  jsonChannel->GetStatus(&status);
-  uint64_t offset = 0;
-  while (NS_SUCCEEDED(status)) {
-    uint64_t available;
-    rv = aStream->Available(&available);
-    if (rv == NS_BASE_STREAM_CLOSED) {
-      rv = NS_OK;
-      break;
-    }
-    if (NS_FAILED(rv)) {
-      jsonChannel->Cancel(rv);
-      break;
-    }
-    if (!available)
-      break; // blocking input stream has none available when done
-
-    if (available > UINT32_MAX)
-      available = UINT32_MAX;
-
-    rv = jsonListener->OnDataAvailable(jsonChannel, nullptr,
-                                       aStream,
-                                       offset,
-                                       (uint32_t)available);
-    if (NS_FAILED(rv)) {
-      jsonChannel->Cancel(rv);
-      break;
-    }
-
-    offset += available;
-    jsonChannel->GetStatus(&status);
-  }
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = jsonListener->OnStopRequest(jsonChannel, nullptr, status);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
-NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult)
-{
-  nsJSON* json = new nsJSON();
-  NS_ADDREF(json);
-  *aResult = json;
-
-  return NS_OK;
-}
-
-nsJSONListener::nsJSONListener(JSContext *cx, JS::Value *rootVal,
-                               bool needsConverter)
-  : mNeedsConverter(needsConverter),
-    mCx(cx),
-    mRootVal(rootVal)
-{
-}
-
-nsJSONListener::~nsJSONListener()
-{
-}
-
-NS_INTERFACE_MAP_BEGIN(nsJSONListener)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsJSONListener)
-  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
-  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(nsJSONListener)
-NS_IMPL_RELEASE(nsJSONListener)
-
-NS_IMETHODIMP
-nsJSONListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
-{
-  mDecoder = nullptr;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
-                              nsresult aStatusCode)
-{
-  JS::Rooted<JS::Value> reviver(mCx, JS::NullValue()), value(mCx);
-
-  JS::ConstTwoByteChars chars(reinterpret_cast<const char16_t*>(mBufferedChars.Elements()),
-                              mBufferedChars.Length());
-  bool ok = JS_ParseJSONWithReviver(mCx, chars.begin().get(),
-                                      uint32_t(mBufferedChars.Length()),
-                                      reviver, &value);
-
-  *mRootVal = value;
-  mBufferedChars.TruncateLength(0);
-  return ok ? NS_OK : NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-nsJSONListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
-                                nsIInputStream *aStream,
-                                uint64_t aOffset, uint32_t aLength)
-{
-  nsresult rv = NS_OK;
-
-  char buffer[JSON_STREAM_BUFSIZE];
-  unsigned long bytesRemaining = aLength;
-  while (bytesRemaining) {
-    unsigned int bytesRead;
-    rv = aStream->Read(buffer,
-                       std::min((unsigned long)sizeof(buffer), bytesRemaining),
-                       &bytesRead);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = ProcessBytes(buffer, bytesRead);
-    NS_ENSURE_SUCCESS(rv, rv);
-    bytesRemaining -= bytesRead;
-  }
-
-  return rv;
-}
-
-nsresult
-nsJSONListener::ProcessBytes(const char* aBuffer, uint32_t aByteLength)
-{
-  if (mNeedsConverter && !mDecoder) {
-    // BOM sniffing is built into the decoder.
-    mDecoder = UTF_8_ENCODING->NewDecoder();
-  }
-
-  if (!aBuffer)
-    return NS_OK;
-
-  nsresult rv;
-  if (mNeedsConverter) {
-    rv = ConsumeConverted(aBuffer, aByteLength);
-  } else {
-    uint32_t unichars = aByteLength / sizeof(char16_t);
-    rv = Consume((char16_t *) aBuffer, unichars);
-  }
-
-  return rv;
-}
-
-nsresult
-nsJSONListener::ConsumeConverted(const char* aBuffer, uint32_t aByteLength)
-{
-  CheckedInt<size_t> needed = mDecoder->MaxUTF16BufferLength(aByteLength);
-  if (!needed.isValid()) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  CheckedInt<size_t> total(needed);
-  total += mBufferedChars.Length();
-  if (!total.isValid()) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  char16_t* endelems = mBufferedChars.AppendElements(needed.value(), fallible);
-  if (!endelems) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  auto src = AsBytes(MakeSpan(aBuffer, aByteLength));
-  auto dst = MakeSpan(endelems, needed.value());
-  uint32_t result;
-  size_t read;
-  size_t written;
-  bool hadErrors;
-  // Ignoring EOF like the old code
-  Tie(result, read, written, hadErrors) =
-    mDecoder->DecodeToUTF16(src, dst, false);
-  MOZ_ASSERT(result == kInputEmpty);
-  MOZ_ASSERT(read == src.Length());
-  MOZ_ASSERT(written <= needed.value());
-  Unused << hadErrors;
-  mBufferedChars.TruncateLength(total.value() - (needed.value() - written));
-  return NS_OK;
-}
-
-nsresult
-nsJSONListener::Consume(const char16_t* aBuffer, uint32_t aByteLength)
-{
-  if (!mBufferedChars.AppendElements(aBuffer, aByteLength))
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/dom/json/nsJSON.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsJSON_h__
-#define nsJSON_h__
-
-#include "nsIJSON.h"
-#include "nsString.h"
-#include "nsCOMPtr.h"
-#include "nsIOutputStream.h"
-#include "mozilla/Encoding.h"
-#include "nsIRequestObserver.h"
-#include "nsIStreamListener.h"
-#include "nsTArray.h"
-
-class nsIURI;
-
-class MOZ_STACK_CLASS nsJSONWriter
-{
-public:
-  nsJSONWriter();
-  explicit nsJSONWriter(nsIOutputStream* aStream);
-  virtual ~nsJSONWriter();
-  nsCOMPtr<nsIOutputStream> mStream;
-  nsresult Write(const char16_t *aBuffer, uint32_t aLength);
-  nsString mOutputString;
-  bool DidWrite();
-  void FlushBuffer();
-
-protected:
-  char16_t *mBuffer;
-  uint32_t mBufferCount;
-  bool mDidWrite;
-  nsresult WriteToStream(nsIOutputStream* aStream,
-                         mozilla::Encoder* encoder,
-                         const char16_t* aBuffer,
-                         uint32_t aLength);
-
-  mozilla::UniquePtr<mozilla::Encoder> mEncoder;
-};
-
-class nsJSON final : public nsIJSON
-{
-public:
-  nsJSON();
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIJSON
-
-protected:
-  virtual ~nsJSON();
-
-  nsresult DecodeInternal(JSContext* cx,
-                          nsIInputStream* aStream,
-                          int32_t aContentLength,
-                          bool aNeedsConverter,
-                          JS::MutableHandle<JS::Value> aRetVal);
-  nsCOMPtr<nsIURI> mURI;
-};
-
-nsresult
-NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult);
-
-class nsJSONListener : public nsIStreamListener
-{
-public:
-  nsJSONListener(JSContext *cx, JS::Value *rootVal, bool needsConverter);
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIREQUESTOBSERVER
-  NS_DECL_NSISTREAMLISTENER
-
-protected:
-  virtual ~nsJSONListener();
-
-  bool mNeedsConverter;
-  JSContext *mCx;
-  JS::Value *mRootVal;
-  mozilla::UniquePtr<mozilla::Decoder> mDecoder;
-  nsTArray<char16_t> mBufferedChars;
-  nsresult ProcessBytes(const char* aBuffer, uint32_t aByteLength);
-  nsresult ConsumeConverted(const char* aBuffer, uint32_t aByteLength);
-  nsresult Consume(const char16_t *data, uint32_t len);
-};
-
-#endif
deleted file mode 100644
--- a/dom/json/test/mochitest.ini
+++ /dev/null
@@ -1,1 +0,0 @@
-[test_json.html]
deleted file mode 100644
--- a/dom/json/test/test_json.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=408838
--->
-<head>
-  <title>Test for Bug 408838</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408838">Mozilla Bug 408838</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-/** Test for Bug 408838 **/
-
-is(typeof JSON, "object", "JSON should be present");
-is(typeof JSON.parse, "function", "JSON.parse should be present");
-is(typeof JSON.stringify, "function", "JSON.stringify should be present");
-
-var str = '{"foo":[1,{"bar":"baz"}],"qux":1234.1234,"quux":[true,false,null,"hmm",9,[]]}';
-var x = JSON.parse(str);
-
-is(x.foo[0], 1, "JSON integer");
-is(x.foo[1].bar, "baz", "JSON string in object");
-is(x.qux, 1234.1234, "JSON float");
-
-var y = JSON.stringify(x);
-is(y, str, "JSON round trip");
-
-</script>
-</pre>
-</body>
-</html>
-
deleted file mode 100644
--- a/dom/json/test/unit/decodeFromStream-01.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "JSON Test Pattern pass3": {
-        "The outermost value": "must be an object or array.",
-        "In this test": "It is an object."
-    }
-}
-
deleted file mode 100644
--- a/dom/json/test/unit/decodeFromStream-small.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{}
\ No newline at end of file
deleted file mode 100644
--- a/dom/json/test/unit/test_decodeFromStream.js
+++ /dev/null
@@ -1,29 +0,0 @@
-var Ci = Components.interfaces;
-var Cc = Components.classes;
-
-var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
-
-function run_test()
-{
-  function read_file(path)
-  {
-    try
-    {
-      var f = do_get_file(path);
-      var istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
-      istream.init(f, -1, -1, false);
-      return nativeJSON.decodeFromStream(istream, istream.available());
-    }
-    finally
-    {
-      istream.close();
-    }
-  }
-
-  var x = read_file("decodeFromStream-01.json");
-  do_check_eq(x["JSON Test Pattern pass3"]["The outermost value"], "must be an object or array.");
-  do_check_eq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
-
-  x = read_file("decodeFromStream-small.json");
-  do_check_eq(x.toSource(), "({})", "empty object parsed");
-}
deleted file mode 100644
--- a/dom/json/test/unit/xpcshell.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[DEFAULT]
-head =
-support-files =
-  decodeFromStream-01.json
-  decodeFromStream-small.json
-
-[test_decodeFromStream.js]
-
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -412,17 +412,17 @@ public:
       MOZ_ASSERT(false, "MediaManager should stay until everything is removed");
       return;
     }
     GetUserMediaWindowListener* windowListener =
       mgr->GetWindowListener(mWindowID);
 
     if (!windowListener) {
       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-      auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+      auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
       if (globalWindow) {
         RefPtr<GetUserMediaRequest> req =
           new GetUserMediaRequest(globalWindow->AsInner(),
                                   VoidString(), VoidString());
         obs->NotifyObservers(req, "recording-device-stopped", nullptr);
       }
       return;
     }
@@ -467,17 +467,17 @@ public:
             revokeVideoPermission = false;
             break;
           }
         }
       }
 
       if (revokeVideoPermission) {
         nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-        auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+        auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
         nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner()
                                                   : nullptr;
         RefPtr<GetUserMediaRequest> req =
           new GetUserMediaRequest(window, removedRawId, removedSourceType);
         obs->NotifyObservers(req, "recording-device-stopped", nullptr);
       }
     }
 
@@ -495,17 +495,17 @@ public:
             revokeAudioPermission = false;
             break;
           }
         }
       }
 
       if (revokeAudioPermission) {
         nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-        auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+        auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
         nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner()
                                                   : nullptr;
         RefPtr<GetUserMediaRequest> req =
           new GetUserMediaRequest(window, removedRawId, removedSourceType);
         obs->NotifyObservers(req, "recording-device-stopped", nullptr);
       }
     }
 
@@ -663,17 +663,17 @@ public:
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
 
     // Only run if the window is still active.
     if (!(mManager->IsWindowStillActive(mWindowID))) {
       return NS_OK;
     }
     // This is safe since we're on main-thread, and the windowlist can only
     // be invalidated from the main-thread (see OnNavigation)
-    if (auto* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID)) {
+    if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
       RefPtr<MediaStreamError> error =
         new MediaStreamError(window->AsInner(), *mError);
       onFailure->OnError(error);
     }
     return NS_OK;
   }
 private:
   ~ErrorCallbackRunnable()
@@ -1036,17 +1036,17 @@ public:
     // DOMMediaStream::NotifyMediaStreamGraphShutdown is called.
     RefPtr<DOMMediaStream> mStream;
   };
 
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+    nsGlobalWindowInner* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
     nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner() : nullptr;
 
     // We're on main-thread, and the windowlist can only
     // be invalidated from the main-thread (see OnNavigation)
     GetUserMediaWindowListener* listener =
       mManager->GetWindowListener(mWindowID);
     if (!listener || !window || !window->GetExtantDoc()) {
       // This window is no longer live.  mListener has already been removed
@@ -1186,17 +1186,17 @@ public:
         domStream->AddTrackInternal(track);
       }
     }
 
     if (!domStream || !stream || sInShutdown) {
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
       LOG(("Returning error for getUserMedia() - no stream"));
 
-      if (auto* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID)) {
+      if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
         RefPtr<MediaStreamError> error = new MediaStreamError(window->AsInner(),
             NS_LITERAL_STRING("InternalError"),
             sInShutdown ? NS_LITERAL_STRING("In shutdown") :
                           NS_LITERAL_STRING("No stream."));
         onFailure->OnError(error);
       }
       return NS_OK;
     }
@@ -1584,17 +1584,17 @@ public:
     // We add a disabled listener to the StreamListeners array until accepted
     // If this was the only active MediaStream, remove the window from the list.
     if (NS_IsMainThread()) {
       // This is safe since we're on main-thread, and the window can only
       // be invalidated from the main-thread (see OnNavigation)
       nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget();
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
 
-      if (auto* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID)) {
+      if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
         RefPtr<MediaStreamError> error = new MediaStreamError(window->AsInner(),
                                                               aName, aMessage);
         onFailure->OnError(error);
       }
       // Should happen *after* error runs for consistency, but may not matter
       mWindowListener->Remove(mSourceListener);
     } else {
       // This will re-check the window being alive on main-thread
@@ -2090,23 +2090,22 @@ void MediaManager::OnDeviceChange() {
         if (!deviceIDs.Contains(id)) {
           deviceIDs.AppendElement(id);
         }
       }
 
       for (auto& id : self->mDeviceIDs) {
         if (!deviceIDs.Contains(id)) {
           // Stop the coresponding SourceListener
-          nsGlobalWindow::WindowByIdTable* windowsById = nsGlobalWindow::GetWindowsTable();
+          nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+            nsGlobalWindowInner::GetWindowsTable();
           if (windowsById) {
             for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
-              nsGlobalWindow* window = iter.Data();
-              if (window->IsInnerWindow()) {
-                self->IterateWindowListeners(window->AsInner(), StopRawIDCallback, &id);
-              }
+              nsGlobalWindowInner* window = iter.Data();
+              self->IterateWindowListeners(window->AsInner(), StopRawIDCallback, &id);
             }
           }
         }
       }
 
       self->mDeviceIDs = deviceIDs;
     }, [](MediaStreamError*& reason) {});
     return NS_OK;
@@ -2147,17 +2146,17 @@ static bool IsFullyActive(nsPIDOMWindowI
     nsPIDOMWindowOuter* context = aWindow->GetOuterWindow();
     if (!context) {
       return false;
     }
     if (context->IsTopLevelWindow()) {
       return true;
     }
     nsCOMPtr<Element> frameElement =
-      nsGlobalWindow::Cast(context)->GetRealFrameElementOuter();
+      nsGlobalWindowOuter::Cast(context)->GetRealFrameElementOuter();
     if (!frameElement) {
       return false;
     }
     aWindow = frameElement->OwnerDoc()->GetInnerWindow();
   }
 }
 
 enum class GetUserMediaSecurityState {
@@ -2263,17 +2262,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
     Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
                           (uint32_t) GetUserMediaSecurityState::Localhost);
   } else {
     Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
                           (uint32_t) GetUserMediaSecurityState::Other);
   }
 
   nsCOMPtr<nsIPrincipal> principal =
-    nsGlobalWindow::Cast(aWindow)->GetPrincipal();
+    nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
   if (NS_WARN_IF(!principal)) {
     return NS_ERROR_FAILURE;
   }
 
   // This principal needs to be sent to different threads and so via IPC.
   // For this reason it's better to convert it to PrincipalInfo right now.
   ipc::PrincipalInfo principalInfo;
   rv = PrincipalToPrincipalInfo(principal, &principalInfo);
@@ -2510,30 +2509,30 @@ MediaManager::GetUserMedia(nsPIDOMWindow
   RefPtr<MediaManager> self = this;
   p->Then([self, onSuccess, onFailure, windowID, c, windowListener,
            sourceListener, askPermission, prefs, isHTTPS, callID, principalInfo,
            isChrome](SourceSet*& aDevices) mutable {
     // grab result
     auto devices = MakeRefPtr<Refcountable<UniquePtr<SourceSet>>>(aDevices);
 
     // Ensure that our windowID is still good.
-    if (!nsGlobalWindow::GetInnerWindowWithId(windowID)) {
+    if (!nsGlobalWindowInner::GetInnerWindowWithId(windowID)) {
       return;
     }
 
     // Apply any constraints. This modifies the passed-in list.
     RefPtr<PledgeChar> p2 = self->SelectSettings(c, isChrome, devices);
 
     p2->Then([self, onSuccess, onFailure, windowID, c,
               windowListener, sourceListener, askPermission, prefs, isHTTPS,
               callID, principalInfo, isChrome, devices
              ](const char*& badConstraint) mutable {
 
       // Ensure that the captured 'this' pointer and our windowID are still good.
-      auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(windowID);
+      auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(windowID);
       RefPtr<nsPIDOMWindowInner> window = globalWindow ? globalWindow->AsInner()
                                                        : nullptr;
       if (!MediaManager::Exists() || !window) {
         return;
       }
 
       if (badConstraint) {
         nsString constraint;
@@ -2701,29 +2700,29 @@ MediaManager::ToJSArray(SourceSet& aDevi
 already_AddRefed<MediaManager::PledgeSourceSet>
 MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
                                    MediaSourceEnum aVideoType,
                                    MediaSourceEnum aAudioType,
                                    bool aFake)
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsPIDOMWindowInner* window =
-    nsGlobalWindow::GetInnerWindowWithId(aWindowId)->AsInner();
+    nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
 
   // This function returns a pledge, a promise-like object with the future result
   RefPtr<PledgeSourceSet> pledge = new PledgeSourceSet();
   uint32_t id = mOutstandingPledges.Append(*pledge);
 
   // To get a device list anonymized for a particular origin, we must:
   // 1. Get an origin-key (for either regular or private browsing)
   // 2. Get the raw devices list
   // 3. Anonymize the raw list with the origin-key.
 
   nsCOMPtr<nsIPrincipal> principal =
-    nsGlobalWindow::Cast(window)->GetPrincipal();
+    nsGlobalWindowInner::Cast(window)->GetPrincipal();
   MOZ_ASSERT(principal);
 
   ipc::PrincipalInfo principalInfo;
   nsresult rv = PrincipalToPrincipalInfo(principal, &principalInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     RefPtr<PledgeSourceSet> p = new PledgeSourceSet();
     RefPtr<MediaStreamError> error =
       new MediaStreamError(window, NS_LITERAL_STRING("NotAllowedError"));
@@ -2931,17 +2930,17 @@ MediaManager::OnNavigation(uint64_t aWin
     for (auto& callID : *callIDs) {
       mActiveCallbacks.Remove(callID);
     }
     mCallIds.Remove(aWindowID);
   }
 
   // This is safe since we're on main-thread, and the windowlist can only
   // be added to from the main-thread
-  auto* window = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
+  auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
   if (window) {
     IterateWindowListeners(window->AsInner(), StopSharingCallback, nullptr);
   } else {
     RemoveWindowID(aWindowID);
   }
   MOZ_ASSERT(!GetWindowListener(aWindowID));
 
   RemoveMediaDevicesCallback(aWindowID);
@@ -2984,17 +2983,17 @@ MediaManager::AddWindowID(uint64_t aWind
 }
 
 void
 MediaManager::RemoveWindowID(uint64_t aWindowId)
 {
   mActiveWindows.Remove(aWindowId);
 
   // get outer windowID
-  auto* window = nsGlobalWindow::GetInnerWindowWithId(aWindowId);
+  auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
   if (!window) {
     LOG(("No inner window for %" PRIu64, aWindowId));
     return;
   }
 
   nsPIDOMWindowOuter* outer = window->AsInner()->GetOuterWindow();
   if (!outer) {
     LOG(("No outer window for inner %" PRIu64, aWindowId));
@@ -3340,17 +3339,17 @@ MediaManager::GetActiveMediaCaptureWindo
   for (auto iter = mActiveWindows.Iter(); !iter.Done(); iter.Next()) {
     const uint64_t& id = iter.Key();
     RefPtr<GetUserMediaWindowListener> winListener = iter.UserData();
     if (!winListener) {
       continue;
     }
 
     nsPIDOMWindowInner* window =
-      nsGlobalWindow::GetInnerWindowWithId(id)->AsInner();
+      nsGlobalWindowInner::GetInnerWindowWithId(id)->AsInner();
     MOZ_ASSERT(window);
     // XXXkhuey ...
     if (!window) {
       continue;
     }
 
     if (winListener->CapturingVideo() || winListener->CapturingAudio() ||
         winListener->CapturingScreen() || winListener->CapturingWindow() ||
@@ -3464,17 +3463,17 @@ StopScreensharingCallback(MediaManager *
 }
 
 void
 MediaManager::StopScreensharing(uint64_t aWindowID)
 {
   // We need to stop window/screensharing for all streams in all innerwindows that
   // correspond to that outerwindow.
 
-  auto* window = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
+  auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
   if (!window) {
     return;
   }
   IterateWindowListeners(window->AsInner(), &StopScreensharingCallback, nullptr);
 }
 
 // lets us do all sorts of things to the listeners
 void
@@ -3544,17 +3543,17 @@ MediaManager::IsActivelyCapturingOrHasAP
                           getter_AddRefs(win));
     if (win && win->WindowID() == aWindowId) {
       return true;
     }
   }
 
   // Or are persistent permissions (audio or video) granted?
 
-  auto* window = nsGlobalWindow::GetInnerWindowWithId(aWindowId);
+  auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
   if (NS_WARN_IF(!window)) {
     return false;
   }
   // Check if this site has persistent permissions.
   nsresult rv;
   nsCOMPtr<nsIPermissionManager> mgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -3780,17 +3779,17 @@ SourceListener::StopSharing()
     // We want to stop the whole stream if there's no audio;
     // just the video track if we have both.
     // StopTrack figures this out for us.
     StopTrack(kVideoTrack);
   }
   if (mAudioDevice &&
       mAudioDevice->GetMediaSource() == MediaSourceEnum::AudioCapture) {
     uint64_t windowID = mWindowListener->WindowID();
-    nsCOMPtr<nsPIDOMWindowInner> window = nsGlobalWindow::GetInnerWindowWithId(windowID)->AsInner();
+    nsCOMPtr<nsPIDOMWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(windowID)->AsInner();
     MOZ_RELEASE_ASSERT(window);
     window->SetAudioCapture(false);
     MediaStreamGraph* graph =
       MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER, window);
     graph->UnregisterCaptureStreamForWindow(windowID);
     mStream->Destroy();
   }
 }
@@ -4044,17 +4043,17 @@ SourceListener::ApplyConstraintsToTrack(
       if (!mgr) {
         return NS_OK;
       }
       RefPtr<PledgeVoid> p = mgr->mOutstandingVoidPledges.Remove(id);
       if (p) {
         if (NS_SUCCEEDED(rv)) {
           p->Resolve(false);
         } else {
-          auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId);
+          auto* window = nsGlobalWindowInner::GetInnerWindowWithId(windowId);
           if (window) {
             if (badConstraint) {
               nsString constraint;
               constraint.AssignASCII(badConstraint);
               RefPtr<MediaStreamError> error =
                   new MediaStreamError(window->AsInner(),
                                        NS_LITERAL_STRING("OverconstrainedError"),
                                        NS_LITERAL_STRING(""),
@@ -4189,15 +4188,15 @@ GetUserMediaNotificationEvent::Run()
     msg = NS_LITERAL_STRING("starting");
     stream->OnTracksAvailable(mOnTracksAvailableCallback->release());
     break;
   case STOPPING:
     msg = NS_LITERAL_STRING("shutdown");
     break;
   }
 
-  RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+  RefPtr<nsGlobalWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
   return MediaManager::NotifyRecordingStatusChange(window->AsInner(), msg);
 }
 
 } // namespace mozilla
--- a/dom/media/TextTrack.cpp
+++ b/dom/media/TextTrack.cpp
@@ -331,17 +331,17 @@ TextTrack::GetLanguage(nsAString& aLangu
 void
 TextTrack::DispatchAsyncTrustedEvent(const nsString& aEventName)
 {
   nsPIDOMWindowInner* win = GetOwner();
   if (!win) {
     return;
   }
   RefPtr<TextTrack> self = this;
-  nsGlobalWindow::Cast(win)->Dispatch(
+  nsGlobalWindowInner::Cast(win)->Dispatch(
     TaskCategory::Other,
     NS_NewRunnableFunction(
       "dom::TextTrack::DispatchAsyncTrustedEvent",
       [self, aEventName]() { self->DispatchTrustedEvent(aEventName); }));
 }
 
 bool
 TextTrack::IsLoaded()
--- a/dom/media/TextTrackList.cpp
+++ b/dom/media/TextTrackList.cpp
@@ -188,17 +188,17 @@ TextTrackList::CreateAndDispatchChangeEv
 
     mPendingTextTrackChange = true;
     RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
     event->InitEvent(NS_LITERAL_STRING("change"), false, false);
     event->SetTrusted(true);
 
     nsCOMPtr<nsIRunnable> eventRunner = new ChangeEventRunner(this, event);
-    nsGlobalWindow::Cast(win)->Dispatch(TaskCategory::Other, eventRunner.forget());
+    nsGlobalWindowInner::Cast(win)->Dispatch(TaskCategory::Other, eventRunner.forget());
   }
 }
 
 void
 TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack,
                                                  const nsAString& aEventName)
 {
   DebugOnly<nsresult> rv;
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -947,68 +947,68 @@ skip-if = android_version == '17' # andr
 skip-if = android_version == '17' # android(bug 1232305)
 [test_paused_after_ended.html]
 skip-if = toolkit == 'android' # bug 1302613, android(bug 1232305)
 [test_play_events.html]
 skip-if = toolkit == 'android' # bug 1300330, android(bug 1232305)
 [test_play_events_2.html]
 skip-if = toolkit == 'android' # bug 1302614, bug 1328749, android(bug 1232305)
 [test_play_promise_1.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_2.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_3.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_4.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_5.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_6.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_7.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_8.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_9.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_10.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_11.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_12.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_13.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_14.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_15.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_16.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_17.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_promise_18.html]
-skip-if = android_version == '17' # bug 1392196
+skip-if = android_version == '17' || android_version == '23' # bug 1392196, bug 1415061
 tags=promise-play
 [test_play_twice.html]
 skip-if = appname == "seamonkey" || toolkit == 'android' #  Seamonkey: Bug 598252, bug 1307337, bug 1143695, android(bug 1232305)
 [test_playback.html]
 skip-if = toolkit == 'android' # bug 1316177
 [test_playback_errors.html]
 skip-if = android_version == '17' # bug 1340180, android(bug 1232305)
 [test_playback_rate.html]
@@ -1036,16 +1036,17 @@ skip-if = android_version == '25' && deb
 [test_replay_metadata.html]
 skip-if = toolkit == 'android' # bug 1311259, bug 1325994, android(bug 1232305)
 [test_reset_events_async.html]
 [test_reset_src.html]
 skip-if = toolkit == 'android' # android(bug 1232305)
 [test_video_dimensions.html]
 skip-if = toolkit == 'android' # bug 1298238, bug 1304535, android(bug 1232305)
 [test_resolution_change.html]
+skip-if = android_version == '19' # bug 1393866
 tags=capturestream
 [test_resume.html]
 skip-if = true # bug 1021673
 [test_seek_negative.html]
 skip-if = toolkit == 'android' # bug 1295443, bug 1306787, android(bug 1232305)
 [test_seek_nosrc.html]
 [test_seek_out_of_range.html]
 skip-if = toolkit == 'android' # bug 1299382, android(bug 1232305)
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -84,18 +84,18 @@ MediaEngineTabVideoSource::Notify(nsITim
   Draw();
   return NS_OK;
 }
 
 nsresult
 MediaEngineTabVideoSource::InitRunnable::Run()
 {
   if (mVideoSource->mWindowId != -1) {
-    nsGlobalWindow* globalWindow =
-      nsGlobalWindow::GetOuterWindowWithId(mVideoSource->mWindowId);
+    nsGlobalWindowOuter* globalWindow =
+      nsGlobalWindowOuter::GetOuterWindowWithId(mVideoSource->mWindowId);
     if (!globalWindow) {
       // We can't access the window, just send a blacked out screen.
       mVideoSource->mWindow = nullptr;
       mVideoSource->mBlackedoutWindow = true;
     } else {
       nsCOMPtr<nsPIDOMWindowOuter> window = globalWindow->AsOuter();
       if (window) {
         mVideoSource->mWindow = window;
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -24,17 +24,16 @@ interfaces = [
     'css',
     'traversal',
     'range',
     'xbl',
     'xpath',
     'xul',
     'security',
     'storage',
-    'json',
     'offline',
     'geolocation',
     'notification',
     'svg',
     'smil',
     'push',
     'payments',
 ]
@@ -60,17 +59,16 @@ DIRS += [
     'file',
     'filehandle',
     'filesystem',
     'flyweb',
     'gamepad',
     'geolocation',
     'grid',
     'html',
-    'json',
     'jsurl',
     'asmjscache',
     'mathml',
     'media',
     'notification',
     'offline',
     'power',
     'push',
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -139,18 +139,18 @@ PerformanceTiming::FetchStartHighRes()
   if (!mFetchStart) {
     if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return mZeroTime;
     }
     MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
         "valid if the performance timing is enabled");
     if (!mAsyncOpen.IsNull()) {
-      if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
-        mFetchStart = TimeStampToDOMHighRes(mWorkerStart);
+      if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
+        mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart);
       } else {
         mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
       }
     }
   }
   return mFetchStart;
 }
 
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -695,17 +695,17 @@ NPObject*
   // The window want to return here is the outer window, *not* the inner (since
   // we don't know what the plugin will do with it).
   nsIDocument* doc = GetDocumentFromNPP(npp);
   NS_ENSURE_TRUE(doc, nullptr);
   nsCOMPtr<nsPIDOMWindowOuter> outer = doc->GetWindow();
   NS_ENSURE_TRUE(outer, nullptr);
 
   JS::Rooted<JSObject*> global(dom::RootingCx(),
-                               nsGlobalWindow::Cast(outer)->GetGlobalJSObject());
+                               nsGlobalWindowOuter::Cast(outer)->GetGlobalJSObject());
   return nsJSObjWrapper::GetNewOrUsed(npp, global);
 }
 
 NPObject*
 _getpluginelement(NPP npp)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n"));
@@ -971,17 +971,17 @@ bool
   if (!npp)
     return false;
 
   NPPAutoPusher nppPusher(npp);
 
   nsIDocument *doc = GetDocumentFromNPP(npp);
   NS_ENSURE_TRUE(doc, false);
 
-  nsGlobalWindow* win = nsGlobalWindow::Cast(doc->GetInnerWindow());
+  nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(doc->GetInnerWindow());
   if (NS_WARN_IF(!win || !win->FastGetGlobalJSObject())) {
     return false;
   }
 
   nsAutoMicroTask mt;
   dom::AutoEntryScript aes(win, "NPAPI NPN_evaluate");
   JSContext* cx = aes.cx();
 
--- a/dom/presentation/PresentationRequest.cpp
+++ b/dom/presentation/PresentationRequest.cpp
@@ -183,17 +183,17 @@ PresentationRequest::StartWithDevice(con
     return promise.forget();
   }
 
   if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
-  RefPtr<Navigator> navigator = nsGlobalWindow::Cast(GetOwner())->Navigator();
+  RefPtr<Navigator> navigator = nsGlobalWindowInner::Cast(GetOwner())->Navigator();
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<Presentation> presentation = navigator->GetPresentation(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
@@ -483,17 +483,17 @@ void
 PresentationRequest::NotifyPromiseSettled()
 {
   PRES_DEBUG("%s\n", __func__);
 
   if (!GetOwner()) {
     return;
   }
 
-  RefPtr<Navigator> navigator = nsGlobalWindow::Cast(GetOwner())->Navigator();
+  RefPtr<Navigator> navigator = nsGlobalWindowInner::Cast(GetOwner())->Navigator();
   if (!navigator) {
     return;
   }
 
   ErrorResult rv;
   RefPtr<Presentation> presentation = navigator->GetPresentation(rv);
 
   if (presentation) {
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -1118,17 +1118,17 @@ PresentationService::UntrackSessionInfo(
     // Terminate receiver page.
     uint64_t windowId;
     nsresult rv = GetWindowIdBySessionIdInternal(aSessionId, aRole, &windowId);
     if (NS_SUCCEEDED(rv)) {
       NS_DispatchToMainThread(NS_NewRunnableFunction(
         "dom::PresentationService::UntrackSessionInfo", [windowId]() -> void {
           PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
 
-          if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
+          if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(windowId)) {
             window->Close();
           }
         }));
     }
 
     mSessionInfoAtReceiver.Remove(aSessionId);
   }
 
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -390,17 +390,17 @@ PresentationSessionInfo::GetWindow()
   }
   uint64_t windowId = 0;
   if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(mSessionId,
                                                            mRole,
                                                            &windowId)))) {
     return nullptr;
   }
 
-  auto window = nsGlobalWindow::GetInnerWindowWithId(windowId);
+  auto window = nsGlobalWindowInner::GetInnerWindowWithId(windowId);
   if (!window) {
     return nullptr;
   }
 
   return window->AsInner();
 }
 
 /* virtual */ bool
--- a/dom/presentation/ipc/PresentationBuilderChild.cpp
+++ b/dom/presentation/ipc/PresentationBuilderChild.cpp
@@ -42,17 +42,17 @@ nsresult PresentationBuilderChild::Init(
 
   if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(
                            mSessionId,
                            mRole,
                            &windowId)))) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsPIDOMWindowInner* window = nsGlobalWindow::GetInnerWindowWithId(windowId)->AsInner();
+  nsPIDOMWindowInner* window = nsGlobalWindowInner::GetInnerWindowWithId(windowId)->AsInner();
   if (NS_WARN_IF(!window)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mBuilder->BuildDataChannelTransport(mRole, window, this);
 }
 
 void
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -68,17 +68,17 @@ PresentationIPCService::StartSession(
 {
   if (aWindowId != 0) {
     AddRespondingSessionId(aWindowId,
                            aSessionId,
                            nsIPresentationService::ROLE_CONTROLLER);
   }
 
   nsPIDOMWindowInner* window =
-    nsGlobalWindow::GetInnerWindowWithId(aWindowId)->AsInner();
+    nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
   TabId tabId = TabParent::GetTabIdFrom(window->GetDocShell());
 
   return SendRequest(aCallback, StartSessionRequest(aUrls,
                                                     nsString(aSessionId),
                                                     nsString(aOrigin),
                                                     nsString(aDeviceId),
                                                     aWindowId,
                                                     tabId,
@@ -485,17 +485,17 @@ PresentationIPCService::UntrackSessionIn
     if (NS_SUCCEEDED(GetWindowIdBySessionIdInternal(aSessionId,
                                                     aRole,
                                                     &windowId))) {
       NS_DispatchToMainThread(NS_NewRunnableFunction(
         "dom::PresentationIPCService::UntrackSessionInfo",
         [windowId]() -> void {
           PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
 
-          if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
+          if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(windowId)) {
             window->Close();
           }
         }));
     }
   }
 
   // Remove the OOP responding info (if it has never been used).
   RemoveRespondingSessionId(aSessionId, aRole);
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -492,17 +492,19 @@ Promise::ReportRejectedPromise(JSContext
     JS_ClearPendingException(aCx);
     return;
   }
 
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   bool isMainThread = MOZ_LIKELY(NS_IsMainThread());
   bool isChrome = isMainThread ? nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(aPromise))
                                : GetCurrentThreadWorkerPrivate()->IsChromeWorker();
-  nsGlobalWindow* win = isMainThread ? xpc::WindowGlobalOrNull(aPromise) : nullptr;
+  nsGlobalWindowInner* win = isMainThread
+    ? xpc::WindowGlobalOrNull(aPromise)
+    : nullptr;
   xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
                   win ? win->AsInner()->WindowID() : 0);
 
   // Now post an event to do the real reporting async
   NS_DispatchToMainThread(new AsyncErrorReporter(xpcReport));
 }
 
 bool
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -500,33 +500,33 @@ bool
 AutoJSAPI::Init(JSObject* aObject)
 {
   return Init(xpc::NativeGlobal(aObject));
 }
 
 bool
 AutoJSAPI::Init(nsPIDOMWindowInner* aWindow, JSContext* aCx)
 {
-  return Init(nsGlobalWindow::Cast(aWindow), aCx);
+  return Init(nsGlobalWindowInner::Cast(aWindow), aCx);
 }
 
 bool
 AutoJSAPI::Init(nsPIDOMWindowInner* aWindow)
 {
-  return Init(nsGlobalWindow::Cast(aWindow));
+  return Init(nsGlobalWindowInner::Cast(aWindow));
 }
 
 bool
-AutoJSAPI::Init(nsGlobalWindow* aWindow, JSContext* aCx)
+AutoJSAPI::Init(nsGlobalWindowInner* aWindow, JSContext* aCx)
 {
   return Init(static_cast<nsIGlobalObject*>(aWindow), aCx);
 }
 
 bool
-AutoJSAPI::Init(nsGlobalWindow* aWindow)
+AutoJSAPI::Init(nsGlobalWindowInner* aWindow)
 {
   return Init(static_cast<nsIGlobalObject*>(aWindow));
 }
 
 // Even with autoJSAPIOwnsErrorReporting, the JS engine still sends warning
 // reports to the JSErrorReporter as soon as they are generated. These go
 // directly to the console, so we can handle them easily here.
 //
@@ -547,17 +547,17 @@ WarningOnlyErrorReporter(JSContext* aCx,
     workers::WorkerPrivate* worker = workers::GetWorkerPrivateFromContext(aCx);
     MOZ_ASSERT(worker);
 
     worker->ReportError(aCx, JS::ConstUTF8CharsZ(), aRep);
     return;
   }
 
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
-  nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx);
+  nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aCx);
   if (!win) {
     // We run addons in a separate privileged compartment, but if we're in an
     // addon compartment we should log warnings to the console of the associated
     // DOM Window.
     win = xpc::AddonWindowOrNull(JS::CurrentGlobalOrNull(aCx));
   }
   xpcReport->Init(aRep, nullptr, nsContentUtils::IsSystemCaller(aCx),
                   win ? win->AsInner()->WindowID() : 0);
@@ -587,17 +587,17 @@ AutoJSAPI::ReportException()
   JSAutoCompartment ac(cx(), errorGlobal);
   JS::Rooted<JS::Value> exn(cx());
   js::ErrorReport jsReport(cx());
   if (StealException(&exn) &&
       jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
     if (mIsMainThread) {
       RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
 
-      RefPtr<nsGlobalWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
+      RefPtr<nsGlobalWindowInner> win = xpc::WindowGlobalOrNull(errorGlobal);
       if (!win) {
         // We run addons in a separate privileged compartment, but they still
         // expect to trigger the onerror handler of their associated DOM Window.
         win = xpc::AddonWindowOrNull(errorGlobal);
       }
       nsPIDOMWindowInner* inner = win ? win->AsInner() : nullptr;
       bool isChrome = nsContentUtils::IsSystemPrincipal(
         nsContentUtils::ObjectPrincipal(errorGlobal));
--- a/dom/script/ScriptSettings.h
+++ b/dom/script/ScriptSettings.h
@@ -14,17 +14,17 @@
 #include "nsIPrincipal.h"
 
 #include "mozilla/Maybe.h"
 
 #include "jsapi.h"
 #include "js/Debug.h"
 
 class nsPIDOMWindowInner;
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 class nsIScriptContext;
 class nsIDocument;
 class nsIDocShell;
 
 namespace mozilla {
 namespace dom {
 
 /*
@@ -241,18 +241,18 @@ public:
   // show up in the corresponding web console.
   MOZ_MUST_USE bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
 
   // Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
   // when it is more easily available than an nsIGlobalObject.
   MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow);
   MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
 
-  MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow);
-  MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
+  MOZ_MUST_USE bool Init(nsGlobalWindowInner* aWindow);
+  MOZ_MUST_USE bool Init(nsGlobalWindowInner* aWindow, JSContext* aCx);
 
   JSContext* cx() const {
     MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
     MOZ_ASSERT(IsStackTop());
     return mCx;
   }
 
 #ifdef DEBUG
--- a/dom/smil/TimeEvent.cpp
+++ b/dom/smil/TimeEvent.cpp
@@ -48,17 +48,17 @@ NS_INTERFACE_MAP_END_INHERITING(Event)
 NS_IMETHODIMP
 TimeEvent::GetDetail(int32_t* aDetail)
 {
   *aDetail = mDetail;
   return NS_OK;
 }
 
 void
-TimeEvent::InitTimeEvent(const nsAString& aType, nsGlobalWindow* aView,
+TimeEvent::InitTimeEvent(const nsAString& aType, nsGlobalWindowInner* aView,
                          int32_t aDetail)
 {
   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
 
   Event::InitEvent(aType, false /*doesn't bubble*/, false /*can't cancel*/);
   mDetail = aDetail;
   mView = aView ? aView->GetOuterWindow() : nullptr;
 }
--- a/dom/smil/TimeEvent.h
+++ b/dom/smil/TimeEvent.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_TimeEvent_h_
 #define mozilla_dom_TimeEvent_h_
 
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TimeEventBinding.h"
 #include "nsIDOMTimeEvent.h"
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class TimeEvent final : public Event,
                         public nsIDOMTimeEvent
 {
 public:
@@ -34,17 +34,17 @@ public:
   // Forward to base class
   NS_FORWARD_TO_EVENT
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return TimeEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
-  void InitTimeEvent(const nsAString& aType, nsGlobalWindow* aView,
+  void InitTimeEvent(const nsAString& aType, nsGlobalWindowInner* aView,
                      int32_t aDetail);
 
 
   int32_t Detail() const
   {
     return mDetail;
   }
 
--- a/dom/vr/VREventObserver.cpp
+++ b/dom/vr/VREventObserver.cpp
@@ -17,17 +17,17 @@ namespace dom {
 
 using namespace gfx;
 
 /**
  * This class is used by nsGlobalWindow to implement window.onvrdisplayactivate,
  * window.onvrdisplaydeactivate, window.onvrdisplayconnected,
  * window.onvrdisplaydisconnected, and window.onvrdisplaypresentchange.
  */
-VREventObserver::VREventObserver(nsGlobalWindow* aGlobalWindow)
+VREventObserver::VREventObserver(nsGlobalWindowInner* aGlobalWindow)
   : mWindow(aGlobalWindow)
   , mIs2DView(true)
   , mHasReset(false)
 {
   MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow());
 
   UpdateSpentTimeIn2DTelemetry(false);
   VRManagerChild* vmc = VRManagerChild::Get();
--- a/dom/vr/VREventObserver.h
+++ b/dom/vr/VREventObserver.h
@@ -5,42 +5,42 @@
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_VREventObserver_h
 #define mozilla_dom_VREventObserver_h
 
 #include "mozilla/dom/VRDisplayEventBinding.h"
 #include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
 
-class nsGlobalWindow;
+class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class VREventObserver final
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(VREventObserver)
-  explicit VREventObserver(nsGlobalWindow* aGlobalWindow);
+  explicit VREventObserver(nsGlobalWindowInner* aGlobalWindow);
 
   void NotifyVRDisplayMounted(uint32_t aDisplayID);
   void NotifyVRDisplayUnmounted(uint32_t aDisplayID);
   void NotifyVRDisplayNavigation(uint32_t aDisplayID);
   void NotifyVRDisplayRequested(uint32_t aDisplayID);
   void NotifyVRDisplayConnect(uint32_t aDisplayID);
   void NotifyVRDisplayDisconnect(uint32_t aDisplayID);
   void NotifyVRDisplayPresentChange(uint32_t aDisplayID);
 
   void DisconnectFromOwner();
   void UpdateSpentTimeIn2DTelemetry(bool aUpdate);
 
 private:
   ~VREventObserver();
 
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowInner> mWindow;
   // For WebVR telemetry for tracking users who view content
   // in the 2D view.
   TimeStamp mSpendTimeIn2DView;
   bool mIs2DView;
   bool mHasReset;
 };
 
 } // namespace dom
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -38,17 +38,18 @@ ServiceWorkerClientInfo::ServiceWorkerCl
   , mFrameType(FrameType::None)
 {
   MOZ_ASSERT(aDoc);
   nsresult rv = aDoc->GetOrCreateId(mClientId);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to get the UUID of the document.");
   }
 
-  RefPtr<nsGlobalWindow> innerWindow = nsGlobalWindow::Cast(aDoc->GetInnerWindow());
+  RefPtr<nsGlobalWindowInner> innerWindow =
+    nsGlobalWindowInner::Cast(aDoc->GetInnerWindow());
   if (innerWindow) {
     // XXXcatalinb: The inner window can be null if the document is navigating
     // and was detached.
     mWindowId = innerWindow->WindowID();
   }
 
   nsCOMPtr<nsIURI> originalURI = aDoc->GetOriginalURI();
   if (originalURI) {
@@ -64,17 +65,18 @@ ServiceWorkerClientInfo::ServiceWorkerCl
   mFocused = aDoc->HasFocus(result);
   if (result.Failed()) {
     NS_WARNING("Failed to get focus information.");
   }
 
   MOZ_ASSERT_IF(mLastFocusTime.IsNull(), !mFocused);
   MOZ_ASSERT_IF(mFocused, !mLastFocusTime.IsNull());
 
-  RefPtr<nsGlobalWindow> outerWindow = nsGlobalWindow::Cast(aDoc->GetWindow());
+  RefPtr<nsGlobalWindowOuter> outerWindow =
+    nsGlobalWindowOuter::Cast(aDoc->GetWindow());
   if (!outerWindow) {
     MOZ_ASSERT(mFrameType == FrameType::None);
   } else if (!outerWindow->IsTopLevelWindow()) {
     mFrameType = FrameType::Nested;
   } else if (outerWindow->HadOriginalOpener()) {
     mFrameType = FrameType::Auxiliary;
   } else {
     mFrameType = FrameType::Top_level;
@@ -145,17 +147,17 @@ public:
     , mSourceScope(aSourceScope)
     , mWindowId(aWindowId)
   {}
 
   NS_IMETHOD
   Run() override
   {
     AssertIsOnMainThread();
-    nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
+    nsGlobalWindowInner* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
     if (!window) {
       return NS_ERROR_FAILURE;
     }
 
     dom::Navigator* navigator = window->Navigator();
     if (!navigator) {
       return NS_ERROR_FAILURE;
     }
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3088,17 +3088,17 @@ FireControllerChangeOnDocument(nsIDocume
   MOZ_ASSERT(aDocument);
 
   nsCOMPtr<nsPIDOMWindowInner> w = aDocument->GetInnerWindow();
   if (!w) {
     NS_WARNING("Failed to dispatch controllerchange event");
     return;
   }
 
-  auto* window = nsGlobalWindow::Cast(w.get());
+  auto* window = nsGlobalWindowInner::Cast(w.get());
   dom::Navigator* navigator = window->Navigator();
   if (!navigator) {
     return;
   }
 
   RefPtr<ServiceWorkerContainer> container = navigator->ServiceWorker();
   ErrorResult result;
   container->ControllerChanged(result);
@@ -3779,17 +3779,18 @@ ServiceWorkerManager::ShouldReportToWind
         continue;
       }
 
       uint64_t id = nsContentUtils::GetInnerWindowID(inner);
       if (id == 0) {
         continue;
       }
 
-      nsCOMPtr<nsPIDOMWindowInner> win = nsGlobalWindow::GetInnerWindowWithId(id)->AsInner();
+      nsCOMPtr<nsPIDOMWindowInner> win =
+        nsGlobalWindowInner::GetInnerWindowWithId(id)->AsInner();
       if (!win) {
         continue;
       }
 
       nsCOMPtr<nsPIDOMWindowOuter> outer = win->GetScriptableTop();
 
       // Match.  We should report to this window.
       if (outer && winId == outer->WindowID()) {
--- a/dom/workers/ServiceWorkerWindowClient.cpp
+++ b/dom/workers/ServiceWorkerWindowClient.cpp
@@ -117,17 +117,18 @@ public:
   {
     MOZ_ASSERT(mPromiseProxy);
   }
 
   NS_IMETHOD
   Run() override
   {
     AssertIsOnMainThread();
-    nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
+    nsGlobalWindowInner* window =
+      nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
     UniquePtr<ServiceWorkerClientInfo> clientInfo;
 
     if (window) {
       nsCOMPtr<nsIDocument> doc = window->GetDocument();
       if (doc) {
         nsContentUtils::DispatchFocusChromeEvent(window->GetOuterWindow());
         clientInfo.reset(new ServiceWorkerClientInfo(doc));
       }
@@ -378,17 +379,17 @@ public:
     nsCOMPtr<nsIURI> baseUrl;
     nsCOMPtr<nsIURI> url;
     nsresult rv = ParseUrl(getter_AddRefs(baseUrl), getter_AddRefs(url));
 
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return RejectPromise(NS_ERROR_TYPE_ERR);
     }
 
-    nsGlobalWindow* window;
+    nsGlobalWindowInner* window;
     rv = Navigate(url, principal, &window);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return RejectPromise(rv);
     }
 
     nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
     nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
     if (NS_WARN_IF(!webProgress)) {
@@ -466,21 +467,22 @@ private:
 
     baseUrl.forget(aBaseUrl);
     url.forget(aUrl);
 
     return NS_OK;
   }
 
   nsresult
-  Navigate(nsIURI* aUrl, nsIPrincipal* aPrincipal, nsGlobalWindow** aWindow)
+  Navigate(nsIURI* aUrl, nsIPrincipal* aPrincipal, nsGlobalWindowInner** aWindow)
   {
     MOZ_ASSERT(aWindow);
 
-    nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
+    nsGlobalWindowInner* window =
+      nsGlobalWindowInner::GetInnerWindowWithId(mWindowId);
     if (NS_WARN_IF(!window)) {
       return NS_ERROR_TYPE_ERR;
     }
 
     nsCOMPtr<nsIDocument> doc = window->GetDocument();
     if (NS_WARN_IF(!doc)) {
       return NS_ERROR_TYPE_ERR;
     }
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -298,17 +298,17 @@ WorkerRunnable::Run()
     // We may still not have a globalObject here: in the case of
     // CompileScriptRunnable, we don't actually create the global object until
     // we have the script data, which happens in a syncloop under
     // CompileScriptRunnable::WorkerRun, so we can't assert that it got created
     // in the PreRun call above.
   } else {
     kungFuDeathGrip = mWorkerPrivate;
     if (isMainThread) {
-      globalObject = nsGlobalWindow::Cast(mWorkerPrivate->GetWindow());
+      globalObject = nsGlobalWindowInner::Cast(mWorkerPrivate->GetWindow());
     } else {
       globalObject = mWorkerPrivate->GetParent()->GlobalScope();
     }
   }
 
   // We might run script as part of WorkerRun, so we need an AutoEntryScript.
   // This is part of the HTML spec for workers at:
   // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -88,44 +88,44 @@ nsXBLPrototypeHandler::nsXBLPrototypeHan
                                              const char16_t* aClickCount,
                                              const char16_t* aGroup,
                                              const char16_t* aPreventDefault,
                                              const char16_t* aAllowUntrusted,
                                              nsXBLPrototypeBinding* aBinding,
                                              uint32_t aLineNumber)
   : mHandlerText(nullptr),
     mLineNumber(aLineNumber),
-    mReserved(false),
+    mReserved(XBLReservedKey_False),
     mNextHandler(nullptr),
     mPrototypeBinding(aBinding)
 {
   Init();
 
   ConstructPrototype(nullptr, aEvent, aPhase, aAction, aCommand, aKeyCode,
                      aCharCode, aModifiers, aButton, aClickCount,
                      aGroup, aPreventDefault, aAllowUntrusted);
 }
 
-nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement, bool aReserved)
+nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement, XBLReservedKey aReserved)
   : mHandlerElement(nullptr),
     mLineNumber(0),
     mReserved(aReserved),
     mNextHandler(nullptr),
     mPrototypeBinding(nullptr)
 {
   Init();
 
   // Make sure our prototype is initialized.
   ConstructPrototype(aHandlerElement);
 }
 
 nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
   : mHandlerText(nullptr),
     mLineNumber(0),
-    mReserved(false),
+    mReserved(XBLReservedKey_False),
     mNextHandler(nullptr),
     mPrototypeBinding(aBinding)
 {
   Init();
 }
 
 nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
 {
--- a/dom/xbl/nsXBLPrototypeHandler.h
+++ b/dom/xbl/nsXBLPrototypeHandler.h
@@ -50,16 +50,25 @@ class KeyboardShortcut;
 #define NS_HANDLER_TYPE_SYSTEM              (1 << 6)
 #define NS_HANDLER_TYPE_PREVENTDEFAULT      (1 << 7)
 
 // XXX Use nsIDOMEvent:: codes?
 #define NS_PHASE_CAPTURING          1
 #define NS_PHASE_TARGET             2
 #define NS_PHASE_BUBBLING           3
 
+// Values of the reserved attribute. When unset, the default value depends on
+// the permissions.default.shortcuts preference.
+enum XBLReservedKey : uint8_t
+{
+  XBLReservedKey_False = 0,
+  XBLReservedKey_True = 1,
+  XBLReservedKey_Unset = 2,
+};
+
 class nsXBLPrototypeHandler
 {
   typedef mozilla::IgnoreModifierState IgnoreModifierState;
   typedef mozilla::layers::KeyboardShortcut KeyboardShortcut;
   typedef mozilla::Modifiers Modifiers;
 
 public:
   // This constructor is used by XBL handlers (both the JS and command shorthand variety)
@@ -69,17 +78,17 @@ public:
                         const char16_t* aModifiers, const char16_t* aButton,
                         const char16_t* aClickCount, const char16_t* aGroup,
                         const char16_t* aPreventDefault,
                         const char16_t* aAllowUntrusted,
                         nsXBLPrototypeBinding* aBinding,
                         uint32_t aLineNumber);
 
   // This constructor is used only by XUL key handlers (e.g., <key>)
-  explicit nsXBLPrototypeHandler(nsIContent* aKeyElement, bool aReserved);
+  explicit nsXBLPrototypeHandler(nsIContent* aKeyElement, XBLReservedKey aReserved);
 
   // This constructor is used for handlers loaded from the cache
   explicit nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding);
 
   ~nsXBLPrototypeHandler();
 
   /**
    * Try and convert this XBL handler into an APZ KeyboardShortcut for handling
@@ -113,17 +122,17 @@ public:
   }
 
   already_AddRefed<nsIContent> GetHandlerElement();
 
   void AppendHandlerText(const nsAString& aText);
 
   uint8_t GetPhase() { return mPhase; }
   uint8_t GetType() { return mType; }
-  bool GetIsReserved() { return mReserved; }
+  XBLReservedKey GetIsReserved() { return mReserved; }
 
   nsXBLPrototypeHandler* GetNextHandler() { return mNextHandler; }
   void SetNextHandler(nsXBLPrototypeHandler* aHandler) { mNextHandler = aHandler; }
 
   nsresult ExecuteHandler(mozilla::dom::EventTarget* aTarget, nsIDOMEvent* aEvent);
 
   already_AddRefed<nsAtom> GetEventName();
   void SetEventName(nsAtom* aName) { mEventName = aName; }
@@ -228,17 +237,17 @@ protected:
   uint8_t mType;             // The type of the handler.  The handler is either a XUL key
                              // handler, an XBL "command" event, or a normal XBL event with
                              // accompanying JavaScript.  The high bit is used to indicate
                              // whether this handler should prevent the default action.
   uint8_t mMisc;             // Miscellaneous extra information.  For key events,
                              // stores whether or not we're a key code or char code.
                              // For mouse events, stores the clickCount.
 
-  bool mReserved;            // <key> is reserved for chrome. Not used by handlers.
+  XBLReservedKey mReserved;  // <key> is reserved for chrome. Not used by handlers.
 
   int32_t mKeyMask;          // Which modifier keys this event handler expects to have down
                              // in order to be matched.
 
   // The primary filter information for mouse/key events.
   int32_t mDetail;           // For key events, contains a charcode or keycode. For
                              // mouse events, stores the button info.
 
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -206,18 +206,26 @@ BuildHandlerChain(nsIContent* aContent, 
       bool attrExists =
         key->GetAttr(kNameSpaceID_None, nsGkAtoms::key, valKey) ||
         key->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, valCharCode) ||
         key->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, valKeyCode);
       if (attrExists &&
           valKey.IsEmpty() && valCharCode.IsEmpty() && valKeyCode.IsEmpty())
         continue;
 
-      bool reserved = key->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
-                                       nsGkAtoms::_true, eCaseMatters);
+      // reserved="pref" is the default for <key> elements.
+      XBLReservedKey reserved = XBLReservedKey_Unset;
+      if (key->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
+                           nsGkAtoms::_true, eCaseMatters)) {
+        reserved = XBLReservedKey_True;
+      } else if (key->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
+                                   nsGkAtoms::_false, eCaseMatters)) {
+        reserved = XBLReservedKey_False;
+      }
+
       nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(key, reserved);
 
       handler->SetNextHandler(*aResult);
       *aResult = handler;
     }
   }
 }
 
@@ -720,46 +728,55 @@ nsXBLWindowKeyHandler::WalkHandlersAndEx
     // Before executing this handler, check that it's not disabled,
     // and that it has something to do (oncommand of the <key> or its
     // <command> is non-empty).
     nsCOMPtr<Element> commandElement;
     if (!GetElementForHandler(handler, getter_AddRefs(commandElement))) {
       continue;
     }
 
-    bool isReserved = handler->GetIsReserved();
-    if (aOutReservedForChrome) {
-      *aOutReservedForChrome = isReserved;
-    }
-
     if (commandElement) {
       if (aExecute && !IsExecutableElement(commandElement)) {
         continue;
       }
     }
 
     if (!aExecute) {
       if (handler->EventTypeEquals(aEventType)) {
+        if (aOutReservedForChrome) {
+          *aOutReservedForChrome = IsReservedKey(widgetKeyboardEvent, handler);
+        }
+
         return true;
       }
+
       // If the command is reserved and the event is keydown, check also if
       // the handler is for keypress because if following keypress event is
       // reserved, we shouldn't dispatch the event into web contents.
-      if (isReserved &&
-          aEventType == nsGkAtoms::keydown &&
+      if (aEventType == nsGkAtoms::keydown &&
           handler->EventTypeEquals(nsGkAtoms::keypress)) {
-        return true;
+        if (IsReservedKey(widgetKeyboardEvent, handler)) {
+          if (aOutReservedForChrome) {
+            *aOutReservedForChrome = true;
+          }
+
+          return true;
+        }
       }
       // Otherwise, we've not found a handler for the event yet.
       continue;
     }
 
+    // This should only be assigned when aExecute is false.
+    MOZ_ASSERT(!aOutReservedForChrome);
+
     // If it's not reserved and the event is a key event on a plugin,
     // the handler shouldn't be executed.
-    if (!isReserved && widgetKeyboardEvent->IsKeyEventOnPlugin()) {
+    if (widgetKeyboardEvent->IsKeyEventOnPlugin() &&
+        !IsReservedKey(widgetKeyboardEvent, handler)) {
       return false;
     }
 
     nsCOMPtr<EventTarget> target;
     nsCOMPtr<Element> chromeHandlerElement = GetElement();
     if (chromeHandlerElement) {
       // XXX commandElement may be nullptr...
       target = commandElement;
@@ -787,16 +804,35 @@ nsXBLWindowKeyHandler::WalkHandlersAndEx
                                   aCharCode, ignoreModifierState, aExecute);
   }
 #endif
 
   return false;
 }
 
 bool
+nsXBLWindowKeyHandler::IsReservedKey(WidgetKeyboardEvent* aKeyEvent,
+                                     nsXBLPrototypeHandler* aHandler)
+{
+  XBLReservedKey reserved = aHandler->GetIsReserved();
+  // reserved="true" means that the key is always reserved. reserved="false"
+  // means that the key is never reserved. Otherwise, we check site-specific
+  // permissions.
+  if (reserved == XBLReservedKey_False) {
+    return false;
+  }
+
+  if (reserved == XBLReservedKey_True) {
+    return true;
+  }
+
+  return nsContentUtils::ShouldBlockReservedKeys(aKeyEvent);
+}
+
+bool
 nsXBLWindowKeyHandler::HasHandlerForEvent(nsIDOMKeyEvent* aEvent,
                                           bool* aOutReservedForChrome)
 {
   WidgetKeyboardEvent* widgetKeyboardEvent =
     aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (NS_WARN_IF(!widgetKeyboardEvent) || !widgetKeyboardEvent->IsTrusted()) {
     return false;
   }
--- a/dom/xbl/nsXBLWindowKeyHandler.h
+++ b/dom/xbl/nsXBLWindowKeyHandler.h
@@ -14,16 +14,17 @@
 
 class nsAtom;
 class nsIDOMElement;
 class nsIDOMKeyEvent;
 class nsXBLPrototypeHandler;
 
 namespace mozilla {
 class EventListenerManager;
+class WidgetKeyboardEvent;
 struct IgnoreModifierState;
 namespace dom {
 class Element;
 class EventTarget;
 } // namespace dom
 } // namespace mozilla
 
 class nsXBLWindowKeyHandler : public nsIDOMEventListener
@@ -72,16 +73,21 @@ protected:
   void HandleEventOnCaptureInSystemEventGroup(nsIDOMKeyEvent* aEvent);
 
   // Check if any handler would handle the given event. Optionally returns
   // whether the command handler for the event is marked with the "reserved"
   // attribute.
   bool HasHandlerForEvent(nsIDOMKeyEvent* aEvent,
                           bool* aOutReservedForChrome = nullptr);
 
+  // Returns true if the key would be reserved for the given handler. A reserved
+  // key is not sent to a content process or single-process equivalent.
+  bool IsReservedKey(mozilla::WidgetKeyboardEvent* aKeyEvent,
+                     nsXBLPrototypeHandler* aHandler);
+
   // Returns event type for matching between aWidgetKeyboardEvent and
   // shortcut key handlers.  This is used for calling WalkHandlers(),
   // WalkHandlersInternal() and WalkHandlersAndExecute().
   nsAtom* ConvertEventToDOMEventType(
              const mozilla::WidgetKeyboardEvent& aWidgetKeyboardEvent) const;
 
   // lazily load the special doc info for loading handlers
   static void EnsureSpecialDocInfo();
new file mode 100644
--- /dev/null
+++ b/dom/xslt/crashtests/1336828.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script id=o_xml type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<tag_name/>
+</script>
+<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="42">
+ <xsl:variable name="var_name"><xsl:template/></xsl:variable>
+ <xsl:template match="tag_name[$var_name]"/>
+</xsl:stylesheet>
+</script>
+<script>
+window.onload = function(){
+  let doc = new DOMParser(), proc = new XSLTProcessor();
+  proc.importStylesheet(doc.parseFromString(document.getElementById('o_xslt').textContent, "text/xml"));
+  proc.transformToDocument(doc.parseFromString(document.getElementById('o_xml').textContent, "text/xml"));
+};
+</script>
+</head>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/xslt/crashtests/1336830.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script id=o_xml type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<tag_name/>
+</script>
+<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="42">
+  <xsl:template match="*">
+    <xsl:apply-imports/>
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="whatever_1">whatever_2</xsl:with-param>
+    </xsl:apply-templates>
+  </xsl:template>
+</xsl:stylesheet>
+</script>
+<script>
+window.onload = function(){
+  setTimeout(function(){ window.close(); }, 400);
+  let doc = new DOMParser(), proc = new XSLTProcessor();
+  proc.importStylesheet(doc.parseFromString(document.getElementById('o_xslt').textContent, "text/xml"));
+  proc.transformToFragment(doc.parseFromString(document.getElementById('o_xml').textContent, "text/xml"), document);
+};
+</script>
+</head>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/xslt/crashtests/1336832.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script id=o_xml type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<tag_name/>
+</script>
+<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:variable name="var_1">
+    <xsl:for-each select="/">
+      <xsl:value-of select="count()"/>
+    </xsl:for-each>
+  </xsl:variable>
+  <xsl:template match="/">
+    <xsl:value-of select="//*[1 = $var_1]"/>
+  </xsl:template>
+</xsl:stylesheet>
+</script>
+<script>
+window.onload = function(){
+  let doc = new DOMParser(), proc = new XSLTProcessor();
+  proc.importStylesheet(doc.parseFromString(document.getElementById('o_xslt').textContent, "text/xml"));
+  proc.transformToDocument(doc.parseFromString(document.getElementById('o_xml').textContent, "text/xml"));
+};
+</script>
+</head>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/xslt/crashtests/949990.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom() {
+    document.evaluate("a", document.documentElement, null, 4096, null);
+}
+
+</script>
+</head>
+
+<body onload="boom()"></body>
+</html>
--- a/dom/xslt/crashtests/crashtests.list
+++ b/dom/xslt/crashtests/crashtests.list
@@ -10,14 +10,18 @@ load 527558_1.xml
 load 528300.xml
 load 528488.xml
 load 528963.xml
 load 545927.html
 load 601543.html
 load 602115.html
 load 603844.html
 load 667315.xml
+load 949990.html
 load 1089049.html
 load 1205163.xml
 load 1243337.xml
 load 1330492.html
+load 1336828.html
+load 1336830.html
+load 1336832.html
 load 1338277.html
 load 1361892.html
--- a/dom/xslt/xpath/XPathExpression.cpp
+++ b/dom/xslt/xpath/XPathExpression.cpp
@@ -96,16 +96,21 @@ XPathExpression::EvaluateWithContext(nsI
                                      XPathResult* aInResult,
                                      ErrorResult& aRv)
 {
     if (aContextPosition > aContextSize) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
     }
 
+    if (aType > XPathResultBinding::FIRST_ORDERED_NODE_TYPE) {
+        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+        return nullptr;
+    }
+
     if (!nsContentUtils::LegacyIsCallerNativeCode() &&
         !nsContentUtils::CanCallerAccess(&aContextNode))
     {
         aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
         return nullptr;
     }
 
     if (mCheckDocument) {
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -130,17 +130,18 @@ static const char* kPreloadPermissions[]
 };
 
 // A list of permissions that can have a fallback default permission
 // set under the permissions.default.* pref.
 static const char* kPermissionsWithDefaults[] = {
   "camera",
   "microphone",
   "geo",
-  "desktop-notification"
+  "desktop-notification",
+  "shortcuts"
 };
 
 // NOTE: nullptr can be passed as aType - if it is this function will return
 // "false" unconditionally.
 bool
 HasDefaultPref(const char* aType)
 {
   if (aType) {
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-52371
+52373
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -33798,16 +33798,17 @@ malefaction/M
 malefactor/SM
 malefic
 maleficence/M
 maleficent
 maleness/M
 malevolence/M
 malevolent/Y
 malfeasance/M
+malform/S
 malformation/SM
 malformed
 malfunction/MDSG
 malice/M
 malicious/PY
 maliciousness/M
 malign/DSG
 malignancy/SM
@@ -42042,16 +42043,17 @@ remain/SGD
 remainder/GMDS
 remand/SGD
 remapping
 remark/B
 remarkableness/M
 remarkably
 remarked/U
 remediable
+remediate/DGS
 remedy/GDSM
 remember/DG
 remembered/U
 remembrance/MS
 reminder/M
 reminisce/GDS
 reminiscence/MS
 reminiscent/Y
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1568,22 +1568,24 @@ DrawTarget::Draw3DTransformedSurface(Sou
   RefPtr<DataSourceSurface> dstSurf =
     Factory::CreateDataSourceSurface(xformBounds.Size(),
                                      !srcImage->isOpaque() ?
                                        aSurface->GetFormat() : SurfaceFormat::A8R8G8B8_UINT32,
                                      true);
   if (!dstSurf) {
     return false;
   }
+
+  DataSourceSurface::ScopedMap map(dstSurf, DataSourceSurface::READ_WRITE);
   std::unique_ptr<SkCanvas> dstCanvas(
     SkCanvas::MakeRasterDirect(
                         SkImageInfo::Make(xformBounds.Width(), xformBounds.Height(),
                         GfxFormatToSkiaColorType(dstSurf->GetFormat()),
                         kPremul_SkAlphaType),
-      dstSurf->GetData(), dstSurf->Stride()));
+      map.GetData(), map.GetStride()));
   if (!dstCanvas) {
     return false;
   }
 
   // Do the transform.
   SkPaint paint;
   paint.setAntiAlias(true);
   paint.setFilterQuality(kLow_SkFilterQuality);
@@ -1741,23 +1743,24 @@ DrawTargetSkia::OptimizeSourceSurfaceFor
 #endif
 
   if (aSurface->GetType() == SurfaceType::SKIA) {
     RefPtr<SourceSurface> surface(aSurface);
     return surface.forget();
   }
 
   RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
+  DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
 
   // For plugins, GDI can sometimes just write 0 to the alpha channel
   // even for RGBX formats. In this case, we have to manually write
   // the alpha channel to make Skia happy with RGBX and in case GDI
   // writes some bad data. Luckily, this only happens on plugins.
-  WriteRGBXFormat(dataSurface->GetData(), dataSurface->GetSize(),
-                  dataSurface->Stride(), dataSurface->GetFormat());
+  WriteRGBXFormat(map.GetData(), dataSurface->GetSize(),
+                  map.GetStride(), dataSurface->GetFormat());
   return dataSurface.forget();
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
 #ifdef USE_SKIA_GPU
   if (UsingSkiaGPU()) {
@@ -1770,18 +1773,21 @@ DrawTargetSkia::OptimizeSourceSurface(So
     return surface.forget();
   }
 
   // If we're not using skia-gl then drawing doesn't require any
   // uploading, so any data surface is fine. Call GetDataSurface
   // to trigger any required readback so that it only happens
   // once.
   RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
-  MOZ_ASSERT(VerifyRGBXFormat(dataSurface->GetData(), dataSurface->GetSize(),
-                              dataSurface->Stride(), dataSurface->GetFormat()));
+#ifdef DEBUG
+  DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ);
+  MOZ_ASSERT(VerifyRGBXFormat(map.GetData(), dataSurface->GetSize(),
+                              map.GetStride(), dataSurface->GetFormat()));
+#endif
   return dataSurface.forget();
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
 #ifdef USE_SKIA_GPU
   if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
--- a/gfx/2d/FilterProcessingSIMD-inl.h
+++ b/gfx/2d/FilterProcessingSIMD-inl.h
@@ -15,20 +15,22 @@ namespace gfx {
 template<typename u8x16_t>
 inline already_AddRefed<DataSourceSurface>
 ConvertToB8G8R8A8_SIMD(SourceSurface* aSurface)
 {
   IntSize size = aSurface->GetSize();
   RefPtr<DataSourceSurface> input = aSurface->GetDataSurface();
   RefPtr<DataSourceSurface> output =
     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
-  uint8_t *inputData = input->GetData();
-  uint8_t *outputData = output->GetData();
-  int32_t inputStride = input->Stride();
-  int32_t outputStride = output->Stride();
+  DataSourceSurface::ScopedMap inputMap(input, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap outputMap(output, DataSourceSurface::READ_WRITE);
+  uint8_t *inputData = inputMap.GetData();
+  uint8_t *outputData = outputMap.GetData();
+  int32_t inputStride = inputMap.GetStride();
+  int32_t outputStride = outputMap.GetStride();
   switch (input->GetFormat()) {
     case SurfaceFormat::B8G8R8A8:
       output = input;
       break;
     case SurfaceFormat::B8G8R8X8:
       for (int32_t y = 0; y < size.height; y++) {
         for (int32_t x = 0; x < size.width; x++) {
           int32_t inputIndex = y * inputStride + 4 * x;
@@ -290,22 +292,26 @@ ApplyBlending_SIMD(DataSourceSurface* aI
 {
   IntSize size = aInput1->GetSize();
   RefPtr<DataSourceSurface> target =
     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
   if (!target) {
     return nullptr;
   }
 
-  uint8_t* source1Data = aInput1->GetData();
-  uint8_t* source2Data = aInput2->GetData();
-  uint8_t* targetData = target->GetData();
-  int32_t targetStride = target->Stride();
-  int32_t source1Stride = aInput1->Stride();
-  int32_t source2Stride = aInput2->Stride();
+  DataSourceSurface::ScopedMap inputMap1(aInput1, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap inputMap2(aInput2, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap outputMap(target, DataSourceSurface::READ_WRITE);
+
+  uint8_t* source1Data = inputMap1.GetData();
+  uint8_t* source2Data = inputMap2.GetData();
+  uint8_t* targetData = outputMap.GetData();
+  int32_t targetStride = outputMap.GetStride();
+  int32_t source1Stride = inputMap1.GetStride();
+  int32_t source2Stride = inputMap2.GetStride();
 
   for (int32_t y = 0; y < size.height; y++) {
     for (int32_t x = 0; x < size.width; x += 4) {
       int32_t targetIndex = y * targetStride + 4 * x;
       int32_t source1Index = y * source1Stride + 4 * x;
       int32_t source2Index = y * source2Stride + 4 * x;
 
       u8x16_t s1234 = simd::Load8<u8x16_t>(&source2Data[source2Index]);
@@ -515,20 +521,23 @@ ApplyColorMatrix_SIMD(DataSourceSurface*
 {
   IntSize size = aInput->GetSize();
   RefPtr<DataSourceSurface> target =
     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
   if (!target) {
     return nullptr;
   }
 
-  uint8_t* sourceData = aInput->GetData();
-  uint8_t* targetData = target->GetData();
-  int32_t sourceStride = aInput->Stride();
-  int32_t targetStride = target->Stride();
+  DataSourceSurface::ScopedMap inputMap(aInput, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap outputMap(target, DataSourceSurface::READ_WRITE);
+
+  uint8_t* sourceData = inputMap.GetData();
+  uint8_t* targetData = outputMap.GetData();
+  int32_t sourceStride = inputMap.GetStride();
+  int32_t targetStride = outputMap.GetStride();
 
   const int16_t factor = 128;
   const Float floatElementMax = INT16_MAX / factor; // 255
   MOZ_ASSERT((floatElementMax * factor) <= INT16_MAX, "badly chosen float-to-int scale");
 
   const Float *floats = &aMatrix._11;
 
   ptrdiff_t componentOffsets[4] = {
@@ -697,20 +706,23 @@ CompositeTwoPixels(u16x8_t source, u16x8
 }
 
 template<typename i32x4_t, typename u16x8_t, typename u8x16_t, uint32_t op>
 static void
 ApplyComposition(DataSourceSurface* aSource, DataSourceSurface* aDest)
 {
   IntSize size = aDest->GetSize();
 
-  uint8_t* sourceData = aSource->GetData();
-  uint8_t* destData = aDest->GetData();
-  uint32_t sourceStride = aSource->Stride();
-  uint32_t destStride = aDest->Stride();
+  DataSourceSurface::ScopedMap input(aSource, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap output(aDest, DataSourceSurface::READ_WRITE);
+
+  uint8_t* sourceData = input.GetData();
+  uint8_t* destData = output.GetData();
+  uint32_t sourceStride = input.GetStride();
+  uint32_t destStride = output.GetStride();
 
   for (int32_t y = 0; y < size.height; y++) {
     for (int32_t x = 0; x < size.width; x += 4) {
       uint32_t sourceIndex = y * sourceStride + 4 * x;
       uint32_t destIndex = y * destStride + 4 * x;
 
       u8x16_t s1234 = simd::Load8<u8x16_t>(&sourceData[sourceIndex]);
       u8x16_t d1234 = simd::Load8<u8x16_t>(&destData[destIndex]);
@@ -1020,22 +1032,26 @@ ApplyArithmeticCombine_SIMD(DataSourceSu
 {
   IntSize size = aInput1->GetSize();
   RefPtr<DataSourceSurface> target =
   Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
   if (!target) {
     return nullptr;
   }
 
-  uint8_t* source1Data = aInput1->GetData();
-  uint8_t* source2Data = aInput2->GetData();
-  uint8_t* targetData = target->GetData();
-  uint32_t source1Stride = aInput1->Stride();
-  uint32_t source2Stride = aInput2->Stride();
-  uint32_t targetStride = target->Stride();
+  DataSourceSurface::ScopedMap inputMap1(aInput1, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap inputMap2(aInput2, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap outputMap(target, DataSourceSurface::READ_WRITE);
+
+  uint8_t* source1Data = inputMap1.GetData();
+  uint8_t* source2Data = inputMap2.GetData();
+  uint8_t* targetData = outputMap.GetData();
+  uint32_t source1Stride = inputMap1.GetStride();
+  uint32_t source2Stride = inputMap2.GetStride();
+  uint32_t targetStride = outputMap.GetStride();
 
   // The arithmetic combine filter does the following calculation:
   // result = k1 * in1 * in2 + k2 * in1 + k3 * in2 + k4
   //
   // Or, with in1/2 integers between 0 and 255:
   // result = (k1 * in1 * in2) / 255 + k2 * in1 + k3 * in2 + k4 * 255
   //
   // We want the whole calculation to happen in integer, with 16-bit factors.
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -1528,18 +1528,20 @@ RecordedDrawTargetCreation::Record(S &aS
   WriteElement(aStream, mSize);
   WriteElement(aStream, mFormat);
   WriteElement(aStream, mHasExistingData);
 
   if (mHasExistingData) {
     MOZ_ASSERT(mExistingData);
     MOZ_ASSERT(mExistingData->GetSize() == mSize);
     RefPtr<DataSourceSurface> dataSurf = mExistingData->GetDataSurface();
+
+    DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ);
     for (int y = 0; y < mSize.height; y++) {
-      aStream.write((const char*)dataSurf->GetData() + y * dataSurf->Stride(),
+      aStream.write((const char*)map.GetData() + y * map.GetStride(),
                     BytesPerPixel(mFormat) * mSize.width);
     }
   }
 }
 
 template<class S>
 RecordedDrawTargetCreation::RecordedDrawTargetCreation(S &aStream)
   : RecordedEventDerived(DRAWTARGETCREATION)
@@ -1554,18 +1556,19 @@ RecordedDrawTargetCreation::RecordedDraw
   if (mHasExistingData) {
     RefPtr<DataSourceSurface> dataSurf = Factory::CreateDataSourceSurface(mSize, mFormat);
     if (!dataSurf) {
       gfxWarning() << "RecordedDrawTargetCreation had to reset mHasExistingData";
       mHasExistingData = false;
       return;
     }
 
+    DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ);
     for (int y = 0; y < mSize.height; y++) {
-      aStream.read((char*)dataSurf->GetData() + y * dataSurf->Stride(),
+      aStream.read((char*)map.GetData() + y * map.GetStride(),
                     BytesPerPixel(mFormat) * mSize.width);
     }
     mExistingData = dataSurf;
   }
 }
 
 inline void
 RecordedDrawTargetCreation::OutputSimpleEventInfo(std::stringstream &aStringStream) const
--- a/gfx/2d/SVGTurbulenceRenderer-inl.h
+++ b/gfx/2d/SVGTurbulenceRenderer-inl.h
@@ -324,18 +324,19 @@ already_AddRefed<DataSourceSurface>
 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Render(const IntSize &aSize, const Point &aOffset) const
 {
   RefPtr<DataSourceSurface> target =
     Factory::CreateDataSourceSurface(aSize, SurfaceFormat::B8G8R8A8);
   if (!target) {
     return nullptr;
   }
 
-  uint8_t* targetData = target->GetData();
-  uint32_t stride = target->Stride();
+  DataSourceSurface::ScopedMap map(target, DataSourceSurface::READ_WRITE);
+  uint8_t* targetData = map.GetData();
+  uint32_t stride = map.GetStride();
 
   Point startOffset = EquivalentNonNegativeOffset(aOffset);
 
   for (int32_t y = 0; y < aSize.height; y++) {
     for (int32_t x = 0; x < aSize.width; x += 4) {
       int32_t targIndex = y * stride + x * 4;
       i32x4_t a = Turbulence(startOffset + Point(x, y));
       i32x4_t b = Turbulence(startOffset + Point(x + 1, y));
--- a/gfx/2d/unittest/TestBugs.cpp
+++ b/gfx/2d/unittest/TestBugs.cpp
@@ -56,19 +56,21 @@ TestBugs::CairoClip918671()
   dt->FillRect(Rect(0, 0, 100, 100), ColorPattern(Color(1,0,0)));
 
   RefPtr<SourceSurface> surf1 = dt->Snapshot();
   RefPtr<SourceSurface> surf2 = ref->Snapshot();
 
   RefPtr<DataSourceSurface> dataSurf1 = surf1->GetDataSurface();
   RefPtr<DataSourceSurface> dataSurf2 = surf2->GetDataSurface();
 
+  DataSourceSurface::ScopedMap map1(dataSurf1, DataSourceSurface::READ);
+  DataSourceSurface::ScopedMap map2(dataSurf2, DataSourceSurface::READ);
   for (int y = 0; y < dt->GetSize().height; y++) {
-    VERIFY(memcmp(dataSurf1->GetData() + y * dataSurf1->Stride(),
-                  dataSurf2->GetData() + y * dataSurf2->Stride(),
+    VERIFY(memcmp(map1.GetData() + y * map1.GetStride(),
+                  map2.GetData() + y * map2.GetStride(),
                   dataSurf1->GetSize().width * 4) == 0);
   }
 
 }
 
 void
 TestBugs::PushPopClip950550()
 {
--- a/gfx/gl/GLReadTexImageHelper.cpp
+++ b/gfx/gl/GLReadTexImageHelper.cpp
@@ -310,29 +310,33 @@ ReadPixelsIntoDataSurface(GLContext* gl,
     case SurfaceFormat::R5G6B5_UINT16:
         destFormat = LOCAL_GL_RGB;
         destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
         break;
     default:
         MOZ_CRASH("GFX: Bad format, read pixels.");
     }
     destPixelSize = BytesPerPixel(dest->GetFormat());
-    MOZ_ASSERT(dest->GetSize().width * destPixelSize <= dest->Stride());
+
+    Maybe<DataSourceSurface::ScopedMap> map;
+    map.emplace(dest, DataSourceSurface::READ_WRITE);
+
+    MOZ_ASSERT(dest->GetSize().width * destPixelSize <= map->GetStride());
 
     GLenum readFormat = destFormat;
     GLenum readType = destType;
     bool needsTempSurf = !GetActualReadFormats(gl,
                                                destFormat, destType,
                                                &readFormat, &readType);
 
     RefPtr<DataSourceSurface> tempSurf;
     DataSourceSurface* readSurf = dest;
     int readAlignment = GuessAlignment(dest->GetSize().width,
                                        destPixelSize,
-                                       dest->Stride());
+                                       map->GetStride());
     if (!readAlignment) {
         needsTempSurf = true;
     }
     if (needsTempSurf) {
         if (GLContext::ShouldSpew()) {
             NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
         }
         SurfaceFormat readFormatGFX;
@@ -384,47 +388,52 @@ ReadPixelsIntoDataSurface(GLContext* gl,
         tempSurf = Factory::CreateDataSourceSurfaceWithStride(dest->GetSize(),
                                                               readFormatGFX,
                                                               stride);
         if (NS_WARN_IF(!tempSurf)) {
             return;
         }
 
         readSurf = tempSurf;
+        map = Nothing();
+        map.emplace(readSurf, DataSourceSurface::READ_WRITE);
     }
+
     MOZ_ASSERT(readAlignment);
-    MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0);
+    MOZ_ASSERT(reinterpret_cast<uintptr_t>(map->GetData()) % readAlignment == 0);
 
     GLsizei width = dest->GetSize().width;
     GLsizei height = dest->GetSize().height;
 
     {
         ScopedPackState safePackState(gl);
         gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
 
         gl->fReadPixels(0, 0,
                         width, height,
                         readFormat, readType,
-                        readSurf->GetData());
+                        map->GetData());
     }
 
+    map = Nothing();
+
     if (readSurf != dest) {