Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 28 Jul 2016 17:46:12 +0200
changeset 347074 54eb32559af3c72a14593fdcea471ecae7001da2
parent 347073 cd08b203bbae84b4bc042b4e27fe1f3bc4b2b354 (current diff)
parent 347068 9ec789c0ee5bd3a5e765513c21027fdad953b022 (diff)
child 347075 915257f0f74c8f124904cbcf8ca8204ada4370c7
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland
testing/web-platform/meta/custom-elements/v0/instantiating/custom-element-constructor-prototype.html.ini
testing/web-platform/meta/custom-elements/v0/instantiating/custom-element-prototype.html.ini
--- a/accessible/windows/sdn/sdnAccessible.cpp
+++ b/accessible/windows/sdn/sdnAccessible.cpp
@@ -14,16 +14,17 @@
 #include "nsIAccessibleTypes.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsNameSpaceManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsWinUtils.h"
 #include "nsRange.h"
 
+#include "mozilla/dom/BorrowedAttrInfo.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 STDMETHODIMP
 sdnAccessible::QueryInterface(REFIID aREFIID, void** aInstancePtr)
 {
@@ -144,20 +145,21 @@ sdnAccessible::get_attributes(unsigned  
 
   *aNumAttribs = static_cast<unsigned short>(numAttribs);
 
   for (uint32_t index = 0; index < numAttribs; index++) {
     aNameSpaceIDs[index] = 0;
     aAttribValues[index] = aAttribNames[index] = nullptr;
     nsAutoString attributeValue;
 
-    const nsAttrName* name = elm->GetAttrNameAt(index);
-    aNameSpaceIDs[index] = static_cast<short>(name->NamespaceID());
-    aAttribNames[index] = ::SysAllocString(name->LocalName()->GetUTF16String());
-    elm->GetAttr(name->NamespaceID(), name->LocalName(), attributeValue);
+    dom::BorrowedAttrInfo attr = elm->GetAttrInfoAt(index);
+    attr.mValue->ToString(attributeValue);
+
+    aNameSpaceIDs[index] = static_cast<short>(attr.mName->NamespaceID());
+    aAttribNames[index] = ::SysAllocString(attr.mName->LocalName()->GetUTF16String());
     aAttribValues[index] = ::SysAllocString(attributeValue.get());
   }
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5612,17 +5612,17 @@ function middleMousePaste(event) {
     }
   });
 
   event.stopPropagation();
 }
 
 function stripUnsafeProtocolOnPaste(pasteData) {
   // Don't allow pasting javascript URIs since we don't support
-  // LOAD_FLAGS_DISALLOW_INHERIT_OWNER for those.
+  // LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.
   return pasteData.replace(/^(?:\s*javascript:)+/i, "");
 }
 
 function handleDroppedLink(event, url, name)
 {
   let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
 
   getShortcutOrURIAndPostData(url).then(data => {
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -330,22 +330,22 @@ function openLinkIn(url, where, params) 
   case "current":
     let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
 
     if (aAllowThirdPartyFixup) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
     }
 
-    // LOAD_FLAGS_DISALLOW_INHERIT_OWNER isn't supported for javascript URIs,
+    // LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL isn't supported for javascript URIs,
     // i.e. it causes them not to load at all. Callers should strip
     // "javascript:" from pasted strings to protect users from malicious URIs
     // (see stripUnsafeProtocolOnPaste).
     if (aDisallowInheritPrincipal && !(uriObj && uriObj.schemeIs("javascript"))) {
-      flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+      flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
     }
 
     if (aAllowPopups) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_POPUPS;
     }
     if (aIndicateErrorPageLoad) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV;
     }
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -1,18 +1,20 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-var Bookmarks = PlacesUtils.bookmarks;
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
-Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+XPCOMUtils.defineLazyGetter(this, "Bookmarks", () => {
+  Cu.import("resource://gre/modules/PlacesUtils.jsm");
+  return PlacesUtils.bookmarks;
+});
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 
 function getTree(rootGuid, onlyChildren) {
   function convert(node, parent) {
     let treenode = {
       id: node.guid,
--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -72,20 +72,22 @@ CommandList.prototype = {
   loadCommandsFromManifest(manifest) {
     let commands = new Map();
     // For Windows, chrome.runtime expects 'win' while chrome.commands
     // expects 'windows'.  We can special case this for now.
     let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
     for (let name of Object.keys(manifest.commands)) {
       let command = manifest.commands[name];
       let shortcut = command.suggested_key[os] || command.suggested_key.default;
-      commands.set(name, {
-        description: command.description,
-        shortcut: shortcut.replace(/\s+/g, ""),
-      });
+      if (shortcut) {
+        commands.set(name, {
+          description: command.description,
+          shortcut: shortcut.replace(/\s+/g, ""),
+        });
+      }
     }
     return commands;
   },
 
   /**
    * Registers the commands to a document.
    * @param {ChromeWindow} window The XUL window to insert the Keyset.
    */
--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -1,33 +1,38 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "History", () => {
+  Cu.import("resource://gre/modules/PlacesUtils.jsm");
+  return PlacesUtils.history;
+});
+
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
                                   "resource://devtools/shared/event-emitter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 
 const {
   normalizeTime,
   SingletonEventManager,
 } = ExtensionUtils;
 
-const History = PlacesUtils.history;
+let nsINavHistoryService = Ci.nsINavHistoryService;
 const TRANSITION_TO_TRANSITION_TYPES_MAP = new Map([
-  ["link", History.TRANSITION_LINK],
-  ["typed", History.TRANSITION_TYPED],
-  ["auto_bookmark", History.TRANSITION_BOOKMARK],
-  ["auto_subframe", History.TRANSITION_EMBED],
-  ["manual_subframe", History.TRANSITION_FRAMED_LINK],
+  ["link", nsINavHistoryService.TRANSITION_LINK],
+  ["typed", nsINavHistoryService.TRANSITION_TYPED],
+  ["auto_bookmark", nsINavHistoryService.TRANSITION_BOOKMARK],
+  ["auto_subframe", nsINavHistoryService.TRANSITION_EMBED],
+  ["manual_subframe", nsINavHistoryService.TRANSITION_FRAMED_LINK],
 ]);
 
 let TRANSITION_TYPE_TO_TRANSITIONS_MAP = new Map();
 for (let [transition, transitionType] of TRANSITION_TO_TRANSITION_TYPES_MAP) {
   TRANSITION_TYPE_TO_TRANSITIONS_MAP.set(transitionType, transition);
 }
 
 function getTransitionType(transition) {
@@ -118,17 +123,17 @@ function getObserver() {
       onPageChanged: function() {},
       onFrecencyChanged: function() {},
       onManyFrecenciesChanged: function() {},
       onDeleteVisits: function(uri, time, guid, reason) {
         this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
       },
     };
     EventEmitter.decorate(_observer);
-    PlacesUtils.history.addObserver(_observer, false);
+    History.addObserver(_observer, false);
   }
   return _observer;
 }
 
 extensions.registerSchemaAPI("history", (extension, context) => {
   return {
     history: {
       addUrl: function(details) {
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -0,0 +1,22 @@
+# scripts
+category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
+category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
+category webextension-scripts commands chrome://browser/content/ext-commands.js
+category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
+category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
+category webextension-scripts history chrome://browser/content/ext-history.js
+category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
+category webextension-scripts tabs chrome://browser/content/ext-tabs.js
+category webextension-scripts utils chrome://browser/content/ext-utils.js
+category webextension-scripts windows chrome://browser/content/ext-windows.js
+
+# schemas
+category webextension-schemas bookmarks chrome://browser/content/schemas/bookmarks.json
+category webextension-schemas browser_action chrome://browser/content/schemas/browser_action.json
+category webextension-schemas commands chrome://browser/content/schemas/commands.json
+category webextension-schemas context_menus chrome://browser/content/schemas/context_menus.json
+category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
+category webextension-schemas history chrome://browser/content/schemas/history.json
+category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
+category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
+category webextension-schemas windows chrome://browser/content/schemas/windows.json
\ No newline at end of file
--- a/browser/components/extensions/moz.build
+++ b/browser/components/extensions/moz.build
@@ -1,12 +1,16 @@
 # -*- 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/.
 
 JAR_MANIFESTS += ['jar.mn']
 
+EXTRA_COMPONENTS += [
+    'extensions-browser.manifest',
+]
+
 DIRS += ['schemas']
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
--- a/browser/components/extensions/test/xpcshell/head.js
+++ b/browser/components/extensions/test/xpcshell/head.js
@@ -10,34 +10,29 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
-Cu.import("resource://gre/modules/ExtensionManagement.jsm");
-
 /* exported normalizeManifest */
 
 let BASE_MANIFEST = {
   "applications": {"gecko": {"id": "test@web.ext"}},
 
   "manifest_version": 2,
 
   "name": "name",
   "version": "0",
 };
 
-ExtensionManagement.registerSchema("chrome://browser/content/schemas/commands.json");
-
 function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) {
   const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
-
   yield Management.lazyInit();
 
   let errors = [];
   let context = {
     url: null,
 
     logError: error => {
       errors.push(error);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -153,19 +153,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/ReaderParent.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
                                   "resource://gre/modules/AddonWatcher.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
-                                  "resource://gre/modules/ExtensionManagement.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
                                   "resource:///modules/ShellService.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
                                   "resource://gre/modules/WindowsRegistry.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
                                    "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
@@ -555,39 +552,25 @@ BrowserGlue.prototype = {
     os.addObserver(this, "flash-plugin-hang", false);
     os.addObserver(this, "xpi-signature-changed", false);
     os.addObserver(this, "autocomplete-did-enter-text", false);
 
     if (AppConstants.NIGHTLY_BUILD) {
       os.addObserver(this, AddonWatcher.TOPIC_SLOW_ADDON_DETECTED, false);
     }
 
-    ExtensionManagement.registerScript("chrome://browser/content/ext-bookmarks.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-browserAction.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-commands.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-contextMenus.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-desktop-runtime.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-history.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-pageAction.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-tabs.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-utils.js");
-    ExtensionManagement.registerScript("chrome://browser/content/ext-windows.js");
-
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/bookmarks.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/browser_action.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/commands.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/context_menus.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/context_menus_internal.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/history.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/page_action.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/tabs.json");
-    ExtensionManagement.registerSchema("chrome://browser/content/schemas/windows.json");
-
     this._flashHangCount = 0;
     this._firstWindowReady = new Promise(resolve => this._firstWindowLoaded = resolve);
+
+    if (AppConstants.platform == "win" ||
+        AppConstants.platform == "macosx") {
+      // Handles prompting to inform about incompatibilites when accessibility
+      // and e10s are active together.
+      E10SAccessibilityCheck.init();
+    }
   },
 
   // cleanup (called on application shutdown)
   _dispose: function BG__dispose() {
     let os = Services.obs;
     os.removeObserver(this, "notifications-open-settings");
     os.removeObserver(this, "prefservice:after-app-defaults");
     os.removeObserver(this, "final-ui-startup");
@@ -1351,22 +1334,17 @@ BrowserGlue.prototype = {
 
       if (willPrompt) {
         Services.tm.mainThread.dispatch(function() {
           DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
         }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
       }
     }
 
-    if (AppConstants.platform == "win" ||
-        AppConstants.platform == "macosx") {
-      // Handles prompting to inform about incompatibilites when accessibility
-      // and e10s are active together.
-      E10SAccessibilityCheck.init();
-    }
+    E10SAccessibilityCheck.onWindowsRestored();
   },
 
   _createExtraDefaultProfile: function () {
     if (!AppConstants.MOZ_DEV_EDITION) {
       return;
     }
     // If Developer Edition is the only installed Firefox version and no other
     // profiles are present, create a second one for use by other versions.
@@ -3019,16 +2997,20 @@ var DefaultBrowserCheck = {
       popup.removeEventListener("command", this);
       popup.remove();
       delete this._notification;
     }
   },
 };
 
 var E10SAccessibilityCheck = {
+  // tracks when an a11y init observer fires prior to the
+  // first window being opening.
+  _wantsPrompt: false,
+
   init: function() {
     Services.obs.addObserver(this, "a11y-init-or-shutdown", true);
     Services.obs.addObserver(this, "quit-application-granted", true);
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
   get forcedOn() {
@@ -3051,16 +3033,23 @@ var E10SAccessibilityCheck = {
           // Update this so users can check this while still running
           Services.prefs.setBoolPref("accessibility.loadedInLastSession", true);
           this._showE10sAccessibilityWarning();
         }
         break;
     }
   },
 
+  onWindowsRestored: function() {
+    if (this._wantsPrompt) {
+      this._wantsPrompt = false;
+      this._showE10sAccessibilityWarning();
+    }
+  },
+
   _warnedAboutAccessibility: false,
 
   _showE10sAccessibilityWarning: function() {
     // We don't prompt about a11y incompat if e10s is off.
     if (!Services.appinfo.browserTabsRemoteAutostart) {
       return;
     }
 
@@ -3072,21 +3061,24 @@ var E10SAccessibilityCheck = {
 
     // Only prompt once per session
     if (this._warnedAboutAccessibility) {
       return;
     }
     this._warnedAboutAccessibility = true;
 
     let win = RecentWindow.getMostRecentBrowserWindow();
-    let browser = win.gBrowser.selectedBrowser;
-    if (!win) {
-      Services.console.logStringMessage("Accessibility support is partially disabled due to compatibility issues with new features.");
+    if (!win || !win.gBrowser || !win.gBrowser.selectedBrowser) {
+      Services.console.logStringMessage(
+          "Accessibility support is partially disabled due to compatibility issues with new features.");
+      this._wantsPrompt = true;
+      this._warnedAboutAccessibility = false;
       return;
     }
+    let browser = win.gBrowser.selectedBrowser;
 
     // We disable a11y for content and prompt on the chrome side letting
     // a11y users know they need to disable e10s and restart.
     let promptMessage = win.gNavigatorBundle.getFormattedString(
                           "e10s.accessibilityNotice.mainMessage2",
                           [gBrandBundle.GetStringFromName("brandShortName")]
                         );
     let notification;
--- a/browser/components/sessionstore/SessionHistory.jsm
+++ b/browser/components/sessionstore/SessionHistory.jsm
@@ -165,26 +165,26 @@ var SessionHistoryInternal = {
       entry.scrollRestorationIsManual = true;
     } else {
       let x = {}, y = {};
       shEntry.getScrollPosition(x, y);
       if (x.value != 0 || y.value != 0)
         entry.scroll = x.value + "," + y.value;
     }
 
-    // Collect owner data for the current history entry.
+    // Collect triggeringPrincipal data for the current history entry.
     try {
-      let owner = this.serializeOwner(shEntry);
-      if (owner) {
-        entry.owner_b64 = owner;
+      let triggeringPrincipal = this.serializeTriggeringPrincipal(shEntry);
+      if (triggeringPrincipal) {
+        entry.triggeringPrincipal_b64 = triggeringPrincipal;
       }
     } catch (ex) {
       // Not catching anything specific here, just possible errors
       // from writeCompoundObject() and the like.
-      debug("Failed serializing owner data: " + ex);
+      debug("Failed serializing triggeringPrincipal data: " + ex);
     }
 
     entry.docIdentifier = shEntry.BFCacheEntry.ID;
 
     if (shEntry.stateData != null) {
       entry.structuredCloneState = shEntry.stateData.getDataAsBase64();
       entry.structuredCloneVersion = shEntry.stateData.formatVersion;
     }
@@ -214,46 +214,46 @@ var SessionHistoryInternal = {
         entry.children = children;
       }
     }
 
     return entry;
   },
 
   /**
-   * Serialize owner data contained in the given session history entry.
+   * Serialize triggeringPrincipal data contained in the given session history entry.
    *
    * @param shEntry
    *        The session history entry.
-   * @return The base64 encoded owner data.
+   * @return The base64 encoded triggeringPrincipal data.
    */
-  serializeOwner: function (shEntry) {
-    if (!shEntry.owner) {
+  serializeTriggeringPrincipal: function (shEntry) {
+    if (!shEntry.triggeringPrincipal) {
       return null;
     }
 
     let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].
                        createInstance(Ci.nsIObjectOutputStream);
     let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
     pipe.init(false, false, 0, 0xffffffff, null);
     binaryStream.setOutputStream(pipe.outputStream);
-    binaryStream.writeCompoundObject(shEntry.owner, Ci.nsISupports, true);
+    binaryStream.writeCompoundObject(shEntry.triggeringPrincipal, Ci.nsIPrincipal, true);
     binaryStream.close();
 
     // Now we want to read the data from the pipe's input end and encode it.
     let scriptableStream = Cc["@mozilla.org/binaryinputstream;1"].
                            createInstance(Ci.nsIBinaryInputStream);
     scriptableStream.setInputStream(pipe.inputStream);
-    let ownerBytes =
+    let triggeringPrincipalBytes =
       scriptableStream.readByteArray(scriptableStream.available());
 
     // We can stop doing base64 encoding once our serialization into JSON
     // is guaranteed to handle all chars in strings, including embedded
     // nulls.
-    return btoa(String.fromCharCode.apply(null, ownerBytes));
+    return btoa(String.fromCharCode.apply(null, triggeringPrincipalBytes));
   },
 
   /**
    * Restores session history data for a given docShell.
    *
    * @param docShell
    *        The docShell that owns the session history.
    * @param tabData
@@ -374,26 +374,34 @@ var SessionHistoryInternal = {
         docIdentMap[entry.docIdentifier] = matchingEntry;
       }
       else {
         shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
         childDocIdents = matchingEntry.childDocIdents;
       }
     }
 
+    // The field entry.owner_b64 got renamed to entry.triggeringPricipal_b64 in
+    // Bug 1286472. To remain backward compatible we still have to support that
+    // field for a few cycles before we can remove it within Bug 1289785.
     if (entry.owner_b64) {
-      var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
-                       createInstance(Ci.nsIStringInputStream);
-      var binaryData = atob(entry.owner_b64);
-      ownerInput.setData(binaryData, binaryData.length);
+      entry.triggeringPricipal_b64 = entry.owner_b64;
+      delete entry.owner_b64;
+    }
+
+    if (entry.triggeringPrincipal_b64) {
+      var triggeringPrincipalInput = Cc["@mozilla.org/io/string-input-stream;1"]
+                                       .createInstance(Ci.nsIStringInputStream);
+      var binaryData = atob(entry.triggeringPrincipal_b64);
+      triggeringPrincipalInput.setData(binaryData, binaryData.length);
       var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
                          createInstance(Ci.nsIObjectInputStream);
-      binaryStream.setInputStream(ownerInput);
+      binaryStream.setInputStream(triggeringPrincipalInput);
       try { // Catch possible deserialization exceptions
-        shEntry.owner = binaryStream.readObject(true);
+        shEntry.triggeringPrincipal = binaryStream.readObject(true);
       } catch (ex) { debug(ex); }
     }
 
     if (entry.children && shEntry instanceof Ci.nsISHContainer) {
       for (var i = 0; i < entry.children.length; i++) {
         //XXXzpao Wallpaper patch for bug 514751
         if (!entry.children[i].url)
           continue;
--- a/browser/extensions/e10srollout/bootstrap.js
+++ b/browser/extensions/e10srollout/bootstrap.js
@@ -1,31 +1,37 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
+"use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/UpdateUtils.jsm");
 
  // The amount of people to be part of e10s
 const TEST_THRESHOLD = {
   "beta"    : 0.5,  // 50%
 };
 
+const ADDON_ROLLOUT_POLICY = {
+  "beta"    : "2a", // Set 2 + any WebExtension
+};
+
 const PREF_COHORT_SAMPLE       = "e10s.rollout.cohortSample";
 const PREF_COHORT_NAME         = "e10s.rollout.cohort";
 const PREF_E10S_OPTED_IN       = "browser.tabs.remote.autostart";
 const PREF_E10S_FORCE_ENABLED  = "browser.tabs.remote.force-enable";
 const PREF_E10S_FORCE_DISABLED = "browser.tabs.remote.force-disable";
 const PREF_TOGGLE_E10S         = "browser.tabs.remote.autostart.2";
-
+const PREF_E10S_ADDON_POLICY   = "extensions.e10s.rollout.policy";
+const PREF_E10S_HAS_NONEXEMPT_ADDON = "extensions.e10s.rollout.hasAddon";
 
 function startup() {
   // In theory we only need to run this once (on install()), but
   // it's better to also run it on every startup. If the user has
   // made manual changes to the prefs, this will keep the data
   // reported more accurate.
   // It's also fine (and preferred) to just do it here on startup
   // (instead of observing prefs), because e10s takes a restart
@@ -48,30 +54,48 @@ function defineCohort() {
   cohortDefinedOnThisSession = true;
 
   let updateChannel = UpdateUtils.getUpdateChannel(false);
   if (!(updateChannel in TEST_THRESHOLD)) {
     setCohort("unsupportedChannel");
     return;
   }
 
+  let addonPolicy = "unknown";
+  if (updateChannel in ADDON_ROLLOUT_POLICY) {
+    addonPolicy = ADDON_ROLLOUT_POLICY[updateChannel];
+    Preferences.set(PREF_E10S_ADDON_POLICY, ADDON_ROLLOUT_POLICY[updateChannel]);
+    // This is also the proper place to set the blocklist pref
+    // in case it is necessary.
+  } else {
+    Preferences.reset(PREF_E10S_ADDON_POLICY);
+  }
+
   let userOptedOut = optedOut();
   let userOptedIn = optedIn();
   let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0);
   let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]);
+  let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
+
+  let cohortPrefix = "";
+  if (disqualified) {
+    cohortPrefix = "disqualified-";
+  } else if (hasNonExemptAddon) {
+    cohortPrefix = `addons-set${addonPolicy}-`;
+  }
 
   if (userOptedOut) {
     setCohort("optedOut");
   } else if (userOptedIn) {
     setCohort("optedIn");
   } else if (testGroup) {
-    setCohort(disqualified ? "disqualified-test" : "test");
+    setCohort(`${cohortPrefix}test`);
     Preferences.set(PREF_TOGGLE_E10S, true);
   } else {
-    setCohort(disqualified ? "disqualified-control" : "control");
+    setCohort(`${cohortPrefix}control`);
     Preferences.reset(PREF_TOGGLE_E10S);
   }
 }
 
 function shutdown(data, reason) {
 }
 
 function uninstall() {
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -569,16 +569,20 @@
 @RESPATH@/components/TestInterfaceJS.js
 @RESPATH@/components/TestInterfaceJS.manifest
 @RESPATH@/components/TestInterfaceJSMaplike.js
 #endif
 
 @RESPATH@/components/PACGenerator.js
 @RESPATH@/components/PACGenerator.manifest
 
+; [Extensions]
+@RESPATH@/components/extensions-toolkit.manifest
+@RESPATH@/browser/components/extensions-browser.manifest
+
 ; Modules
 @RESPATH@/browser/modules/*
 @RESPATH@/modules/*
 
 ; Safe Browsing
 #ifdef MOZ_URL_CLASSIFIER
 @RESPATH@/components/nsURLClassifier.manifest
 @RESPATH@/components/nsUrlClassifierHashCompleter.js
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -42,35 +42,65 @@ def windows_sdk_dir(value, host):
         return value
     if host.kernel != 'WINNT':
         return ()
 
     return tuple(x[1] for x in get_registry_values(
         r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots'
         r'\KitsRoot*'))
 
+# The Windows SDK 8.1 and 10 have different layouts. The former has
+# $SDK/include/$subdir, while the latter has $SDK/include/$version/$subdir.
+# The vcvars* scripts don't actually care about the version, they just take
+# the last.
+@imports('os')
+@imports('re')
+@imports(_from='__builtin__', _import='sorted')
+@imports(_from='__builtin__', _import='WindowsError')
+def get_include_dir(sdk, subdir):
+    base = os.path.join(sdk, 'include')
+    try:
+        subdirs = [d for d in os.listdir(base)
+                   if os.path.isdir(os.path.join(base, d))]
+    except WindowsError:
+        subdirs = []
+    if not subdirs:
+        return None
+    if subdir in subdirs:
+        return os.path.join(base, subdir)
+    # At this point, either we have an incomplete or invalid SDK directory,
+    # or we exclusively have version numbers in subdirs.
+    versions = sorted((Version(d) for d in subdirs), reverse=True)
+    # Version('non-number').major is 0, so if the biggest version we have is
+    # 0, we have a problem.
+    if versions[0].major == 0:
+        return None
+    path = os.path.join(base, str(versions[0]), subdir)
+    return path if os.path.isdir(path) else None
+
+
 @imports(_from='mozbuild.shellutil', _import='quote')
 def valid_windows_sdk_dir_result(value):
     if value:
         return '0x%04x in %s' % (value.version, quote(value.path))
 
 @depends_win(c_compiler, windows_sdk_dir, valid_windows_version,
              'WINDOWSSDKDIR')
 @checking('for Windows SDK', valid_windows_sdk_dir_result)
 @imports(_from='__builtin__', _import='sorted')
 @imports(_from='textwrap', _import='dedent')
 def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
                           windows_sdk_dir_env):
     if windows_sdk_dir_env:
         windows_sdk_dir_env = windows_sdk_dir_env[0]
     sdks = {}
     for d in windows_sdk_dir:
-        um_dir = os.path.join(d, 'include', 'um')
-        shared_dir = os.path.join(d, 'include', 'shared')
-        if os.path.isdir(um_dir) and os.path.isdir(shared_dir):
+        um_dir = get_include_dir(d, 'um')
+        shared_dir = get_include_dir(d, 'shared')
+        if um_dir and shared_dir:
             check = dedent('''\
             #include <winsdkver.h>
             WINVER_MAXVER
             ''')
             result = try_preprocess(compiler.wrapper + [compiler.compiler] +
                                     compiler.flags +
                                     ['-I', um_dir, '-I', shared_dir], 'C',
                                     check)
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -362,18 +362,17 @@ nsScriptSecurityManager::GetChannelResul
             return NS_OK;
         }
 
         bool forceInterit = loadInfo->GetForceInheritPrincipal();
         if (aIgnoreSandboxing && !forceInterit) {
           // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of
           // sandboxing:
           if (loadInfo->GetLoadingSandboxed() &&
-              (loadInfo->GetSecurityFlags() &
-               nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED)) {
+              loadInfo->GetForceInheritPrincipalDropped()) {
             forceInterit = true;
           }
         }
         if (forceInterit) {
             NS_ADDREF(*aPrincipal = loadInfo->TriggeringPrincipal());
             return NS_OK;
         }
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1255,19 +1255,19 @@ nsDocShell::LoadURI(nsIURI* aURI,
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> referrer;
   nsCOMPtr<nsIURI> originalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIInputStream> postStream;
   nsCOMPtr<nsIInputStream> headersStream;
-  nsCOMPtr<nsISupports> owner;
-  bool inheritOwner = false;
-  bool ownerIsExplicit = false;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+  bool inheritPrincipal = false;
+  bool principalIsExplicit = false;
   bool sendReferrer = true;
   uint32_t referrerPolicy = mozilla::net::RP_Default;
   bool isSrcdoc = false;
   nsCOMPtr<nsISHEntry> shEntry;
   nsXPIDLString target;
   nsAutoString srcdoc;
   nsCOMPtr<nsIDocShell> sourceDocShell;
   nsCOMPtr<nsIURI> baseURI;
@@ -1286,19 +1286,19 @@ nsDocShell::LoadURI(nsIURI* aURI,
     aLoadInfo->GetReferrer(getter_AddRefs(referrer));
     aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
     aLoadInfo->GetLoadReplace(&loadReplace);
     nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
     aLoadInfo->GetLoadType(&lt);
     // Get the appropriate loadType from nsIDocShellLoadInfo type
     loadType = ConvertDocShellLoadInfoToLoadType(lt);
 
-    aLoadInfo->GetOwner(getter_AddRefs(owner));
-    aLoadInfo->GetInheritOwner(&inheritOwner);
-    aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
+    aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
+    aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
+    aLoadInfo->GetPrincipalIsExplicit(&principalIsExplicit);
     aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
     aLoadInfo->GetTarget(getter_Copies(target));
     aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
     aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
     aLoadInfo->GetSendReferrer(&sendReferrer);
     aLoadInfo->GetReferrerPolicy(&referrerPolicy);
     aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
     aLoadInfo->GetSrcdocData(srcdoc);
@@ -1444,84 +1444,80 @@ nsDocShell::LoadURI(nsIURI* aURI,
   // LOAD_STOP_CONTENT:  location.href = ..., location.assign(...)
   if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
       ShouldBlockLoadingForBackButton()) {
     return NS_OK;
   }
 
   // Perform the load...
 
-  // We need an owner (a referring principal).
+  // We need a triggeringPrincipal (a referring principal).
   //
-  // If ownerIsExplicit is not set there are 4 possibilities:
+  // If principalIsExplicit is not set there are 4 possibilities:
   // (1) If the system principal or an expanded principal was passed
   //     in and we're a typeContent docshell, inherit the principal
   //     from the current document instead.
   // (2) In all other cases when the principal passed in is not null,
   //     use that principal.
   // (3) If the caller has allowed inheriting from the current document,
   //     or if we're being called from system code (eg chrome JS or pure
-  //     C++) then inheritOwner should be true and InternalLoad will get
-  //     an owner from the current document. If none of these things are
+  //     C++) then inheritPrincipal should be true and InternalLoad will get
+  //     a principal from the current document. If none of these things are
   //     true, then
-  // (4) we pass a null owner into the channel, and an owner will be
+  // (4) we don't pass a principal into the channel, and a principal will be
   //     created later from the channel's internal data.
   //
-  // If ownerIsExplicit *is* set, there are 4 possibilities
+  // If principalIsExplicit *is* set, there are 4 possibilities
   // (1) If the system principal or an expanded principal was passed in
   //     and we're a typeContent docshell, return an error.
   // (2) In all other cases when the principal passed in is not null,
   //     use that principal.
   // (3) If the caller has allowed inheriting from the current document,
-  //     then inheritOwner should be true and InternalLoad will get an owner
-  //     from the current document. If none of these things are true, then
-  // (4) we pass a null owner into the channel, and an owner will be
+  //     then inheritPrincipal should be true and InternalLoad will get
+  //     a principal from the current document. If none of these things are
+  //     true, then
+  // (4) we dont' pass a principal into the channel, and a principal will be
   //     created later from the channel's internal data.
-  //
-  // NOTE: This all only works because the only thing the owner is used
-  //       for in InternalLoad is data:, javascript:, and about:blank
-  //       URIs.  For other URIs this would all be dead wrong!
-
-  nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
-  if (owner && mItemType != typeChrome) {
-    if (nsContentUtils::IsSystemPrincipal(ownerPrincipal)) {
-      if (ownerIsExplicit) {
+  nsCOMPtr<nsIPrincipal> principalToInheritAttributesFrom = triggeringPrincipal;
+  if (triggeringPrincipal && mItemType != typeChrome) {
+    if (nsContentUtils::IsSystemPrincipal(principalToInheritAttributesFrom)) {
+      if (principalIsExplicit) {
         return NS_ERROR_DOM_SECURITY_ERR;
       }
-      owner = nullptr;
-      inheritOwner = true;
-    } else if (nsContentUtils::IsExpandedPrincipal(ownerPrincipal)) {
-      if (ownerIsExplicit) {
+      triggeringPrincipal = nullptr;
+      inheritPrincipal = true;
+    } else if (nsContentUtils::IsExpandedPrincipal(principalToInheritAttributesFrom)) {
+      if (principalIsExplicit) {
         return NS_ERROR_DOM_SECURITY_ERR;
       }
       // Don't inherit from the current page.  Just do the safe thing
       // and pretend that we were loaded by a nullprincipal.
       //
       // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
       // have origin attributes.
-      owner = nsNullPrincipal::CreateWithInheritedAttributes(this);
-      inheritOwner = false;
-    }
-  }
-  if (!owner && !inheritOwner && !ownerIsExplicit) {
+      triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this);
+      inheritPrincipal = false;
+    }
+  }
+  if (!triggeringPrincipal && !inheritPrincipal && !principalIsExplicit) {
     // See if there's system or chrome JS code running
-    inheritOwner = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
-  }
-
-  if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
-    inheritOwner = false;
-    owner = ownerPrincipal ?
-              nsNullPrincipal::CreateWithInheritedAttributes(ownerPrincipal) :
-              nsNullPrincipal::CreateWithInheritedAttributes(this);
+    inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
+  }
+
+  if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
+    inheritPrincipal = false;
+    triggeringPrincipal = principalToInheritAttributesFrom ?
+      nsNullPrincipal::CreateWithInheritedAttributes(principalToInheritAttributesFrom) :
+      nsNullPrincipal::CreateWithInheritedAttributes(this);
   }
 
   uint32_t flags = 0;
 
-  if (inheritOwner) {
-    flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
+  if (inheritPrincipal) {
+    flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
   }
 
   if (!sendReferrer) {
     flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
   }
 
   if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
     flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
@@ -1543,17 +1539,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
   return InternalLoad(aURI,
                       originalURI,
                       loadReplace,
                       referrer,
                       referrerPolicy,
-                      owner,
+                      triggeringPrincipal,
                       flags,
                       target.get(),
                       nullptr,      // No type hint
                       NullString(), // No forced download
                       postStream,
                       headersStream,
                       loadType,
                       nullptr, // No SHEntry
@@ -1590,42 +1586,39 @@ nsDocShell::LoadStream(nsIInputStream* a
     // For now, just use a bogus protocol called "internal"
     rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   uint32_t loadType = LOAD_NORMAL;
-  nsCOMPtr<nsIPrincipal> requestingPrincipal;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   if (aLoadInfo) {
     nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
     (void)aLoadInfo->GetLoadType(&lt);
     // Get the appropriate LoadType from nsIDocShellLoadInfo type
     loadType = ConvertDocShellLoadInfoToLoadType(lt);
-
-    nsCOMPtr<nsISupports> owner;
-    aLoadInfo->GetOwner(getter_AddRefs(owner));
-    requestingPrincipal = do_QueryInterface(owner);
+    aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
   }
 
   NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
 
   mLoadType = loadType;
 
-  if (!requestingPrincipal) {
-    requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+  if (!triggeringPrincipal) {
+    triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
   }
 
   // build up a channel for this stream.
   nsCOMPtr<nsIChannel> channel;
   nsresult rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
                                          uri,
                                          aStream,
-                                         requestingPrincipal,
+                                         triggeringPrincipal,
                                          nsILoadInfo::SEC_NORMAL,
                                          nsIContentPolicy::TYPE_OTHER,
                                          aContentType,
                                          aContentCharset);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
   NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
@@ -5353,17 +5346,17 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
   errorPageUrl.AppendASCII(escapedDescription.get());
 
   nsCOMPtr<nsIURI> errorPageURI;
   rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return InternalLoad(errorPageURI, nullptr, false, nullptr,
                       mozilla::net::RP_Default,
-                      nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr,
+                      nullptr, INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL, nullptr,
                       nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
                       nullptr, true, NullString(), this, nullptr, nullptr,
                       nullptr);
 }
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags)
 {
@@ -6767,20 +6760,20 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI
    */
   loadInfo->SetSendReferrer(false);
 
   /* for most refreshes the current URI is an appropriate
    * internal referrer
    */
   loadInfo->SetReferrer(mCurrentURI);
 
-  /* Don't ever "guess" on which owner to use to avoid picking
-   * the current owner.
+  /* Don't ever "guess" on which principal to use to avoid picking
+   * the current principal.
    */
-  loadInfo->SetOwnerIsExplicit(true);
+  loadInfo->SetPrincipalIsExplicit(true);
 
   /* Check if this META refresh causes a redirection
    * to another site.
    */
   bool equalUri = false;
   nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
   if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
       aDelay <= REFRESH_REDIRECT_TIMER) {
@@ -9579,30 +9572,30 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
 }
 
 class InternalLoadEvent : public Runnable
 {
 public:
   InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI,
                     nsIURI* aOriginalURI, bool aLoadReplace,
                     nsIURI* aReferrer, uint32_t aReferrerPolicy,
-                    nsISupports* aOwner, uint32_t aFlags,
+                    nsIPrincipal* aTriggeringPrincipal, uint32_t aFlags,
                     const char* aTypeHint, nsIInputStream* aPostData,
                     nsIInputStream* aHeadersData, uint32_t aLoadType,
                     nsISHEntry* aSHEntry, bool aFirstParty,
                     const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
                     nsIURI* aBaseURI)
     : mSrcdoc(aSrcdoc)
     , mDocShell(aDocShell)
     , mURI(aURI)
     , mOriginalURI(aOriginalURI)
     , mLoadReplace(aLoadReplace)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
-    , mOwner(aOwner)
+    , mTriggeringPrincipal(aTriggeringPrincipal)
     , mPostData(aPostData)
     , mHeadersData(aHeadersData)
     , mSHEntry(aSHEntry)
     , mFlags(aFlags)
     , mLoadType(aLoadType)
     , mFirstParty(aFirstParty)
     , mSourceDocShell(aSourceDocShell)
     , mBaseURI(aBaseURI)
@@ -9615,17 +9608,17 @@ public:
 
   NS_IMETHOD
   Run()
   {
     return mDocShell->InternalLoad(mURI, mOriginalURI,
                                    mLoadReplace,
                                    mReferrer,
                                    mReferrerPolicy,
-                                   mOwner, mFlags,
+                                   mTriggeringPrincipal, mFlags,
                                    nullptr, mTypeHint.get(),
                                    NullString(), mPostData, mHeadersData,
                                    mLoadType, mSHEntry, mFirstParty,
                                    mSrcdoc, mSourceDocShell, mBaseURI,
                                    nullptr, nullptr);
   }
 
 private:
@@ -9635,17 +9628,17 @@ private:
   nsString mSrcdoc;
 
   RefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   bool mLoadReplace;
   nsCOMPtr<nsIURI> mReferrer;
   uint32_t mReferrerPolicy;
-  nsCOMPtr<nsISupports> mOwner;
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIInputStream> mPostData;
   nsCOMPtr<nsIInputStream> mHeadersData;
   nsCOMPtr<nsISHEntry> mSHEntry;
   uint32_t mFlags;
   uint32_t mLoadType;
   bool mFirstParty;
   nsCOMPtr<nsIDocShell> mSourceDocShell;
   nsCOMPtr<nsIURI> mBaseURI;
@@ -9702,17 +9695,17 @@ nsDocShell::IsAboutNewtab(nsIURI* aURI)
 }
 
 NS_IMETHODIMP
 nsDocShell::InternalLoad(nsIURI* aURI,
                          nsIURI* aOriginalURI,
                          bool aLoadReplace,
                          nsIURI* aReferrer,
                          uint32_t aReferrerPolicy,
-                         nsISupports* aOwner,
+                         nsIPrincipal* aTriggeringPrincipal,
                          uint32_t aFlags,
                          const char16_t* aWindowTarget,
                          const char* aTypeHint,
                          const nsAString& aFileName,
                          nsIInputStream* aPostData,
                          nsIInputStream* aHeadersData,
                          uint32_t aLoadType,
                          nsISHEntry* aSHEntry,
@@ -9820,17 +9813,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   }
 
   nsISupports* context = requestingElement;
   if (!context) {
     context = ToSupports(mScriptGlobal);
   }
 
   // XXXbz would be nice to know the loading principal here... but we don't
-  nsCOMPtr<nsIPrincipal> loadingPrincipal = do_QueryInterface(aOwner);
+  nsCOMPtr<nsIPrincipal> loadingPrincipal = aTriggeringPrincipal;
   if (!loadingPrincipal && aReferrer) {
     rv =
       CreatePrincipalFromReferrer(aReferrer, getter_AddRefs(loadingPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = NS_CheckContentLoadPolicy(contentType,
                                  aURI,
@@ -9843,36 +9836,36 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
     if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
       return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
     }
 
     return NS_ERROR_CONTENT_BLOCKED;
   }
 
-  nsCOMPtr<nsISupports> owner(aOwner);
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
   //
-  // Get an owner from the current document if necessary.  Note that we only
+  // Get a principal from the current document if necessary.  Note that we only
   // do this for URIs that inherit a security context and local file URIs;
   // in particular we do NOT do this for about:blank.  This way, random
-  // about:blank loads that have no owner (which basically means they were
+  // about:blank loads that have no principal (which basically means they were
   // done by someone from chrome manually messing with our nsIWebNavigation
   // or by C++ setting document.location) don't get a funky principal.  If
   // callers want something interesting to happen with the about:blank
-  // principal in this case, they should pass an owner in.
+  // principal in this case, they should pass aTriggeringPrincipal in.
   //
   {
     bool inherits;
-    // One more twist: Don't inherit the owner for external loads.
-    if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
-        (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
+    // One more twist: Don't inherit the principal for external loads.
+    if (aLoadType != LOAD_NORMAL_EXTERNAL && !triggeringPrincipal &&
+        (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
         NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
                                                                 &inherits)) &&
         inherits) {
-      owner = GetInheritedPrincipal(true);
+      triggeringPrincipal = GetInheritedPrincipal(true);
     }
   }
 
   // Don't allow loads that would inherit our security context
   // if this document came from an unsafe channel.
   {
     bool willInherit;
     // This condition needs to match the one in
@@ -9903,17 +9896,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   // Resolve the window target before going any further...
   // If the load has been targeted to another DocShell, then transfer the
   // load to it...
   //
   if (aWindowTarget && *aWindowTarget) {
     // We've already done our owner-inheriting.  Mask out that bit, so we
     // don't try inheriting an owner from the target window if we came up
     // with a null owner above.
-    aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
+    aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
 
     bool isNewWindow = false;
     if (!targetDocShell) {
       // If the docshell's document is sandboxed, only open a new window
       // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
       // (i.e. if allow-popups is specified)
       NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
       nsIDocument* doc = mContentViewer->GetDocument();
@@ -9966,17 +9959,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     // window target name from to prevent recursive retargeting!
     //
     if (NS_SUCCEEDED(rv) && targetDocShell) {
       rv = targetDocShell->InternalLoad(aURI,
                                         aOriginalURI,
                                         aLoadReplace,
                                         aReferrer,
                                         aReferrerPolicy,
-                                        owner,
+                                        triggeringPrincipal,
                                         aFlags,
                                         nullptr,         // No window target
                                         aTypeHint,
                                         NullString(),    // No forced download
                                         aPostData,
                                         aHeadersData,
                                         aLoadType,
                                         aSHEntry,
@@ -10045,18 +10038,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // create extra history entries.
       if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       }
 
       // Do this asynchronously
       nsCOMPtr<nsIRunnable> ev =
         new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
-                              aReferrer, aReferrerPolicy, aOwner, aFlags,
-                              aTypeHint, aPostData, aHeadersData,
+                              aReferrer, aReferrerPolicy, aTriggeringPrincipal,
+                              aFlags, aTypeHint, aPostData, aHeadersData,
                               aLoadType, aSHEntry, aFirstParty, aSrcdoc,
                               aSourceDocShell, aBaseURI);
       return NS_DispatchToCurrentThread(ev);
     }
 
     // Just ignore this load attempt
     return NS_OK;
   }
@@ -10218,29 +10211,29 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       nsCOMPtr<nsIDocument> doc = GetDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
       doc->SetDocumentURI(aURI);
 
       /* This is a anchor traversal with in the same page.
        * call OnNewURI() so that, this traversal will be
        * recorded in session and global history.
        */
-      nsCOMPtr<nsISupports> owner;
+      nsCOMPtr<nsIPrincipal> triggeringPrincipal;
       if (mOSHE) {
-        mOSHE->GetOwner(getter_AddRefs(owner));
+        mOSHE->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
       }
       // Pass true for aCloneSHChildren, since we're not
       // changing documents here, so all of our subframes are
       // still relevant to the new session history entry.
       //
       // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
       // flag on firing onLocationChange(...).
       // Anyway, aCloneSHChildren param is simply reflecting
       // doShortCircuitedLoad in this scope.
-      OnNewURI(aURI, nullptr, owner, mLoadType, true, true, true);
+      OnNewURI(aURI, nullptr, triggeringPrincipal, mLoadType, true, true, true);
 
       nsCOMPtr<nsIInputStream> postData;
       nsCOMPtr<nsISupports> cacheKey;
 
       bool scrollRestorationIsManual = false;
       if (mOSHE) {
         /* save current position of scroller(s) (bug 59774) */
         mOSHE->SetScrollPosition(cx, cy);
@@ -10564,17 +10557,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                       nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, this);
   net::PredictorPredict(aURI, nullptr,
                         nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
 
   nsCOMPtr<nsIRequest> req;
   rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer,
                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                  aReferrerPolicy,
-                 owner, aTypeHint, aFileName, aPostData, aHeadersData,
+                 triggeringPrincipal, aTypeHint, aFileName, aPostData, aHeadersData,
                  aFirstParty, aDocShell, getter_AddRefs(req),
                  (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
                  srcdoc, aBaseURI, contentType);
   if (req && aRequest) {
     NS_ADDREF(*aRequest = req);
   }
@@ -10643,17 +10636,17 @@ nsDocShell::GetInheritedPrincipal(bool a
 
 nsresult
 nsDocShell::DoURILoad(nsIURI* aURI,
                       nsIURI* aOriginalURI,
                       bool aLoadReplace,
                       nsIURI* aReferrerURI,
                       bool aSendReferrer,
                       uint32_t aReferrerPolicy,
-                      nsISupports* aOwner,
+                      nsIPrincipal* aTriggeringPrincipal,
                       const char* aTypeHint,
                       const nsAString& aFileName,
                       nsIInputStream* aPostData,
                       nsIInputStream* aHeadersData,
                       bool aFirstParty,
                       nsIDocShell** aDocShell,
                       nsIRequest** aRequest,
                       bool aIsNewWindowTarget,
@@ -10784,17 +10777,17 @@ nsDocShell::DoURILoad(nsIURI* aURI,
   // only inherit if we have a triggeringPrincipal
   bool inherit = false;
 
   // Getting the right triggeringPrincipal needs to be updated and is only
   // ready for use once bug 1182569 landed.
   // Until then, we cannot rely on the triggeringPrincipal for TYPE_DOCUMENT
   // or TYPE_SUBDOCUMENT loads.  Notice the triggeringPrincipal falls back to
   // systemPrincipal below.
-  nsCOMPtr<nsIPrincipal> triggeringPrincipal = do_QueryInterface(aOwner);
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
   if (triggeringPrincipal) {
     inherit = nsContentUtils::ChannelShouldInheritPrincipal(
       triggeringPrincipal,
       aURI,
       true, // aInheritForAboutBlank
       isSrcdoc);
   } else if (!triggeringPrincipal && aReferrerURI) {
     rv = CreatePrincipalFromReferrer(aReferrerURI,
@@ -11425,22 +11418,23 @@ nsDocShell::SetupReferrerFromChannel(nsI
     rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
     if (NS_SUCCEEDED(rv)) {
       SetReferrerPolicy(referrerPolicy);
     }
   }
 }
 
 bool
-nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel, nsISupports* aOwner,
+nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
+                     nsIPrincipal* aTriggeringPrincipal,
                      uint32_t aLoadType, bool aFireOnLocationChange,
                      bool aAddToGlobalHistory, bool aCloneSHChildren)
 {
   NS_PRECONDITION(aURI, "uri is null");
-  NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
+  NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
     nsAutoCString spec;
     aURI->GetSpec(spec);
 
     nsAutoCString chanName;
     if (aChannel) {
@@ -11609,18 +11603,18 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsICh
 
   if (updateSHistory) {
     // Update session history if necessary...
     if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
       /* This is  a fresh page getting loaded for the first time
        *.Create a Entry for it and add it to SH, if this is the
        * rootDocShell
        */
-      (void)AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren,
-                                getter_AddRefs(mLSHE));
+      (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
+                                aCloneSHChildren, getter_AddRefs(mLSHE));
     }
   }
 
   // If this is a POST request, we do not want to include this in global
   // history.
   if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
     nsCOMPtr<nsIURI> previousURI;
     uint32_t previousFlags = 0;
@@ -12071,21 +12065,22 @@ nsDocShell::ShouldAddToSessionHistory(ns
     }
   }
 
   return true;
 }
 
 nsresult
 nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
-                                nsISupports* aOwner, bool aCloneChildren,
+                                nsIPrincipal* aTriggeringPrincipal,
+                                bool aCloneChildren,
                                 nsISHEntry** aNewEntry)
 {
   NS_PRECONDITION(aURI, "uri is null");
-  NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
+  NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
     nsAutoCString spec;
     aURI->GetSpec(spec);
 
     nsAutoCString chanName;
     if (aChannel) {
@@ -12143,17 +12138,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
 
   // Get the post data & referrer
   nsCOMPtr<nsIInputStream> inputStream;
   nsCOMPtr<nsIURI> originalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy = mozilla::net::RP_Default;
   nsCOMPtr<nsISupports> cacheKey;
-  nsCOMPtr<nsISupports> owner = aOwner;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
   bool expired = false;
   bool discardLayoutState = false;
   nsCOMPtr<nsICacheInfoChannel> cacheChannel;
   if (aChannel) {
     cacheChannel = do_QueryInterface(aChannel);
 
     /* If there is a caching channel, get the Cache Key and store it
      * in SH.
@@ -12176,50 +12171,54 @@ nsDocShell::AddToSessionHistory(nsIURI* 
       uint32_t loadFlags;
       aChannel->GetLoadFlags(&loadFlags);
       loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
       httpChannel->GetReferrer(getter_AddRefs(referrerURI));
       httpChannel->GetReferrerPolicy(&referrerPolicy);
 
       discardLayoutState = ShouldDiscardLayoutState(httpChannel);
     }
+    // XXX Bug 1286838: Replace channel owner with loadInfo triggeringPrincipal
+    nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
-    if (!owner) {
+    triggeringPrincipal = do_QueryInterface(owner);
+
+    if (!triggeringPrincipal) {
       nsCOMPtr<nsILoadInfo> loadInfo;
       aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
       if (loadInfo) {
         // For now keep storing just the principal in the SHEntry.
         if (loadInfo->GetLoadingSandboxed()) {
           if (loadInfo->LoadingPrincipal()) {
-            owner = nsNullPrincipal::CreateWithInheritedAttributes(
+            triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(
               loadInfo->LoadingPrincipal());
           } else {
             // get the OriginAttributes
             NeckoOriginAttributes nAttrs;
             loadInfo->GetOriginAttributes(&nAttrs);
             PrincipalOriginAttributes pAttrs;
             pAttrs.InheritFromNecko(nAttrs);
 
-            owner = nsNullPrincipal::Create(pAttrs);
+            triggeringPrincipal = nsNullPrincipal::Create(pAttrs);
           }
         } else if (loadInfo->GetForceInheritPrincipal()) {
-          owner = loadInfo->TriggeringPrincipal();
+          triggeringPrincipal = loadInfo->TriggeringPrincipal();
         }
       }
     }
   }
 
   // Title is set in nsDocShell::SetTitle()
-  entry->Create(aURI,              // uri
-                EmptyString(),     // Title
-                inputStream,       // Post data stream
-                nullptr,           // LayoutHistory state
-                cacheKey,          // CacheKey
-                mContentTypeHint,  // Content-type
-                owner,             // Channel or provided owner
+  entry->Create(aURI,                // uri
+                EmptyString(),       // Title
+                inputStream,         // Post data stream
+                nullptr,             // LayoutHistory state
+                cacheKey,            // CacheKey
+                mContentTypeHint,    // Content-type
+                triggeringPrincipal, // Channel or provided principal
                 mHistoryID,
                 mDynamicallyCreated);
 
   entry->SetOriginalURI(originalURI);
   entry->SetLoadReplace(loadReplace);
   entry->SetReferrerURI(referrerURI);
   entry->SetReferrerPolicy(referrerPolicy);
   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
@@ -12319,64 +12318,65 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
 
   nsCOMPtr<nsIURI> uri;
   nsCOMPtr<nsIURI> originalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIInputStream> postData;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy;
   nsAutoCString contentType;
-  nsCOMPtr<nsISupports> owner;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
 
   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
 
   NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetOriginalURI(getter_AddRefs(originalURI)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetLoadReplace(&loadReplace),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
-  NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)), NS_ERROR_FAILURE);
+  NS_ENSURE_SUCCESS(aEntry->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal)),
+                    NS_ERROR_FAILURE);
 
   // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
   // that's the only thing holding a ref to aEntry that will cause aEntry to
   // die while we're loading it.  So hold a strong ref to aEntry here, just
   // in case.
   nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
   bool isJS;
   nsresult rv = uri->SchemeIs("javascript", &isJS);
   if (NS_FAILED(rv) || isJS) {
     // We're loading a URL that will execute script from inside asyncOpen.
     // Replace the current document with about:blank now to prevent
     // anything from the current document from leaking into any JavaScript
     // code in the URL.
-    nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner);
     // Don't cache the presentation if we're going to just reload the
     // current entry. Caching would lead to trying to save the different
     // content viewers in the same nsISHEntry object.
-    rv = CreateAboutBlankContentViewer(prin, nullptr, aEntry != mOSHE);
+    rv = CreateAboutBlankContentViewer(triggeringPrincipal, nullptr,
+                                       aEntry != mOSHE);
 
     if (NS_FAILED(rv)) {
       // The creation of the intermittent about:blank content
       // viewer failed for some reason (potentially because the
       // user prevented it). Interrupt the history load.
       return NS_OK;
     }
 
-    if (!owner) {
-      // Ensure that we have an owner.  Otherwise javascript: URIs will
-      // pick it up from the about:blank page we just loaded, and we
-      // don't really want even that in this case.
-      owner = nsNullPrincipal::CreateWithInheritedAttributes(this);
+    if (!triggeringPrincipal) {
+      // Ensure that we have a triggeringPrincipal.  Otherwise javascript:
+      // URIs will pick it up from the about:blank page we just loaded,
+      // and we don't really want even that in this case.
+      triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this);
     }
   }
 
   /* If there is a valid postdata *and* the user pressed
    * reload or shift-reload, take user's permission before we
    * repost the data to the server.
    */
   if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
@@ -12387,17 +12387,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
     }
 
     // If the user pressed cancel in the dialog, return.  We're done here.
     if (!repost) {
       return NS_BINDING_ABORTED;
     }
   }
 
-  // Do not inherit owner from document (security-critical!);
+  // Do not inherit principal from document (security-critical!);
   uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
 
   nsAutoString srcdoc;
   bool isSrcdoc;
   nsCOMPtr<nsIURI> baseURI;
   aEntry->GetIsSrcdocEntry(&isSrcdoc);
   if (isSrcdoc) {
     aEntry->GetSrcdocData(srcdoc);
@@ -12411,17 +12411,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
   // aSourceDocShell was introduced. According to spec we should be passing
   // the source browsing context that was used when the history entry was
   // first created. bug 947716 has been created to address this issue.
   rv = InternalLoad(uri,
                     originalURI,
                     loadReplace,
                     referrerURI,
                     referrerPolicy,
-                    owner,
+                    triggeringPrincipal,
                     flags,
                     nullptr,            // No window target
                     contentType.get(),  // Type hint
                     NullString(),       // No forced file download
                     postData,           // Post data stream
                     nullptr,            // No headers stream
                     aLoadType,          // Load type
                     aEntry,             // SHEntry
@@ -13913,17 +13913,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsresult rv = InternalLoad(clonedURI,                 // New URI
                              nullptr,                   // Original URI
                              false,                     // LoadReplace
                              referer,                   // Referer URI
                              refererPolicy,             // Referer policy
-                             aContent->NodePrincipal(), // Owner is our node's
+                             aContent->NodePrincipal(), // Triggering is our node's
                                                         // principal
                              flags,
                              target.get(),              // Window target
                              NS_LossyConvertUTF16toASCII(typeHint).get(),
                              aFileName,                 // Download as file
                              aPostDataStream,           // Post data stream
                              aHeadersDataStream,        // Headers stream
                              LOAD_LINK,                 // Load type
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -343,31 +343,31 @@ protected:
   // Get the principal that we'll set on the channel if we're inheriting. If
   // aConsiderCurrentDocument is true, we try to use the current document if
   // at all possible. If that fails, we fall back on the parent document.
   // If that fails too, we force creation of a content viewer and use the
   // resulting principal. If aConsiderCurrentDocument is false, we just look
   // at the parent.
   nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument);
 
-  // Actually open a channel and perform a URI load. Note: whatever owner is
+  // Actually open a channel and perform a URI load. Note: whatever principal is
   // passed to this function will be set on the channel. Callers who wish to
-  // not have an owner on the channel should just pass null.
+  // not have an principal on the channel should just pass null.
   // If aSrcdoc is not void, the load will be considered as a srcdoc load,
   // and the contents of aSrcdoc will be loaded instead of aURI.
   // aOriginalURI will be set as the originalURI on the channel that does the
   // load. If aOriginalURI is null, aURI will be set as the originalURI.
   // If aLoadReplace is true, OLOAD_REPLACE flag will be set to the nsIChannel.
   nsresult DoURILoad(nsIURI* aURI,
                      nsIURI* aOriginalURI,
                      bool aLoadReplace,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
-                     nsISupports* aOwner,
+                     nsIPrincipal* aTriggeringPrincipal,
                      const char* aTypeHint,
                      const nsAString& aFileName,
                      nsIInputStream* aPostData,
                      nsIInputStream* aHeadersData,
                      bool aFirstParty,
                      nsIDocShell** aDocShell,
                      nsIRequest** aRequest,
                      bool aIsNewWindowTarget,
@@ -396,21 +396,22 @@ protected:
                      bool aFireOnLocationChange,
                      bool aAddToGlobalHistory = true);
 
   // Returns true if would have called FireOnLocationChange,
   // but did not because aFireOnLocationChange was false on entry.
   // In this case it is the caller's responsibility to ensure
   // FireOnLocationChange is called.
   // In all other cases false is returned.
-  // Either aChannel or aOwner must be null. If aChannel is
+  // Either aChannel or aTriggeringPrincipal must be null. If aChannel is
   // present, the owner should be gotten from it.
   // If OnNewURI calls AddToSessionHistory, it will pass its
   // aCloneSHChildren argument as aCloneChildren.
-  bool OnNewURI(nsIURI* aURI, nsIChannel* aChannel, nsISupports* aOwner,
+  bool OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
+                nsIPrincipal* aTriggeringPrincipal,
                 uint32_t aLoadType,
                 bool aFireOnLocationChange,
                 bool aAddToGlobalHistory,
                 bool aCloneSHChildren);
 
   void SetReferrerURI(nsIURI* aURI);
   void SetReferrerPolicy(uint32_t aReferrerPolicy);
 
@@ -418,17 +419,17 @@ protected:
   bool ShouldAddToSessionHistory(nsIURI* aURI);
   // Either aChannel or aOwner must be null. If aChannel is
   // present, the owner should be gotten from it.
   // If aCloneChildren is true, then our current session history's
   // children will be cloned onto the new entry. This should be
   // used when we aren't actually changing the document while adding
   // the new session history entry.
   nsresult AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
-                               nsISupports* aOwner,
+                               nsIPrincipal* aTriggeringPrincipal,
                                bool aCloneChildren,
                                nsISHEntry** aNewEntry);
   nsresult AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
                                    bool aCloneChildren);
 
   nsresult AddChildSHEntryInternal(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
                                    int32_t aChildOffset, uint32_t aLoadType,
                                    bool aCloneChildren);
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -8,18 +8,18 @@
 #include "nsISHEntry.h"
 #include "nsIInputStream.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
   : mLoadReplace(false)
-  , mInheritOwner(false)
-  , mOwnerIsExplicit(false)
+  , mInheritPrincipal(false)
+  , mPrincipalIsExplicit(false)
   , mSendReferrer(true)
   , mReferrerPolicy(mozilla::net::RP_Default)
   , mLoadType(nsIDocShellLoadInfo::loadNormal)
   , mIsSrcdocLoad(false)
 {
 }
 
 nsDocShellLoadInfo::~nsDocShellLoadInfo()
@@ -78,59 +78,56 @@ nsDocShellLoadInfo::GetLoadReplace(bool*
 NS_IMETHODIMP
 nsDocShellLoadInfo::SetLoadReplace(bool aLoadReplace)
 {
   mLoadReplace = aLoadReplace;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::GetOwner(nsISupports** aOwner)
+nsDocShellLoadInfo::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
 {
-  NS_ENSURE_ARG_POINTER(aOwner);
-
-  *aOwner = mOwner;
-  NS_IF_ADDREF(*aOwner);
+  NS_ENSURE_ARG_POINTER(aTriggeringPrincipal);
+  NS_IF_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::SetOwner(nsISupports* aOwner)
+nsDocShellLoadInfo::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
 {
-  mOwner = aOwner;
+  mTriggeringPrincipal = aTriggeringPrincipal;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::GetInheritOwner(bool* aInheritOwner)
+nsDocShellLoadInfo::GetInheritPrincipal(bool* aInheritPrincipal)
 {
-  NS_ENSURE_ARG_POINTER(aInheritOwner);
-
-  *aInheritOwner = mInheritOwner;
+  NS_ENSURE_ARG_POINTER(aInheritPrincipal);
+  *aInheritPrincipal = mInheritPrincipal;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::SetInheritOwner(bool aInheritOwner)
+nsDocShellLoadInfo::SetInheritPrincipal(bool aInheritPrincipal)
 {
-  mInheritOwner = aInheritOwner;
+  mInheritPrincipal = aInheritPrincipal;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::GetOwnerIsExplicit(bool* aOwnerIsExplicit)
+nsDocShellLoadInfo::GetPrincipalIsExplicit(bool* aPrincipalIsExplicit)
 {
-  *aOwnerIsExplicit = mOwnerIsExplicit;
+  *aPrincipalIsExplicit = mPrincipalIsExplicit;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShellLoadInfo::SetOwnerIsExplicit(bool aOwnerIsExplicit)
+nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit)
 {
-  mOwnerIsExplicit = aOwnerIsExplicit;
+  mPrincipalIsExplicit = aPrincipalIsExplicit;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType* aLoadType)
 {
   NS_ENSURE_ARG_POINTER(aLoadType);
 
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -28,20 +28,20 @@ public:
   NS_DECL_NSIDOCSHELLLOADINFO
 
 protected:
   virtual ~nsDocShellLoadInfo();
 
 protected:
   nsCOMPtr<nsIURI> mReferrer;
   nsCOMPtr<nsIURI> mOriginalURI;
-  nsCOMPtr<nsISupports> mOwner;
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mLoadReplace;
-  bool mInheritOwner;
-  bool mOwnerIsExplicit;
+  bool mInheritPrincipal;
+  bool mPrincipalIsExplicit;
   bool mSendReferrer;
   nsDocShellInfoReferrerPolicy mReferrerPolicy;
   nsDocShellInfoLoadType mLoadType;
   nsCOMPtr<nsISHEntry> mSHEntry;
   nsString mTarget;
   nsCOMPtr<nsIInputStream> mPostDataStream;
   nsCOMPtr<nsIInputStream> mHeadersStream;
   bool mIsSrcdocLoad;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -96,17 +96,17 @@ interface nsIDocShell : nsIDocShellTreeI
    */
   [noscript]void loadStream(in nsIInputStream aStream,
                             in nsIURI aURI,
                             in ACString aContentType,
                             in ACString aContentCharset,
                             in nsIDocShellLoadInfo aLoadInfo);
 
   const long INTERNAL_LOAD_FLAGS_NONE                    = 0x0;
-  const long INTERNAL_LOAD_FLAGS_INHERIT_OWNER           = 0x1;
+  const long INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL       = 0x1;
   const long INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER      = 0x2;
   const long INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP = 0x4;
 
   // This flag marks the first load in this object
   // @see nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD
   const long INTERNAL_LOAD_FLAGS_FIRST_LOAD              = 0x8;
 
   const long INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER       = 0x10;
@@ -119,54 +119,53 @@ interface nsIDocShell : nsIDocShellTreeI
 
   // NB: 0x80 is available.
 
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
-   * @param aURI            - The URI to load.
-   * @param aOriginalURI    - The URI to set as the originalURI on the channel
-   *                          that does the load. If null, aURI will be set as
-   *                          the originalURI.
-   * @param aLoadReplace    - If set LOAD_REPLACE flag will be set on the
-   *                          channel. aOriginalURI is null, this argument is
-   *                          ignored.
-   * @param aReferrer       - Referring URI
-   * @param aReferrerPolicy - Referrer policy
-   * @param aOwner          - Owner (security principal)
-   * @param aInheritOwner   - Flag indicating whether the owner of the current
-   *                          document should be inherited if aOwner is null.
-   * @param aStopActiveDoc  - Flag indicating whether loading the current
-   *                          document should be stopped.
-   * @param aWindowTarget   - Window target for the load.
-   * @param aTypeHint       - A hint as to the content-type of the resulting
-   *                          data.  May be null or empty if no hint.
-   * @param aFileName       - Non-null when the link should be downloaded as
-                              the given filename.
-   * @param aPostDataStream - Post data stream (if POSTing)
-   * @param aHeadersStream  - Stream containing "extra" request headers...
-   * @param aLoadFlags      - Flags to modify load behaviour. Flags are defined
-   *                          in nsIWebNavigation.
-   * @param aSHEntry        - Active Session History entry (if loading from SH)
-   * @param aSrcdoc           When INTERNAL_LOAD_FLAGS_IS_SRCDOC is set, the
-   *                          contents of this parameter will be loaded instead
-   *                          of aURI.
-   * @param aSourceDocShell - The source browsing context for the navigation.
-   * @param aBaseURI        - The base URI to be used for the load.  Set in
-   *                          srcdoc loads as it cannot otherwise be inferred
-   *                          in certain situations such as view-source.
+   * @param aURI                 - The URI to load.
+   * @param aOriginalURI         - The URI to set as the originalURI on the channel
+   *                               that does the load. If null, aURI will be set as
+   *                               the originalURI.
+   * @param aLoadReplace         - If set LOAD_REPLACE flag will be set on the
+   *                               channel. aOriginalURI is null, this argument is
+   *                               ignored.
+   * @param aReferrer            - Referring URI
+   * @param aReferrerPolicy      - Referrer policy
+   * @param aTriggeringPrincipal - Principal that initiated that load
+   * @param aFlags               - Any of the load flags defined within above.
+   * @param aStopActiveDoc       - Flag indicating whether loading the current
+   *                               document should be stopped.
+   * @param aWindowTarget        - Window target for the load.
+   * @param aTypeHint            - A hint as to the content-type of the resulting
+   *                               data.  May be null or empty if no hint.
+   * @param aFileName            - Non-null when the link should be downloaded as
+                                   the given filename.
+   * @param aPostDataStream      - Post data stream (if POSTing)
+   * @param aHeadersStream       - Stream containing "extra" request headers...
+   * @param aLoadFlags           - Flags to modify load behaviour. Flags are defined
+   *                               in nsIWebNavigation.
+   * @param aSHEntry             - Active Session History entry (if loading from SH)
+   * @param aSrcdoc                When INTERNAL_LOAD_FLAGS_IS_SRCDOC is set, the
+   *                               contents of this parameter will be loaded instead
+   *                               of aURI.
+   * @param aSourceDocShell      - The source browsing context for the navigation.
+   * @param aBaseURI             - The base URI to be used for the load.  Set in
+   *                               srcdoc loads as it cannot otherwise be inferred
+   *                               in certain situations such as view-source.
    */
   [noscript]void internalLoad(in nsIURI aURI,
                               in nsIURI aOriginalURI,
                               in boolean aLoadReplace,
                               in nsIURI aReferrer,
                               in unsigned long aReferrerPolicy,
-                              in nsISupports aOwner,
+                              in nsIPrincipal aTriggeringPrincipal,
                               in uint32_t aFlags,
                               in wstring aWindowTarget,
                               in string aTypeHint,
                               in AString aFileName,
                               in nsIInputStream aPostDataStream,
                               in nsIInputStream aHeadersStream,
                               in unsigned long aLoadFlags,
                               in nsISHEntry aSHEntry,
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -10,16 +10,17 @@
  * The nsIDocShellLoadInfo interface defines an interface for specifying
  * setup information used in a nsIDocShell::loadURI call.
  */
  
 interface nsIURI;
 interface nsIInputStream;
 interface nsISHEntry;
 interface nsIDocShell;
+interface nsIPrincipal;
 
 typedef long nsDocShellInfoLoadType;
 typedef unsigned long nsDocShellInfoReferrerPolicy;
 
 [scriptable, uuid(e7570e5a-f1d6-452d-b4f8-b35fdc63aa03)]
 interface nsIDocShellLoadInfo : nsISupports
 {
     /** This is the referrer for the load. */
@@ -30,33 +31,34 @@ interface nsIDocShellLoadInfo : nsISuppo
      */
     attribute nsIURI originalURI;
 
     /**
      * loadReplace flag to be passed to nsIDocShell.internalLoad.
      */
     attribute boolean loadReplace;
 
-    /** The owner of the load, that is, the entity responsible for 
-     *  causing the load to occur. This should be a nsIPrincipal typically.
+    /** The principal of the load, that is, the entity responsible for 
+     *  causing the load to occur. In most cases the referrer and
+     *  the triggeringPrincipal's URI will be identical.
      */
-    attribute nsISupports owner;
+    attribute nsIPrincipal triggeringPrincipal;
 
-    /** If this attribute is true and no owner is specified, copy
-     *  the owner from the referring document.
+    /** If this attribute is true and no triggeringPrincipal is specified,
+     * copy the principal from the referring document.
      */
-    attribute boolean inheritOwner;
+    attribute boolean inheritPrincipal;
 
-    /** If this attribute is true only ever use the owner specify by
-     *  the owner and inheritOwner attributes.
+    /** If this attribute is true only ever use the principal specified
+     *  by the triggeringPrincipal and inheritPrincipal attributes.
      *  If there are security reasons for why this is unsafe, such
-     *  as trying to use a systemprincipal owner for a content docshell
-     *  the load fails.
+     *  as trying to use a systemprincipal as the triggeringPrincipal
+     *  for a content docshell the load fails.
      */
-    attribute boolean ownerIsExplicit;
+    attribute boolean principalIsExplicit;
 
     /* these are load type enums... */
     const long loadNormal = 0;                     // Normal Load
     const long loadNormalReplace = 1;              // Normal Load but replaces current history slot
     const long loadHistory = 2;                    // Load from history
     const long loadReloadNormal = 3;               // Reload
     const long loadReloadBypassCache = 4;
     const long loadReloadBypassProxy = 5;
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -176,18 +176,21 @@ interface nsIWebNavigation : nsISupports
   /**
    * Force relevant cookies to be sent with this load even if normally they
    * wouldn't be.
    */
   const unsigned long LOAD_FLAGS_FORCE_ALLOW_COOKIES = 0x20000;
 
   /**
    * Prevent the owner principal from being inherited for this load.
+   * Note: Within Gecko we use the term principal rather than owners
+   *       but some legacy addons might still rely on the outdated term.
    */
-  const unsigned long LOAD_FLAGS_DISALLOW_INHERIT_OWNER = 0x40000;
+  const unsigned long LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL = 0x40000;
+  const unsigned long LOAD_FLAGS_DISALLOW_INHERIT_OWNER     = 0x40000;
 
   /**
    * Overwrite the returned error code with a specific result code
    * when an error page is displayed.
    */
   const unsigned long LOAD_FLAGS_ERROR_LOAD_CHANGES_RV = 0x80000;
 
   /**
--- a/docshell/build/moz.build
+++ b/docshell/build/moz.build
@@ -15,17 +15,14 @@ SOURCES += [
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/docshell/shistory',
     '/uriloader/base',
     '/uriloader/exthandler',
     '/uriloader/prefetch',
 ]
 
-if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
-    LOCAL_INCLUDES += ['/uriloader/exthandler/mac']
-
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_DEVTOOLS'] == 'all':
     DEFINES['MOZ_DEVTOOLS_ALL'] = True
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -15,16 +15,17 @@
 interface nsILayoutHistoryState;
 interface nsIContentViewer;
 interface nsIURI;
 interface nsIInputStream;
 interface nsIDocShellTreeItem;
 interface nsISupportsArray;
 interface nsIStructuredCloneContainer;
 interface nsIBFCacheEntry;
+interface nsIPrincipal;
 
 %{C++
 #include "nsRect.h"
 class nsDocShellEditorData;
 class nsSHEntryShared;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
@@ -185,36 +186,36 @@ interface nsISHEntry : nsISupports
     void setScrollPosition(in long x, in long y);
     void getScrollPosition(out long x, out long y);
 
     /** Additional ways to create an entry */
     [noscript] void create(in nsIURI URI, in AString title,
                            in nsIInputStream inputStream,
                            in nsILayoutHistoryState layoutHistoryState,
                            in nsISupports cacheKey, in ACString contentType,
-                           in nsISupports owner,
+                           in nsIPrincipal triggeringPrincipal,
                            in unsigned long long docshellID,
                            in boolean dynamicCreation);
 
     nsISHEntry clone();
 
     /** Attribute that indicates if this entry is for a subframe navigation */
     void setIsSubFrame(in boolean aFlag);
 
     /** Return any content viewer present in or below this node in the
         nsSHEntry tree.  This will differ from contentViewer in the case
         where a child nsSHEntry has the content viewer for this tree. */
     nsIContentViewer getAnyContentViewer(out nsISHEntry ownerEntry);
 
     /**
-     * Get the owner, if any, that was associated with the channel
+     * Get the principal, if any, that was associated with the channel
      * that the document that was loaded to create this history entry
      * came from.
      */
-    attribute nsISupports owner;
+    attribute nsIPrincipal triggeringPrincipal;
 
     /**
      * Get/set data associated with this history state via a pushState() call,
      * serialized using structured clone.
      **/
     attribute nsIStructuredCloneContainer stateData;
 
     /**
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -407,29 +407,29 @@ nsSHEntry::SetContentType(const nsACStri
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::Create(nsIURI* aURI, const nsAString& aTitle,
                   nsIInputStream* aInputStream,
                   nsILayoutHistoryState* aLayoutHistoryState,
                   nsISupports* aCacheKey, const nsACString& aContentType,
-                  nsISupports* aOwner, uint64_t aDocShellID,
+                  nsIPrincipal* aTriggeringPrincipal, uint64_t aDocShellID,
                   bool aDynamicCreation)
 {
   mURI = aURI;
   mTitle = aTitle;
   mPostData = aInputStream;
 
   // Set the LoadType by default to loadHistory during creation
   mLoadType = (uint32_t)nsIDocShellLoadInfo::loadHistory;
 
   mShared->mCacheKey = aCacheKey;
   mShared->mContentType = aContentType;
-  mShared->mOwner = aOwner;
+  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
   mShared->mDocShellID = aDocShellID;
   mShared->mDynamicallyCreated = aDynamicCreation;
 
   // By default all entries are set false for subframe flag.
   // nsDocShell::CloneAndReplace() which creates entries for
   // all subframe navigations, sets the flag to true.
   mShared->mIsFrameNavigation = false;
 
@@ -499,26 +499,26 @@ nsSHEntry::SetViewerBounds(const nsIntRe
 NS_IMETHODIMP
 nsSHEntry::GetViewerBounds(nsIntRect& aBounds)
 {
   aBounds = mShared->mViewerBounds;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSHEntry::GetOwner(nsISupports** aOwner)
+nsSHEntry::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
 {
-  NS_IF_ADDREF(*aOwner = mShared->mOwner);
+  NS_IF_ADDREF(*aTriggeringPrincipal = mShared->mTriggeringPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSHEntry::SetOwner(nsISupports* aOwner)
+nsSHEntry::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
 {
-  mShared->mOwner = aOwner;
+  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry** aEntry)
 {
   NS_ENSURE_ARG_POINTER(aEntry);
   NS_IF_ADDREF(*aEntry = mShared);
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -110,17 +110,17 @@ NS_IMPL_ISUPPORTS(nsSHEntryShared, nsIBF
 
 already_AddRefed<nsSHEntryShared>
 nsSHEntryShared::Duplicate(nsSHEntryShared* aEntry)
 {
   RefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
 
   newEntry->mDocShellID = aEntry->mDocShellID;
   newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
-  newEntry->mOwner = aEntry->mOwner;
+  newEntry->mTriggeringPrincipal = aEntry->mTriggeringPrincipal;
   newEntry->mContentType.Assign(aEntry->mContentType);
   newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
   newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
   newEntry->mSticky = aEntry->mSticky;
   newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
   newEntry->mCacheKey = aEntry->mCacheKey;
   newEntry->mLastTouched = aEntry->mLastTouched;
 
--- a/docshell/shistory/nsSHEntryShared.h
+++ b/docshell/shistory/nsSHEntryShared.h
@@ -65,17 +65,17 @@ private:
   nsresult SetContentViewer(nsIContentViewer* aViewer);
 
   // See nsISHEntry.idl for an explanation of these members.
 
   // These members are copied by nsSHEntryShared::Duplicate().  If you add a
   // member here, be sure to update the Duplicate() implementation.
   uint64_t mDocShellID;
   nsCOMArray<nsIDocShellTreeItem> mChildShells;
-  nsCOMPtr<nsISupports> mOwner;
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCString mContentType;
   bool mIsFrameNavigation;
   bool mSaveLayoutState;
   bool mSticky;
   bool mDynamicallyCreated;
   nsCOMPtr<nsISupports> mCacheKey;
   uint32_t mLastTouched;
 
--- a/docshell/test/browser/browser_loadDisallowInherit.js
+++ b/docshell/test/browser/browser_loadDisallowInherit.js
@@ -28,17 +28,17 @@ function test() {
       ok(pagePrincipal, "got principal for http:// page");
 
       // Now load the URL normally
       loadURL(url, 0, function () {
         ok(browser.contentPrincipal.equals(pagePrincipal), url + " should inherit principal");
 
         // Now load the URL and disallow inheriting the principal
         let webNav = Components.interfaces.nsIWebNavigation;
-        loadURL(url, webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER, function () {
+        loadURL(url, webNav.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, function () {
           let newPrincipal = browser.contentPrincipal;
           ok(newPrincipal, "got inner principal");
           ok(!newPrincipal.equals(pagePrincipal),
              url + " should not inherit principal when loaded with DISALLOW_INHERIT_OWNER");
   
           func();
         });
       });
new file mode 100644
--- /dev/null
+++ b/dom/base/BorrowedAttrInfo.cpp
@@ -0,0 +1,28 @@
+/* -*- 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 "mozilla/dom/BorrowedAttrInfo.h"
+
+namespace mozilla {
+namespace dom {
+
+BorrowedAttrInfo::BorrowedAttrInfo(const nsAttrName* aName,
+                                   const nsAttrValue* aValue)
+  : mName(aName)
+  , mValue(aValue)
+{
+  MOZ_ASSERT_IF(mName, mValue);
+}
+
+BorrowedAttrInfo::BorrowedAttrInfo(const BorrowedAttrInfo& aOther)
+  : mName(aOther.mName)
+  , mValue(aOther.mValue)
+{
+  MOZ_ASSERT_IF(mName, mValue);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/BorrowedAttrInfo.h
@@ -0,0 +1,46 @@
+/* -*- 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 BorrowedAttrInfo_h__
+#define BorrowedAttrInfo_h__
+
+#include "mozilla/Assertions.h"
+
+class nsAttrName;
+class nsAttrValue;
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * Struct that stores info on an attribute. The name and value must either both
+ * be null or both be non-null.
+ *
+ * Note that, just as the pointers returned by GetAttrNameAt, the pointers that
+ * this struct hold are only valid until the element or its attributes are
+ * mutated (directly or via script).
+ */
+struct BorrowedAttrInfo
+{
+  BorrowedAttrInfo()
+    : mName(nullptr)
+    , mValue(nullptr)
+  {
+  }
+
+  BorrowedAttrInfo(const nsAttrName* aName, const nsAttrValue* aValue);
+
+  BorrowedAttrInfo(const BorrowedAttrInfo& aOther);
+
+  const nsAttrName* mName;
+  const nsAttrValue* mValue;
+
+  explicit operator bool() const { return mName != nullptr; }
+};
+
+} // namespace dom
+} // namespace mozilla
+#endif
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -3,16 +3,17 @@
 /* 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 mozilla_dom_DocumentFragment_h__
 #define mozilla_dom_DocumentFragment_h__
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BorrowedAttrInfo.h"
 #include "mozilla/dom/FragmentOrElement.h"
 #include "nsIDOMDocumentFragment.h"
 
 class nsIAtom;
 class nsAString;
 class nsIDocument;
 class nsIContent;
 
@@ -74,25 +75,29 @@ public:
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override
   {
     return NS_OK;
   }
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, 
+  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override
   {
     return NS_OK;
   }
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override
   {
     return nullptr;
   }
+  virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override
+  {
+    return BorrowedAttrInfo(nullptr, nullptr);
+  }
   virtual uint32_t GetAttrCount() const override
   {
     return 0;
   }
 
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1782,16 +1782,22 @@ Element::UnbindFromTree(bool aDeep, bool
     DeleteProperty(nsGkAtoms::transitionsProperty);
     DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
     DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
     DeleteProperty(nsGkAtoms::animationsProperty);
   }
 
   ClearInDocument();
 
+#ifdef MOZ_STYLO
+  // Drop any servo node data, since it will generally need to be recomputed on
+  // re-insertion anyway.
+  ServoData().reset();
+#endif
+
   // Editable descendant count only counts descendants that
   // are in the uncomposed document.
   ResetEditableDescendantCount();
 
   if (aNullParent || !mParent->IsInShadowTree()) {
     UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
     // Begin keeping track of our subtree root.
@@ -2200,17 +2206,17 @@ Element::MaybeCheckSameAttrVal(int32_t a
                                          this);
 
   // If we have no listeners and aNotify is false, we are almost certainly
   // coming from the content sink and will almost certainly have no previous
   // value.  Even if we do, setting the value is cheap when we have no
   // listeners and don't plan to notify.  The check for aNotify here is an
   // optimization, the check for *aHasListeners is a correctness issue.
   if (*aHasListeners || aNotify) {
-    nsAttrInfo info(GetAttrInfo(aNamespaceID, aName));
+    BorrowedAttrInfo info(GetAttrInfo(aNamespaceID, aName));
     if (info.mValue) {
       // Check whether the old value is the same as the new one.  Note that we
       // only need to actually _get_ the old value if we have listeners or
       // if the element is a custom element (because it may have an
       // attribute changed callback).
       if (*aHasListeners || GetCustomElementData()) {
         // Need to store the old value.
         //
@@ -2531,32 +2537,40 @@ Element::SetMappedAttribute(nsIDocument*
 EventListenerManager*
 Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
                                         bool* aDefer)
 {
   *aDefer = true;
   return GetOrCreateListenerManager();
 }
 
-Element::nsAttrInfo
+BorrowedAttrInfo
 Element::GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const
 {
   NS_ASSERTION(nullptr != aName, "must have attribute name");
   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                "must have a real namespace ID!");
 
   int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
-  if (index >= 0) {
-    return nsAttrInfo(mAttrsAndChildren.AttrNameAt(index),
-                      mAttrsAndChildren.AttrAt(index));
+  if (index < 0) {
+    return BorrowedAttrInfo(nullptr, nullptr);
   }
 
-  return nsAttrInfo(nullptr, nullptr);
+  return mAttrsAndChildren.AttrInfoAt(index);
 }
 
+BorrowedAttrInfo
+Element::GetAttrInfoAt(uint32_t aIndex) const
+{
+  if (aIndex >= mAttrsAndChildren.AttrCount()) {
+    return BorrowedAttrInfo(nullptr, nullptr);
+  }
+
+  return mAttrsAndChildren.AttrInfoAt(aIndex);
+}
 
 bool
 Element::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                  nsAString& aResult) const
 {
   DOMString str;
   bool haveAttr = GetAttr(aNameSpaceID, aName, str);
   str.ToString(aResult);
@@ -3279,17 +3293,17 @@ Element::RequestFullscreen(JSContext* aC
       }
     }
   }
 
   OwnerDoc()->AsyncRequestFullScreen(Move(request));
 }
 
 void
-Element::MozRequestPointerLock()
+Element::RequestPointerLock()
 {
   OwnerDoc()->RequestPointerLock(this);
 }
 
 void
 Element::GetGridFragments(nsTArray<RefPtr<Grid>>& aResult)
 {
   nsGridContainerFrame* frame =
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -504,16 +504,17 @@ public:
                           nsCaseTreatment aCaseSensitive) const;
   virtual int32_t FindAttrValueIn(int32_t aNameSpaceID,
                                   nsIAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override;
+  virtual BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override;
   virtual uint32_t GetAttrCount() const override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override
   {
     List(out, aIndent, EmptyCString());
   }
@@ -745,17 +746,17 @@ public:
     if (nsIPresShell::GetCapturingContent() == this) {
       nsIPresShell::SetCapturingContent(nullptr, 0);
     }
   }
 
   // aCx == nullptr is allowed only if aOptions.isNullOrUndefined()
   void RequestFullscreen(JSContext* aCx, JS::Handle<JS::Value> aOptions,
                          ErrorResult& aError);
-  void MozRequestPointerLock();
+  void RequestPointerLock();
   Attr* GetAttributeNode(const nsAString& aName);
   already_AddRefed<Attr> SetAttributeNode(Attr& aNewAttr,
                                           ErrorResult& aError);
   already_AddRefed<Attr> RemoveAttributeNode(Attr& aOldAttr,
                                              ErrorResult& aError);
   Attr* GetAttributeNodeNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
   already_AddRefed<Attr> SetAttributeNodeNS(Attr& aNewAttr,
@@ -933,30 +934,16 @@ public:
    * @param aType the kind of flush to do, typically Flush_Frames or
    *              Flush_Layout
    * @return the primary frame
    */
   nsIFrame* GetPrimaryFrame(mozFlushType aType);
   // Work around silly C++ name hiding stuff
   nsIFrame* GetPrimaryFrame() const { return nsIContent::GetPrimaryFrame(); }
 
-  /**
-   * Struct that stores info on an attribute.  The name and value must
-   * either both be null or both be non-null.
-   */
-  struct nsAttrInfo {
-    nsAttrInfo(const nsAttrName* aName, const nsAttrValue* aValue) :
-      mName(aName), mValue(aValue) {}
-    nsAttrInfo(const nsAttrInfo& aOther) :
-      mName(aOther.mName), mValue(aOther.mValue) {}
-
-    const nsAttrName* mName;
-    const nsAttrValue* mValue;
-  };
-
   const nsAttrValue* GetParsedAttr(nsIAtom* aAttr) const
   {
     return mAttrsAndChildren.GetAttr(aAttr);
   }
 
   const nsAttrValue* GetParsedAttr(nsIAtom* aAttr, int32_t aNameSpaceID) const
   {
     return mAttrsAndChildren.GetAttr(aAttr, aNameSpaceID);
@@ -981,17 +968,17 @@ public:
   /**
    * Get the attr info for the given namespace ID and attribute name.  The
    * namespace ID must not be kNameSpaceID_Unknown and the name must not be
    * null.  Note that this can only return info on attributes that actually
    * live on this element (and is only virtual to handle XUL prototypes).  That
    * is, this should only be called from methods that only care about attrs
    * that effectively live in mAttrsAndChildren.
    */
-  virtual nsAttrInfo GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const;
+  virtual BorrowedAttrInfo GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const;
 
   virtual void NodeInfoChanged()
   {
   }
 
   /**
    * Parse a string into an nsAttrValue for a CORS attribute.  This
    * never fails.  The resulting value is an enumerated value whose
@@ -1856,17 +1843,17 @@ NS_IMETHOD ReleaseCapture(void) final ov
 NS_IMETHOD MozRequestFullScreen(void) final override                          \
 {                                                                             \
   mozilla::ErrorResult rv;                                                    \
   Element::RequestFullscreen(nullptr, JS::UndefinedHandleValue, rv);          \
   return rv.StealNSResult();                                                  \
 }                                                                             \
 NS_IMETHOD MozRequestPointerLock(void) final override                         \
 {                                                                             \
-  Element::MozRequestPointerLock();                                           \
+  Element::RequestPointerLock();                                              \
   return NS_OK;                                                               \
 }                                                                             \
 using nsINode::QuerySelector;                                                 \
 NS_IMETHOD QuerySelector(const nsAString& aSelector,                          \
                          nsIDOMElement **aReturn) final override              \
 {                                                                             \
   return nsINode::QuerySelector(aSelector, aReturn);                          \
 }                                                                             \
--- a/dom/base/NodeIterator.cpp
+++ b/dom/base/NodeIterator.cpp
@@ -133,18 +133,18 @@ void NodeIterator::NodePointer::MoveBack
 }
 
 /*
  * Factories, constructors and destructors
  */
 
 NodeIterator::NodeIterator(nsINode *aRoot,
                            uint32_t aWhatToShow,
-                           const NodeFilterHolder &aFilter) :
-    nsTraversal(aRoot, aWhatToShow, aFilter),
+                           NodeFilterHolder aFilter) :
+    nsTraversal(aRoot, aWhatToShow, Move(aFilter)),
     mPointer(mRoot, true)
 {
     aRoot->AddMutationObserver(this);
 }
 
 NodeIterator::~NodeIterator()
 {
     /* destructor code */
--- a/dom/base/NodeIterator.h
+++ b/dom/base/NodeIterator.h
@@ -27,17 +27,17 @@ class NodeIterator final : public nsIDOM
                            public nsStubMutationObserver
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMNODEITERATOR
 
     NodeIterator(nsINode *aRoot,
                  uint32_t aWhatToShow,
-                 const NodeFilterHolder &aFilter);
+                 NodeFilterHolder aFilter);
 
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(NodeIterator, nsIDOMNodeIterator)
 
     // WebIDL API
     nsINode* Root() const
     {
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -352,16 +352,19 @@ AutoJSAPI::InitInternal(nsIGlobalObject*
   mIsMainThread = aIsMainThread;
   mGlobalObject = aGlobalObject;
   if (aIsMainThread) {
     // We _could_ just unconditionally emplace mAutoRequest here.  It's just not
     // needed on worker threads, and we're hoping to kill it on the main thread
     // too.
     mAutoRequest.emplace(mCx);
   }
+  if (aGlobal) {
+    JS::ExposeObjectToActiveJS(aGlobal);
+  }
   mAutoNullableCompartment.emplace(mCx, aGlobal);
 
   ScriptSettingsStack::Push(this);
 
   mOldWarningReporter.emplace(JS::GetWarningReporter(aCx));
 
   JS::SetWarningReporter(aCx, WarningOnlyErrorReporter);
 
--- a/dom/base/TreeWalker.cpp
+++ b/dom/base/TreeWalker.cpp
@@ -21,18 +21,18 @@ namespace mozilla {
 namespace dom {
 
 /*
  * Factories, constructors and destructors
  */
 
 TreeWalker::TreeWalker(nsINode *aRoot,
                        uint32_t aWhatToShow,
-                       const NodeFilterHolder &aFilter) :
-    nsTraversal(aRoot, aWhatToShow, aFilter),
+                       NodeFilterHolder aFilter) :
+    nsTraversal(aRoot, aWhatToShow, Move(aFilter)),
     mCurrentNode(aRoot)
 {
 }
 
 TreeWalker::~TreeWalker()
 {
     /* destructor code */
 }
--- a/dom/base/TreeWalker.h
+++ b/dom/base/TreeWalker.h
@@ -28,17 +28,17 @@ class TreeWalker final : public nsIDOMTr
     virtual ~TreeWalker();
 
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMTREEWALKER
 
     TreeWalker(nsINode *aRoot,
                uint32_t aWhatToShow,
-               const NodeFilterHolder &aFilter);
+               NodeFilterHolder aFilter);
 
     NS_DECL_CYCLE_COLLECTION_CLASS(TreeWalker)
 
     // WebIDL API
     nsINode* Root() const
     {
         return mRoot;
     }
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -147,16 +147,17 @@ EXPORTS.mozilla += [
 
 EXPORTS.mozilla.dom += [
     '!UseCounterList.h',
     'AnonymousContent.h',
     'Attr.h',
     'BarProps.h',
     'BlobSet.h',
     'BodyUtil.h',
+    'BorrowedAttrInfo.h',
     'ChildIterator.h',
     'ChromeNodeList.h',
     'ChromeUtils.h',
     'Comment.h',
     'CustomElementsRegistry.h',
     'DirectionalityUtils.h',
     'DocumentFragment.h',
     'DocumentType.h',
@@ -207,16 +208,17 @@ EXPORTS.mozilla.dom += [
 ]
 
 UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
     'BarProps.cpp',
     'BlobSet.cpp',
     'BodyUtil.cpp',
+    'BorrowedAttrInfo.cpp',
     'ChildIterator.cpp',
     'ChromeNodeList.cpp',
     'ChromeUtils.cpp',
     'Comment.cpp',
     'Crypto.cpp',
     'CustomElementsRegistry.cpp',
     'DirectionalityUtils.cpp',
     'DocumentFragment.cpp',
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -74,25 +74,25 @@ int32_t
 GetIndexFromCache(const nsAttrAndChildArray* aArray)
 {
   uint32_t ix = CACHE_GET_INDEX(aArray);
   return indexCache[ix].array == aArray ? indexCache[ix].index : -1;
 }
 
 
 /**
- * Due to a compiler bug in VisualAge C++ for AIX, we need to return the 
- * address of the first index into mBuffer here, instead of simply returning 
+ * Due to a compiler bug in VisualAge C++ for AIX, we need to return the
+ * address of the first index into mBuffer here, instead of simply returning
  * mBuffer itself.
  *
  * See Bug 231104 for more information.
  */
 #define ATTRS(_impl) \
   reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0]))
-  
+
 
 #define NS_IMPL_EXTRA_SIZE \
   ((sizeof(Impl) - sizeof(mImpl->mBuffer)) / sizeof(void*))
 
 nsAttrAndChildArray::nsAttrAndChildArray()
   : mImpl(nullptr)
 {
 }
@@ -109,29 +109,29 @@ nsAttrAndChildArray::~nsAttrAndChildArra
 }
 
 nsIContent*
 nsAttrAndChildArray::GetSafeChildAt(uint32_t aPos) const
 {
   if (aPos < ChildCount()) {
     return ChildAt(aPos);
   }
-  
+
   return nullptr;
 }
 
 nsIContent * const *
 nsAttrAndChildArray::GetChildArray(uint32_t* aChildCount) const
 {
   *aChildCount = ChildCount();
-  
+
   if (!*aChildCount) {
     return nullptr;
   }
-  
+
   return reinterpret_cast<nsIContent**>(mImpl->mBuffer + AttrSlotsSize());
 }
 
 nsresult
 nsAttrAndChildArray::InsertChildAt(nsIContent* aChild, uint32_t aPos)
 {
   NS_ASSERTION(aChild, "nullchild");
   NS_ASSERTION(aPos <= ChildCount(), "out-of-bounds");
@@ -179,17 +179,17 @@ nsAttrAndChildArray::InsertChildAt(nsICo
 
   void** pos = mImpl->mBuffer + offset + aPos;
   if (childCount != aPos) {
     memmove(pos + 1, pos, (childCount - aPos) * sizeof(nsIContent*));
   }
   SetChildAtPos(pos, aChild, aPos, childCount);
 
   SetChildCount(childCount + 1);
-  
+
   return NS_OK;
 }
 
 void
 nsAttrAndChildArray::RemoveChildAt(uint32_t aPos)
 {
   // Just store the return value of TakeChildAt in an nsCOMPtr to
   // trigger a release.
@@ -479,16 +479,31 @@ nsAttrAndChildArray::RemoveAttrAt(uint32
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->RemoveAttrAt(aPos - nonmapped, aValue);
 
   return MakeMappedUnique(mapped);
 }
 
+BorrowedAttrInfo
+nsAttrAndChildArray::AttrInfoAt(uint32_t aPos) const
+{
+  NS_ASSERTION(aPos < AttrCount(),
+               "out-of-bounds access in nsAttrAndChildArray");
+
+  uint32_t nonmapped = NonMappedAttrCount();
+  if (aPos < nonmapped) {
+    return BorrowedAttrInfo(&ATTRS(mImpl)[aPos].mName, &ATTRS(mImpl)[aPos].mValue);
+  }
+
+  return BorrowedAttrInfo(mImpl->mMappedAttrs->NameAt(aPos - nonmapped),
+                    mImpl->mMappedAttrs->AttrAt(aPos - nonmapped));
+}
+
 const nsAttrName*
 nsAttrAndChildArray::AttrNameAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
                "out-of-bounds access in nsAttrAndChildArray");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -9,16 +9,17 @@
  * the two is unified to minimize footprint.
  */
 
 #ifndef nsAttrAndChildArray_h___
 #define nsAttrAndChildArray_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/dom/BorrowedAttrInfo.h"
 
 #include "nscore.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
 #include "nsCaseTreatment.h"
 
 class nsINode;
 class nsIContent;
@@ -41,16 +42,17 @@ class nsMappedAttributeElement;
 #define ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK \
     ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1)
 
 
 #define ATTRSIZE (sizeof(InternalAttr) / sizeof(void*))
 
 class nsAttrAndChildArray
 {
+  typedef mozilla::dom::BorrowedAttrInfo BorrowedAttrInfo;
 public:
   nsAttrAndChildArray();
   ~nsAttrAndChildArray();
 
   uint32_t ChildCount() const
   {
     return mImpl ? (mImpl->mAttrAndChildCount >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) : 0;
   }
@@ -94,16 +96,19 @@ public:
 
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue);
 
   // Returns attribute name at given position, *not* out-of-bounds safe
   const nsAttrName* AttrNameAt(uint32_t aPos) const;
 
+  // Returns the attribute info at a given position, *not* out-of-bounds safe
+  BorrowedAttrInfo AttrInfoAt(uint32_t aPos) const;
+
   // Returns attribute name at given position or null if aPos is out-of-bounds
   const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const;
 
   const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
   int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
 
   nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
                                 nsMappedAttributeElement* aContent,
@@ -159,17 +164,17 @@ private:
   bool AttrSlotIsTaken(uint32_t aSlot) const
   {
     NS_PRECONDITION(aSlot < AttrSlotCount(), "out-of-bounds");
     return mImpl->mBuffer[aSlot * ATTRSIZE];
   }
 
   void SetChildCount(uint32_t aCount)
   {
-    mImpl->mAttrAndChildCount = 
+    mImpl->mAttrAndChildCount =
         (mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
         (aCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS);
   }
 
   void SetAttrSlotCount(uint32_t aCount)
   {
     mImpl->mAttrAndChildCount =
         (mImpl->mAttrAndChildCount & ~ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -438,17 +438,17 @@ private:
   // exist already.
   MiscContainer* EnsureEmptyMiscContainer();
   bool EnsureEmptyAtomArray();
   already_AddRefed<nsStringBuffer>
     GetStringBuffer(const nsAString& aValue) const;
   // Given an enum table and a particular entry in that table, return
   // the actual integer value we should store.
   int32_t EnumTableEntryToValue(const EnumTable* aEnumTable,
-                                const EnumTable* aTableEntry);  
+                                const EnumTable* aTableEntry);
 
   static nsTArray<const EnumTable*>* sEnumTableArray;
 
   uintptr_t mBits;
 };
 
 inline const nsAttrValue&
 nsAttrValue::operator=(const nsAttrValue& aOther)
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3622,21 +3622,21 @@ nsContentUtils::IsChildOfSameType(nsIDoc
   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(aDoc->GetDocShell());
   nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
   if (docShellAsItem) {
     docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
   }
   return sameTypeParent != nullptr;
 }
 
-bool 
+bool
 nsContentUtils::IsScriptType(const nsACString& aContentType)
 {
   // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
-  // define in nsContentDLF.h as well. 
+  // define in nsContentDLF.h as well.
   return aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
          aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
          aContentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
          aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
          aContentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
          aContentType.EqualsLiteral(APPLICATION_JSON) ||
          aContentType.EqualsLiteral(TEXT_JSON);
 }
@@ -4440,19 +4440,20 @@ nsContentUtils::CreateContextualFragment
 
     // see if we need to add xmlns declarations
     uint32_t count = content->GetAttrCount();
     bool setDefaultNamespace = false;
     if (count > 0) {
       uint32_t index;
 
       for (index = 0; index < count; index++) {
-        const nsAttrName* name = content->GetAttrNameAt(index);
+        const BorrowedAttrInfo info = content->GetAttrInfoAt(index);
+        const nsAttrName* name = info.mName;
         if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
-          content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
+          info.mValue->ToString(uriStr);
 
           // really want something like nsXMLContentSerializer::SerializeAttr
           tagName.AppendLiteral(" xmlns"); // space important
           if (name->GetPrefix()) {
             tagName.Append(char16_t(':'));
             name->LocalName()->ToString(nameStr);
             tagName.Append(nameStr);
           } else {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -641,17 +641,17 @@ public:
    * @return true if aContent has an attribute aName in namespace aNameSpaceID,
    * and the attribute value is non-empty.
    */
   static bool HasNonEmptyAttr(const nsIContent* aContent, int32_t aNameSpaceID,
                                 nsIAtom* aName);
 
   /**
    * Method that gets the primary presContext for the node.
-   * 
+   *
    * @param aContent The content node.
    * @return the presContext, or nullptr if the content is not in a document
    *         (if GetCurrentDoc returns nullptr)
    */
   static nsPresContext* GetContextForContent(const nsIContent* aContent);
 
   /**
    * Method to do security and content policy checks on the image URI
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -169,17 +169,16 @@
 #include "mozAutoDocUpdate.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsDOMNavigationTiming.h"
 
 #include "nsSMILAnimationController.h"
 #include "imgIContainer.h"
 #include "nsSVGUtils.h"
-#include "SVGElementFactory.h"
 
 #include "nsRefreshDriver.h"
 
 // FOR CSP (autogenerated by xpidl)
 #include "nsIContentSecurityPolicy.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPService.h"
 #include "mozilla/dom/nsCSPUtils.h"
@@ -187,17 +186,16 @@
 #include "nsHTMLCSSStyleSheet.h"
 #include "SVGAttrAnimationRuleProcessor.h"
 #include "mozilla/dom/DOMImplementation.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/Comment.h"
 #include "nsTextNode.h"
 #include "mozilla/dom/Link.h"
 #include "mozilla/dom/HTMLElementBinding.h"
-#include "mozilla/dom/SVGElementBinding.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/dom/Touch.h"
 #include "mozilla/dom/TouchEvent.h"
 
 #include "mozilla/Preferences.h"
 
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
@@ -6252,31 +6250,24 @@ nsDocument::RegisterElement(JSContext* a
   }
 
   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
   nsCOMPtr<nsIAtom> nameAtom;
   int32_t namespaceID = kNameSpaceID_XHTML;
   JS::Rooted<JSObject*> protoObject(aCx);
   {
     JS::Rooted<JSObject*> htmlProto(aCx);
-    JS::Rooted<JSObject*> svgProto(aCx);
     {
       JSAutoCompartment ac(aCx, global);
 
       htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
       if (!htmlProto) {
         rv.Throw(NS_ERROR_OUT_OF_MEMORY);
         return;
       }
-
-      svgProto = SVGElementBinding::GetProtoObjectHandle(aCx);
-      if (!svgProto) {
-        rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-        return;
-      }
     }
 
     if (!aOptions.mPrototype) {
       if (!JS_WrapObject(aCx, &htmlProto)) {
         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
         return;
       }
 
@@ -6318,72 +6309,54 @@ nsDocument::RegisterElement(JSContext* a
 
       if (!desc.configurable()) {
         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
         return;
       }
 
       JS::Rooted<JSObject*> protoProto(aCx, protoObject);
 
-      if (!JS_WrapObject(aCx, &htmlProto) || !JS_WrapObject(aCx, &svgProto)) {
+      if (!JS_WrapObject(aCx, &htmlProto)) {
         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
         return;
       }
 
-      // If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG
-      // Namespace.
       while (protoProto) {
         if (protoProto == htmlProto) {
           break;
         }
 
-        if (protoProto == svgProto) {
-          namespaceID = kNameSpaceID_SVG;
-          break;
-        }
-
         if (!JS_GetPrototype(aCx, protoProto, &protoProto)) {
           rv.Throw(NS_ERROR_UNEXPECTED);
           return;
         }
       }
     } // Done with the checks, leave prototype's compartment.
 
     // If name was provided and not null...
     if (!lcName.IsEmpty()) {
       // Let BASE be the element interface for NAME and NAMESPACE.
-      bool known = false;
       nameAtom = NS_Atomize(lcName);
-      if (namespaceID == kNameSpaceID_XHTML) {
-        nsIParserService* ps = nsContentUtils::GetParserService();
-        if (!ps) {
-          rv.Throw(NS_ERROR_UNEXPECTED);
-          return;
-        }
-
-        known =
-          ps->HTMLCaseSensitiveAtomTagToId(nameAtom) != eHTMLTag_userdefined;
-      } else {
-        known = SVGElementFactory::Exists(nameAtom);
-      }
+      nsIParserService* ps = nsContentUtils::GetParserService();
+      if (!ps) {
+        rv.Throw(NS_ERROR_UNEXPECTED);
+        return;
+      }
+
+      bool known =
+        ps->HTMLCaseSensitiveAtomTagToId(nameAtom) != eHTMLTag_userdefined;
 
       // If BASE does not exist or is an interface for a custom element, set ERROR
       // to InvalidName and stop.
       // If BASE exists, then it cannot be an interface for a custom element.
       if (!known) {
         rv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
         return;
       }
     } else {
-      // If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop.
-      if (namespaceID == kNameSpaceID_SVG) {
-        rv.Throw(NS_ERROR_UNEXPECTED);
-        return;
-      }
-
       nameAtom = typeAtom;
     }
   } // Leaving the document's compartment for the LifecycleCallbacks init
 
   JS::Rooted<JSObject*> wrappedProto(aCx, protoObject);
   if (!JS_WrapObject(aCx, &wrappedProto)) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
@@ -7027,39 +7000,38 @@ nsDocument::CreateNodeIterator(nsIDOMNod
   if (!aRoot) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
   NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
 
   ErrorResult rv;
-  NodeFilterHolder holder(aFilter);
-  *_retval = nsIDocument::CreateNodeIterator(*root, aWhatToShow, holder,
+  *_retval = nsIDocument::CreateNodeIterator(*root, aWhatToShow,
+                                             NodeFilterHolder(aFilter),
                                              rv).take();
   return rv.StealNSResult();
 }
 
 already_AddRefed<NodeIterator>
 nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
                                 NodeFilter* aFilter,
                                 ErrorResult& rv) const
 {
-  NodeFilterHolder holder(aFilter);
-  return CreateNodeIterator(aRoot, aWhatToShow, holder, rv);
+  return CreateNodeIterator(aRoot, aWhatToShow, NodeFilterHolder(aFilter), rv);
 }
 
 already_AddRefed<NodeIterator>
 nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
-                                const NodeFilterHolder& aFilter,
+                                NodeFilterHolder aFilter,
                                 ErrorResult& rv) const
 {
   nsINode* root = &aRoot;
   RefPtr<NodeIterator> iterator = new NodeIterator(root, aWhatToShow,
-                                                     aFilter);
+                                                   Move(aFilter));
   return iterator.forget();
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
                              uint32_t aWhatToShow,
                              nsIDOMNodeFilter *aFilter,
                              uint8_t aOptionalArgc,
@@ -7070,38 +7042,36 @@ nsDocument::CreateTreeWalker(nsIDOMNode 
   if (!aOptionalArgc) {
     aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
   }
 
   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
   NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
   ErrorResult rv;
-  NodeFilterHolder holder(aFilter);
-  *_retval = nsIDocument::CreateTreeWalker(*root, aWhatToShow, holder,
+  *_retval = nsIDocument::CreateTreeWalker(*root, aWhatToShow,
+                                           NodeFilterHolder(aFilter),
                                            rv).take();
   return rv.StealNSResult();
 }
 
 already_AddRefed<TreeWalker>
 nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
                               NodeFilter* aFilter,
                               ErrorResult& rv) const
 {
-  NodeFilterHolder holder(aFilter);
-  return CreateTreeWalker(aRoot, aWhatToShow, holder, rv);
+  return CreateTreeWalker(aRoot, aWhatToShow, NodeFilterHolder(aFilter), rv);
 }
 
 already_AddRefed<TreeWalker>
 nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
-                              const NodeFilterHolder& aFilter,
-                              ErrorResult& rv) const
+                              NodeFilterHolder aFilter, ErrorResult& rv) const
 {
   nsINode* root = &aRoot;
-  RefPtr<TreeWalker> walker = new TreeWalker(root, aWhatToShow, aFilter);
+  RefPtr<TreeWalker> walker = new TreeWalker(root, aWhatToShow, Move(aFilter));
   return walker.forget();
 }
 
 
 NS_IMETHODIMP
 nsDocument::GetDefaultView(mozIDOMWindowProxy** aDefaultView)
 {
   *aDefaultView = nullptr;
@@ -9408,17 +9378,17 @@ nsDocument::OnPageHide(bool aPersisted,
 
   // We do not stop the animations (bug 1024343)
   // when the page is refreshing while being dragged out
   nsDocShell* docShell = mDocumentContainer.get();
   if (aPersisted && !(docShell && docShell->InFrameSwap())) {
     SetImagesNeedAnimating(false);
   }
 
-  MozExitPointerLock();
+  ExitPointerLock();
 
   // Now send out a PageHide event.
   nsCOMPtr<EventTarget> target = aDispatchStartTarget;
   if (!target) {
     target = do_QueryInterface(GetWindow());
   }
 
   // Dispatch observer notification to notify observers page is hidden.
@@ -12245,32 +12215,32 @@ static void
 DispatchPointerLockChange(nsIDocument* aTarget)
 {
   if (!aTarget) {
     return;
   }
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(aTarget,
-                             NS_LITERAL_STRING("mozpointerlockchange"),
+                             NS_LITERAL_STRING("pointerlockchange"),
                              true,
                              false);
   asyncDispatcher->PostDOMEvent();
 }
 
 static void
 DispatchPointerLockError(nsIDocument* aTarget, const char* aMessage)
 {
   if (!aTarget) {
     return;
   }
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(aTarget,
-                             NS_LITERAL_STRING("mozpointerlockerror"),
+                             NS_LITERAL_STRING("pointerlockerror"),
                              true,
                              false);
   asyncDispatcher->PostDOMEvent();
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("DOM"), aTarget,
                                   nsContentUtils::eDOM_PROPERTIES,
                                   aMessage);
 }
@@ -12526,31 +12496,31 @@ void
 nsIDocument::UnlockPointer(nsIDocument* aDoc)
 {
   nsDocument::UnlockPointer(aDoc);
 }
 
 NS_IMETHODIMP
 nsDocument::MozExitPointerLock()
 {
-  nsIDocument::MozExitPointerLock();
+  nsIDocument::ExitPointerLock();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
 {
-  Element* el = nsIDocument::GetMozPointerLockElement();
+  Element* el = nsIDocument::GetPointerLockElement();
   nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
   retval.forget(aPointerLockedElement);
   return NS_OK;
 }
 
 Element*
-nsIDocument::GetMozPointerLockElement()
+nsIDocument::GetPointerLockElement()
 {
   nsCOMPtr<Element> pointerLockedElement =
     do_QueryReferent(EventStateManager::sPointerLockedElement);
   if (!pointerLockedElement) {
     return nullptr;
   }
 
   // Make sure pointer locked element is in the same document.
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -421,17 +421,17 @@ nsFrameLoader::ReallyStartLoadingInterna
 
   // If this frame is sandboxed with respect to origin we will set it up with
   // a null principal later in nsDocShell::DoURILoad.
   // We do it there to correctly sandbox content that was loaded into
   // the frame via other methods than the src attribute.
   // We'll use our principal, not that of the document loaded inside us.  This
   // is very important; needed to prevent XSS attacks on documents loaded in
   // subframes!
-  loadInfo->SetOwner(mOwnerContent->NodePrincipal());
+  loadInfo->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
 
   nsCOMPtr<nsIURI> referrer;
 
   nsAutoString srcdoc;
   bool isSrcdoc = mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
                   mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc,
                                          srcdoc);
 
@@ -476,17 +476,17 @@ nsFrameLoader::ReallyStartLoadingInterna
   loadInfo->SetReferrerPolicy(referrerPolicy);
 
   // Default flags:
   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
 
   // Flags for browser frame:
   if (OwnerIsMozBrowserFrame()) {
     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-            nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+            nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
   }
 
   // Kick off the load...
   bool tmpState = mNeedsAsyncDestroy;
   mNeedsAsyncDestroy = true;
   nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
   rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
   mNeedsAsyncDestroy = tmpState;
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -585,16 +585,22 @@ nsGenericDOMDataNode::UnbindFromTree(boo
       NS_RELEASE(mParent);
     } else {
       mParent = nullptr;
     }
     SetParentIsContent(false);
   }
   ClearInDocument();
 
+#ifdef MOZ_STYLO
+  // Drop any servo node data, since it will generally need to be recomputed on
+  // re-insertion anyway.
+  ServoData().reset();
+#endif
+
   if (aNullParent || !mParent->IsInShadowTree()) {
     UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
     // Begin keeping track of our subtree root.
     SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
   }
 
   if (document && !GetContainingShadow()) {
@@ -642,16 +648,22 @@ nsGenericDOMDataNode::UnsetAttr(int32_t 
 }
 
 const nsAttrName*
 nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
 {
   return nullptr;
 }
 
+BorrowedAttrInfo
+nsGenericDOMDataNode::GetAttrInfoAt(uint32_t aIndex) const
+{
+  return BorrowedAttrInfo(nullptr, nullptr);
+}
+
 uint32_t
 nsGenericDOMDataNode::GetAttrCount() const
 {
   return 0;
 }
 
 uint32_t
 nsGenericDOMDataNode::GetChildCount() const
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -118,16 +118,17 @@ public:
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const override;
+  virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const override;
   virtual uint32_t GetAttrCount() const override;
   virtual const nsTextFragment *GetText() override;
   virtual uint32_t TextLength() const override;
   virtual nsresult SetText(const char16_t* aBuffer, uint32_t aLength,
                            bool aNotify) override;
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
@@ -320,14 +321,14 @@ public:
   virtual bool IsPurple() override
   {
     return mRefCnt.IsPurple();
   }
   virtual void RemovePurple() override
   {
     mRefCnt.RemovePurple();
   }
-  
+
 private:
   already_AddRefed<nsIAtom> GetCurrentValueAtom();
 };
 
 #endif /* nsGenericDOMDataNode_h___ */
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -872,16 +872,18 @@ GK_ATOM(onpageshow, "onpageshow")
 GK_ATOM(onpaint, "onpaint")
 GK_ATOM(onpairingaborted, "onpairingaborted")
 GK_ATOM(onpairingconfirmationreq, "onpairingconfirmationreq")
 GK_ATOM(onpairingconsentreq, "onpairingconsentreq")
 GK_ATOM(onpaste, "onpaste")
 GK_ATOM(onpendingchange, "onpendingchange")
 GK_ATOM(onpichange, "onpichange")
 GK_ATOM(onpicture, "onpicture")
+GK_ATOM(onpointerlockchange, "onpointerlockchange")
+GK_ATOM(onpointerlockerror, "onpointerlockerror")
 GK_ATOM(onpopuphidden, "onpopuphidden")
 GK_ATOM(onpopuphiding, "onpopuphiding")
 GK_ATOM(onpopupshowing, "onpopupshowing")
 GK_ATOM(onpopupshown, "onpopupshown")
 GK_ATOM(onposter, "onposter")
 GK_ATOM(onpreviewstatechange, "onpreviewstatechange")
 GK_ATOM(onpullphonebookreq, "onpullphonebookreq")
 GK_ATOM(onpullvcardentryreq, "onpullvcardentryreq")
@@ -991,16 +993,18 @@ GK_ATOM(persist, "persist")
 GK_ATOM(phase, "phase")
 GK_ATOM(picture, "picture")
 GK_ATOM(ping, "ping")
 GK_ATOM(pinned,"pinned")
 GK_ATOM(placeholder, "placeholder")
 GK_ATOM(plaintext, "plaintext")
 GK_ATOM(playbackrate, "playbackrate")
 GK_ATOM(pointSize, "point-size")
+GK_ATOM(pointerlockchange, "pointerlockchange")
+GK_ATOM(pointerlockerror, "pointerlockerror")
 GK_ATOM(poly, "poly")
 GK_ATOM(polygon, "polygon")
 GK_ATOM(popup, "popup")
 GK_ATOM(popupalign, "popupalign")
 GK_ATOM(popupanchor, "popupanchor")
 GK_ATOM(popupgroup, "popupgroup")
 GK_ATOM(popuphidden, "popuphidden")
 GK_ATOM(popuphiding, "popuphiding")
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -2,16 +2,17 @@
 /* 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 nsIContent_h___
 #define nsIContent_h___
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BorrowedAttrInfo.h"
 #include "nsCaseTreatment.h" // for enum, cannot be forward-declared
 #include "nsINode.h"
 
 // Forward declarations
 class nsAString;
 class nsIAtom;
 class nsIURI;
 class nsRuleWalker;
@@ -30,17 +31,17 @@ struct CustomElementData;
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
 
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
-  eLinkState_NotLink    = 3 
+  eLinkState_NotLink    = 3
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID \
 { 0x8e1bab9d, 0x8815, 0x4d2c, \
   { 0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22 } }
 
 /**
@@ -97,17 +98,17 @@ public:
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) = 0;
 
   /**
    * Unbind this content node from a tree.  This will set its current document
    * and binding parent to null.  In the typical case of a node being removed
    * from a parent, this will be called after it has been removed from the
    * parent's child list and after the nsIDocumentObserver notifications for
-   * the removal have been dispatched.   
+   * the removal have been dispatched.
    * @param aDeep Whether to recursively unbind the entire subtree rooted at
    *        this node.  The only time false should be passed is when the
    *        parent node of the content is being destroyed.
    * @param aNullParent Whether to null out the parent pointer as well.  This
    *        is usually desirable.  This argument should only be false while
    *        recursively calling UnbindFromTree when a subtree is detached.
    * @note This method is safe to call on nodes that are not bound to a tree.
    */
@@ -388,44 +389,44 @@ public:
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValue The value to compare to.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
    */
   bool AttrValueIs(int32_t aNameSpaceID,
                    nsIAtom* aName,
                    const nsAString& aValue,
                    nsCaseTreatment aCaseSensitive) const;
-  
+
   /**
    * Test whether this content node's given attribute has the given value.  If
    * the attribute is not set at all, this will return false.
    *
    * @param aNameSpaceID The namespace ID of the attribute.  Must not
    *                     be kNameSpaceID_Unknown.
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValue The value to compare to.  Must not be null.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
    */
   bool AttrValueIs(int32_t aNameSpaceID,
                    nsIAtom* aName,
                    nsIAtom* aValue,
                    nsCaseTreatment aCaseSensitive) const;
-  
+
   enum {
     ATTR_MISSING = -1,
     ATTR_VALUE_NO_MATCH = -2
   };
   /**
    * Check whether this content node's given attribute has one of a given
    * list of values. If there is a match, we return the index in the list
    * of the first matching value. If there was no attribute at all, then
    * we return ATTR_MISSING. If there was an attribute but it didn't
    * match, we return ATTR_VALUE_NO_MATCH. A non-negative result always
    * indicates a match.
-   * 
+   *
    * @param aNameSpaceID The namespace ID of the attribute.  Must not
    *                     be kNameSpaceID_Unknown.
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValues a nullptr-terminated array of pointers to atom values to test
    *                against.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the values.
    * @return ATTR_MISSING, ATTR_VALUE_NO_MATCH or the non-negative index
    * indicating the first value of aValues that matched
@@ -442,34 +443,39 @@ public:
   /**
    * Remove an attribute so that it is no longer explicitly specified.
    *
    * @param aNameSpaceID the namespace id of the attribute
    * @param aAttr the name of the attribute to unset
    * @param aNotify specifies whether or not the document should be
    * notified of the attribute change
    */
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr, 
+  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
                              bool aNotify) = 0;
 
 
   /**
    * Get the namespace / name / prefix of a given attribute.
-   * 
+   *
    * @param   aIndex the index of the attribute name
    * @returns The name at the given index, or null if the index is
    *          out-of-bounds.
    * @note    The document returned by NodeInfo()->GetDocument() (if one is
    *          present) is *not* necessarily the owner document of the element.
    * @note    The pointer returned by this function is only valid until the
    *          next call of either GetAttrNameAt or SetAttr on the element.
    */
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const = 0;
 
   /**
+   * Gets the attribute info (name and value) for this content at a given index.
+   */
+  virtual mozilla::dom::BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const = 0;
+
+  /**
    * Get the number of all specified attributes.
    *
    * @return the number of attributes
    */
   virtual uint32_t GetAttrCount() const = 0;
 
   /**
    * Get direct access (but read only) to the text in the text content.
@@ -479,23 +485,23 @@ public:
   virtual const nsTextFragment *GetText() = 0;
 
   /**
    * Get the length of the text content.
    * NOTE: This should not be called on elements.
    */
   virtual uint32_t TextLength() const = 0;
 
-   /**
-    * Determines if an event attribute name (such as onclick) is valid for
-    * a given element type.
-    * @note calls nsContentUtils::IsEventAttributeName with right flag
-    * @note overridden by subclasses as needed
-    * @param aName the event name to look up
-    */
+  /**
+   * Determines if an event attribute name (such as onclick) is valid for
+   * a given element type.
+   * @note calls nsContentUtils::IsEventAttributeName with right flag
+   * @note overridden by subclasses as needed
+   * @param aName the event name to look up
+   */
   virtual bool IsEventAttributeName(nsIAtom* aName)
   {
     return false;
   }
 
   /**
    * Set the text to the given value. If aNotify is true then
    * the document is notified of the content change.
@@ -546,23 +552,23 @@ public:
    * Append the text content to aResult.
    * NOTE: This asserts and returns for elements
    */
   MOZ_MUST_USE
   virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) = 0;
 
   /**
    * Check if this content is focusable and in the current tab order.
-   * Note: most callers should use nsIFrame::IsFocusable() instead as it 
+   * Note: most callers should use nsIFrame::IsFocusable() instead as it
    *       checks visibility and other layout factors as well.
    * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
-   * For example, only the selected radio button in a group is in the 
+   * For example, only the selected radio button in a group is in the
    * tab order, unless the radio group has no selection in which case
-   * all of the visible, non-disabled radio buttons in the group are 
-   * in the tab order. On the other hand, all of the visible, non-disabled 
+   * all of the visible, non-disabled radio buttons in the group are
+   * in the tab order. On the other hand, all of the visible, non-disabled
    * radio buttons are always focusable via clicking or script.
    * Also, depending on either the accessibility.tabfocus pref or
    * a system setting (nowadays: Full keyboard access, mac only)
    * some widgets may be focusable but removed from the tab order.
    * @param  [inout, optional] aTabIndex the computed tab index
    *         In: default tabindex for element (-1 nonfocusable, == 0 focusable)
    *         Out: computed tabindex
    * @param  [optional] aTabIndex the computed tab index
@@ -773,17 +779,17 @@ public:
    * element and then call setAttribute() directly, at which point
    * DoneCreatingElement() has already been called and is out of the picture).
    */
   virtual void DoneCreatingElement()
   {
   }
 
   /**
-   * This method is called when the parser begins creating the element's 
+   * This method is called when the parser begins creating the element's
    * children, if any are present.
    *
    * This is only called for XTF elements currently.
    */
   virtual void BeginAddingChildren()
   {
   }
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2544,24 +2544,24 @@ public:
     CreateEvent(const nsAString& aEventType, mozilla::ErrorResult& rv) const;
   already_AddRefed<nsRange> CreateRange(mozilla::ErrorResult& rv);
   already_AddRefed<mozilla::dom::NodeIterator>
     CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
                        mozilla::dom::NodeFilter* aFilter,
                        mozilla::ErrorResult& rv) const;
   already_AddRefed<mozilla::dom::NodeIterator>
     CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
-                       const mozilla::dom::NodeFilterHolder& aFilter,
+                       mozilla::dom::NodeFilterHolder aFilter,
                        mozilla::ErrorResult& rv) const;
   already_AddRefed<mozilla::dom::TreeWalker>
     CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
                      mozilla::dom::NodeFilter* aFilter, mozilla::ErrorResult& rv) const;
   already_AddRefed<mozilla::dom::TreeWalker>
     CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
-                     const mozilla::dom::NodeFilterHolder& aFilter,
+                     mozilla::dom::NodeFilterHolder aFilter,
                      mozilla::ErrorResult& rv) const;
 
   // Deprecated WebIDL bits
   already_AddRefed<mozilla::dom::CDATASection>
     CreateCDATASection(const nsAString& aData, mozilla::ErrorResult& rv);
   already_AddRefed<mozilla::dom::Attr>
     CreateAttribute(const nsAString& aName, mozilla::ErrorResult& rv);
   already_AddRefed<mozilla::dom::Attr>
@@ -2599,18 +2599,18 @@ public:
   // Not const because all the full-screen goop is not const
   virtual bool FullscreenEnabled() = 0;
   virtual Element* GetFullscreenElement() = 0;
   bool Fullscreen()
   {
     return !!GetFullscreenElement();
   }
   void ExitFullscreen();
-  Element* GetMozPointerLockElement();
-  void MozExitPointerLock()
+  Element* GetPointerLockElement();
+  void ExitPointerLock()
   {
     UnlockPointer(this);
   }
   bool Hidden() const
   {
     return mVisibilityState != mozilla::dom::VisibilityState::Visible;
   }
   bool MozHidden() const
--- a/dom/base/nsIGlobalObject.h
+++ b/dom/base/nsIGlobalObject.h
@@ -48,16 +48,21 @@ public:
    * a window from going away.
    */
   bool
   IsDying() const
   {
     return mIsDying;
   }
 
+  // GetGlobalJSObject may return a gray object.  If this ever changes so that
+  // it stops doing that, please simplify the code in FindAssociatedGlobal in
+  // BindingUtils.h that does JS::ExposeObjectToActiveJS on the return value of
+  // GetGlobalJSObject.  Also, in that case the JS::ExposeObjectToActiveJS in
+  // AutoJSAPI::InitInternal can probably be removed.
   virtual JSObject* GetGlobalJSObject() = 0;
 
   // This method is not meant to be overridden.
   nsIPrincipal* PrincipalOrNull();
 
   void RegisterHostObjectURI(const nsACString& aURI);
 
   void UnregisterHostObjectURI(const nsACString& aURI);
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -144,22 +144,16 @@ nsINode::nsSlots::Unlink()
 }
 
 //----------------------------------------------------------------------
 
 nsINode::~nsINode()
 {
   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
   MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
-
-#ifdef MOZ_STYLO
-  if (mServoNodeData) {
-    Servo_DropNodeData(mServoNodeData);
-  }
-#endif
 }
 
 void*
 nsINode::GetProperty(uint16_t aCategory, nsIAtom *aPropertyName,
                      nsresult *aStatus) const
 {
   return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
                                                            aStatus);
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -3,16 +3,17 @@
 /* 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 nsINode_h___
 #define nsINode_h___
 
 #include "mozilla/Likely.h"
+#include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"               // for member, local
 #include "nsGkAtoms.h"              // for nsGkAtoms::baseURIProperty
 #include "nsIDOMNode.h"
 #include "mozilla/dom/NodeInfo.h"            // member (in nsCOMPtr)
 #include "nsIVariant.h"             // for use in GetUserData()
 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
 #include "nsPropertyTable.h"        // for typedefs
 #include "nsTObserverArray.h"       // for member
@@ -46,17 +47,32 @@ class nsIMutationObserver;
 class nsINode;
 class nsINodeList;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsNodeWeakReference;
 class nsDOMMutationObserver;
+
+// We declare the bare minimum infrastructure here to allow us to have a
+// UniquePtr<ServoNodeData> on nsINode.
 struct ServoNodeData;
+extern "C" void Servo_DropNodeData(ServoNodeData*);
+namespace mozilla {
+template<>
+class DefaultDelete<ServoNodeData>
+{
+public:
+  void operator()(ServoNodeData* aPtr) const
+  {
+    Servo_DropNodeData(aPtr);
+  }
+};
+} // namespace mozilla
 
 namespace mozilla {
 class EventListenerManager;
 namespace dom {
 /**
  * @return true if aChar is what the DOM spec defines as 'space character'.
  * http://dom.spec.whatwg.org/#space-character
  */
@@ -335,19 +351,16 @@ public:
   : mNodeInfo(aNodeInfo)
   , mParent(nullptr)
   , mBoolFlags(0)
   , mNextSibling(nullptr)
   , mPreviousSibling(nullptr)
   , mFirstChild(nullptr)
   , mSubtreeRoot(this)
   , mSlots(nullptr)
-#ifdef MOZ_STYLO
-  , mServoNodeData(nullptr)
-#endif
   {
   }
 #endif
 
   virtual ~nsINode();
 
   /**
    * Bit-flags to pass (or'ed together) to IsNodeOfType()
@@ -2054,33 +2067,24 @@ public:
   void SetOn##name_(mozilla::dom::EventHandlerNonNull* listener);
 #define TOUCH_EVENT EVENT
 #define DOCUMENT_ONLY_EVENT EVENT
 #include "mozilla/EventNameList.h"
 #undef DOCUMENT_ONLY_EVENT
 #undef TOUCH_EVENT
 #undef EVENT
 
-  ServoNodeData* GetServoNodeData() {
+  mozilla::UniquePtr<ServoNodeData>& ServoData() {
 #ifdef MOZ_STYLO
     return mServoNodeData;
 #else
     MOZ_CRASH("Accessing servo node data in non-stylo build");
 #endif
   }
 
-  void SetServoNodeData(ServoNodeData* aData) {
-#ifdef MOZ_STYLO
-    MOZ_ASSERT(!mServoNodeData);
-    mServoNodeData = aData;
-#else
-    MOZ_CRASH("Setting servo node data in non-stylo build");
-#endif
-  }
-
 protected:
   static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
   static void Unlink(nsINode *tmp);
 
   RefPtr<mozilla::dom::NodeInfo> mNodeInfo;
 
   // mParent is an owning ref most of the time, except for the case of document
   // nodes, so it cannot be represented by nsCOMPtr, so mark is as
@@ -2111,17 +2115,17 @@ protected:
     nsINode* MOZ_NON_OWNING_REF mSubtreeRoot;
   };
 
   // Storage for more members that are usually not needed; allocated lazily.
   nsSlots* mSlots;
 
 #ifdef MOZ_STYLO
   // Layout data managed by Servo.
-  ServoNodeData* mServoNodeData;
+  mozilla::UniquePtr<ServoNodeData> mServoNodeData;
 #endif
 };
 
 inline nsIDOMNode* GetAsDOMNode(nsINode* aNode)
 {
   return aNode ? aNode->AsDOMNode() : nullptr;
 }
 
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -103,17 +103,17 @@ nsLocation::GetDocShell()
 nsresult
 nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
 {
   *aLoadInfo = nullptr;
 
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
 
-  nsCOMPtr<nsISupports> owner;
+  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   nsCOMPtr<nsIURI> sourceURI;
   net::ReferrerPolicy referrerPolicy = net::RP_Default;
 
   if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
     // No cx means that there's no JS running, or at least no JS that
     // was run through code that properly pushed a context onto the
     // context stack (as all code that runs JS off of web pages
     // does). We won't bother with security checks in this case, but
@@ -148,17 +148,17 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDo
 
     if (doc) {
       nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI, principalURI;
       docOriginalURI = doc->GetOriginalURI();
       docCurrentURI = doc->GetDocumentURI();
       rv = doc->NodePrincipal()->GetURI(getter_AddRefs(principalURI));
       NS_ENSURE_SUCCESS(rv, rv);
 
-      owner = doc->NodePrincipal();
+      triggeringPrincipal = doc->NodePrincipal();
       referrerPolicy = doc->GetReferrerPolicy();
 
       bool urisEqual = false;
       if (docOriginalURI && docCurrentURI && principalURI) {
         principalURI->Equals(docOriginalURI, &urisEqual);
       }
       if (urisEqual) {
         sourceURI = docCurrentURI;
@@ -178,26 +178,26 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDo
         }
       }
     }
     else {
       // No document; determine triggeringPrincipal by quering the
       // subjectPrincipal, wich is the principal of the current JS
       // compartment, or a null principal in case there is no
       // compartment yet.
-      owner = nsContentUtils::SubjectPrincipal();
+      triggeringPrincipal = nsContentUtils::SubjectPrincipal();
     }
   }
 
   // Create load info
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
 
-  loadInfo->SetOwner(owner);
+  loadInfo->SetTriggeringPrincipal(triggeringPrincipal);
 
   if (sourceURI) {
     loadInfo->SetReferrer(sourceURI);
     loadInfo->SetReferrerPolicy(referrerPolicy);
   }
 
   loadInfo.swap(*aLoadInfo);
 
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -87,17 +87,17 @@ private:
 
   struct InternalAttr
   {
     nsAttrName mName;
     nsAttrValue mValue;
   };
 
   /**
-   * Due to a compiler bug in VisualAge C++ for AIX, we need to return the 
+   * Due to a compiler bug in VisualAge C++ for AIX, we need to return the
    * address of the first index into mAttrs here, instead of simply
    * returning mAttrs itself.
    *
    * See Bug 231104 for more information.
    */
   const InternalAttr* Attrs() const
   {
     return reinterpret_cast<const InternalAttr*>(&(mAttrs[0]));
--- a/dom/base/nsTraversal.cpp
+++ b/dom/base/nsTraversal.cpp
@@ -13,20 +13,20 @@
 
 #include "nsGkAtoms.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsTraversal::nsTraversal(nsINode *aRoot,
                          uint32_t aWhatToShow,
-                         const NodeFilterHolder &aFilter) :
+                         NodeFilterHolder aFilter) :
     mRoot(aRoot),
     mWhatToShow(aWhatToShow),
-    mFilter(aFilter),
+    mFilter(Move(aFilter)),
     mInAcceptNode(false)
 {
     NS_ASSERTION(aRoot, "invalid root in call to nsTraversal constructor");
 }
 
 nsTraversal::~nsTraversal()
 {
     /* destructor code */
--- a/dom/base/nsTraversal.h
+++ b/dom/base/nsTraversal.h
@@ -20,17 +20,17 @@
 
 class nsINode;
 
 class nsTraversal
 {
 public:
     nsTraversal(nsINode *aRoot,
                 uint32_t aWhatToShow,
-                const mozilla::dom::NodeFilterHolder &aFilter);
+                mozilla::dom::NodeFilterHolder aFilter);
     virtual ~nsTraversal();
 
 protected:
     nsCOMPtr<nsINode> mRoot;
     uint32_t mWhatToShow;
     mozilla::dom::NodeFilterHolder mFilter;
     bool mInAcceptNode;
 
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -240,17 +240,17 @@ nsXHTMLContentSerializer::SerializeAttri
 
   int32_t contentNamespaceID = aContent->GetNameSpaceID();
 
   // this method is not called by nsHTMLContentSerializer
   // so we don't have to check HTML element, just XHTML
 
   if (mIsCopying && kNameSpaceID_XHTML == contentNamespaceID) {
 
-    // Need to keep track of OL and LI elements in order to get ordinal number 
+    // Need to keep track of OL and LI elements in order to get ordinal number
     // for the LI.
     if (aTagName == nsGkAtoms::ol) {
       // We are copying and current node is an OL;
       // Store its start attribute value in olState->startVal.
       nsAutoString start;
       int32_t startAttrVal = 0;
       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::start, start);
       if (!start.IsEmpty()) {
@@ -301,17 +301,19 @@ nsXHTMLContentSerializer::SerializeAttri
   // XXX Unfortunately we need a namespace manager to get
   // attribute URIs.
   for (index = 0; index < count; index++) {
 
     if (aSkipAttr == index) {
         continue;
     }
 
-    const nsAttrName* name = aContent->GetAttrNameAt(index);
+    BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
+    const nsAttrName* name = info.mName;
+
     int32_t namespaceID = name->NamespaceID();
     nsIAtom* attrName = name->LocalName();
     nsIAtom* attrPrefix = name->GetPrefix();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attrName);
     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
@@ -326,17 +328,17 @@ nsXHTMLContentSerializer::SerializeAttri
     }
 
     bool addNSAttr = false;
     if (kNameSpaceID_XMLNS != namespaceID) {
       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     }
 
-    aContent->GetAttr(namespaceID, attrName, valueStr);
+    info.mValue->ToString(valueStr);
 
     nsDependentAtomString nameStr(attrName);
     bool isJS = false;
 
     if (kNameSpaceID_XHTML == contentNamespaceID) {
       //
       // Filter out special case of <br type="_moz"> or <br _moz*>,
       // used by the editor.  Bug 16988.  Yuck.
@@ -349,17 +351,17 @@ nsXHTMLContentSerializer::SerializeAttri
       if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li)
           && (attrName == nsGkAtoms::value)) {
         // This is handled separately in SerializeLIValueAttribute()
         continue;
       }
 
       isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
 
-      if (namespaceID == kNameSpaceID_None && 
+      if (namespaceID == kNameSpaceID_None &&
           ((attrName == nsGkAtoms::href) ||
           (attrName == nsGkAtoms::src))) {
         // Make all links absolute when converting only the selection:
         if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) {
           // Would be nice to handle OBJECT and APPLET tags,
           // but that gets more complicated since we have to
           // search the tag list for CODEBASE as well.
           // For now, just leave them relative.
@@ -555,17 +557,17 @@ nsXHTMLContentSerializer::IsShorthandAtt
   // checked
   if ((aAttrName == nsGkAtoms::checked) &&
       (aElementName == nsGkAtoms::input)) {
     return true;
   }
 
   // compact
   if ((aAttrName == nsGkAtoms::compact) &&
-      (aElementName == nsGkAtoms::dir || 
+      (aElementName == nsGkAtoms::dir ||
        aElementName == nsGkAtoms::dl ||
        aElementName == nsGkAtoms::menu ||
        aElementName == nsGkAtoms::ol ||
        aElementName == nsGkAtoms::ul)) {
     return true;
   }
 
   // declare
@@ -673,17 +675,17 @@ nsXHTMLContentSerializer::LineBreakBefor
         IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
       return res;
     }
   }
 
   return mAddSpace;
 }
 
-bool 
+bool
 nsXHTMLContentSerializer::LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName)
 {
 
   if (aNamespaceID != kNameSpaceID_XHTML) {
     return false;
   }
 
   if ((aName == nsGkAtoms::html) ||
@@ -704,17 +706,17 @@ nsXHTMLContentSerializer::LineBreakAfter
       (aName == nsGkAtoms::area) ||
       (aName == nsGkAtoms::style)) {
     return true;
   }
 
   return false;
 }
 
-bool 
+bool
 nsXHTMLContentSerializer::LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName)
 {
 
   if (aNamespaceID != kNameSpaceID_XHTML) {
     return false;
   }
 
   if ((aName == nsGkAtoms::html) ||
@@ -726,17 +728,17 @@ nsXHTMLContentSerializer::LineBreakBefor
       (aName == nsGkAtoms::select) ||
       (aName == nsGkAtoms::table) ||
       (aName == nsGkAtoms::tbody)) {
     return true;
   }
   return false;
 }
 
-bool 
+bool
 nsXHTMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName)
 {
 
   if (aNamespaceID != kNameSpaceID_XHTML) {
     return false;
   }
 
   if ((aName == nsGkAtoms::html) ||
@@ -886,17 +888,17 @@ nsXHTMLContentSerializer::SerializeLIVal
     In that case we would not like to set "value" attribute to reduce the changes.
     */
     //do nothing...
   }
   else if (offset > 0) {
     // Set value attribute.
     nsAutoString valueStr;
 
-    //As serializer needs to use this valueAttr we are creating here, 
+    //As serializer needs to use this valueAttr we are creating here,
     valueStr.AppendInt(startVal + offset);
     NS_ENSURE_TRUE(SerializeAttr(EmptyString(), NS_LITERAL_STRING("value"),
                                  valueStr, aStr, false), false);
   }
 
   return true;
 }
 
@@ -928,17 +930,17 @@ nsXHTMLContentSerializer::IsFirstChildOf
 }
 
 bool
 nsXHTMLContentSerializer::HasNoChildren(nsIContent * aContent) {
 
   for (nsIContent* child = aContent->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
-       
+
     if (!child->IsNodeOfType(nsINode::eTEXT))
       return false;
 
     if (child->TextLength())
       return false;
   }
 
   return true;
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -68,17 +68,17 @@ nsXMLContentSerializer::nsXMLContentSeri
 }
 
 nsXMLContentSerializer::~nsXMLContentSerializer()
 {
 }
 
 NS_IMPL_ISUPPORTS(nsXMLContentSerializer, nsIContentSerializer)
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
                              const char* aCharSet, bool aIsCopying,
                              bool aRewriteEncodingDeclaration)
 {
   mPrefixIndex = 0;
   mColPos = 0;
   mIndentOverflow = 0;
   mIsIndentationAddedOnCurrentLine = false;
@@ -147,17 +147,17 @@ nsXMLContentSerializer::AppendTextData(n
   NS_ASSERTION(aStartOffset >= 0, "Negative start offset for text fragment!");
   NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
 
   if (length <= 0) {
     // XXX Zero is a legal value, maybe non-zero values should be an
     // error.
     return NS_OK;
   }
-    
+
   if (frag->Is2b()) {
     const char16_t *strStart = frag->Get2b() + aStartOffset;
     if (aTranslateEntities) {
       NS_ENSURE_TRUE(AppendAndTranslateEntities(Substring(strStart, strStart + length), aStr),
                      NS_ERROR_OUT_OF_MEMORY);
     }
     else {
       NS_ENSURE_TRUE(aStr.Append(Substring(strStart, strStart + length), mozilla::fallible),
@@ -173,17 +173,17 @@ nsXMLContentSerializer::AppendTextData(n
       NS_ENSURE_TRUE(aStr.Append(NS_ConvertASCIItoUTF16(frag->Get1b()+aStartOffset, length), mozilla::fallible),
                      NS_ERROR_OUT_OF_MEMORY);
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendText(nsIContent* aText,
                                    int32_t aStartOffset,
                                    int32_t aEndOffset,
                                    nsAString& aStr)
 {
   NS_ENSURE_ARG(aText);
 
   nsAutoString data;
@@ -204,17 +204,17 @@ nsXMLContentSerializer::AppendText(nsICo
   }
   else {
     NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendCDATASection(nsIContent* aCDATASection,
                                            int32_t aStartOffset,
                                            int32_t aEndOffset,
                                            nsAString& aStr)
 {
   NS_ENSURE_ARG(aCDATASection);
   nsresult rv;
 
@@ -239,17 +239,17 @@ nsXMLContentSerializer::AppendCDATASecti
 
   NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("]]>"), aStr), NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendProcessingInstruction(nsIContent* aPI,
                                                     int32_t aStartOffset,
                                                     int32_t aEndOffset,
                                                     nsAString& aStr)
 {
   nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(aPI);
   NS_ENSURE_ARG(pi);
   nsresult rv;
@@ -288,17 +288,17 @@ nsXMLContentSerializer::AppendProcessing
   }
   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("?>"), aStr), NS_ERROR_OUT_OF_MEMORY);
 
   MaybeFlagNewlineForRootNode(aPI);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendComment(nsIContent* aComment,
                                       int32_t aStartOffset,
                                       int32_t aEndOffset,
                                       nsAString& aStr)
 {
   nsCOMPtr<nsIDOMComment> comment = do_QueryInterface(aComment);
   NS_ENSURE_ARG(comment);
   nsresult rv;
@@ -345,17 +345,17 @@ nsXMLContentSerializer::AppendComment(ns
   NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("-->"), aStr), NS_ERROR_OUT_OF_MEMORY);
 
   MaybeFlagNewlineForRootNode(aComment);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendDoctype(nsIContent* aDocType,
                                       nsAString& aStr)
 {
   nsCOMPtr<nsIDOMDocumentType> docType = do_QueryInterface(aDocType);
   NS_ENSURE_ARG(docType);
   nsresult rv;
   nsAutoString name, publicId, systemId, internalSubset;
 
@@ -406,23 +406,23 @@ nsXMLContentSerializer::AppendDoctype(ns
     else {
       quote = char16_t('\'');
     }
     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" SYSTEM "), aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(systemId, aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(quote, aStr), NS_ERROR_OUT_OF_MEMORY);
   }
-  
+
   if (!internalSubset.IsEmpty()) {
     NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING(" ["), aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(internalSubset, aStr), NS_ERROR_OUT_OF_MEMORY);
     NS_ENSURE_TRUE(AppendToString(char16_t(']'), aStr), NS_ERROR_OUT_OF_MEMORY);
   }
-    
+
   NS_ENSURE_TRUE(AppendToString(kGreaterThan, aStr), NS_ERROR_OUT_OF_MEMORY);
   MaybeFlagNewlineForRootNode(aDocType);
 
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSerializer::PushNameSpaceDecl(const nsAString& aPrefix,
@@ -511,17 +511,17 @@ nsXMLContentSerializer::ConfirmPrefix(ns
       if (!haveSeenOurPrefix && aURI.Equals(decl.mURI)) {
         // Just use our uriMatch stuff.  That will deal with an empty aPrefix
         // the right way.  We can break out of the loop now, though.
         uriMatch = true;
         closestURIMatch = aPrefix;
         break;
       }
 
-      haveSeenOurPrefix = true;      
+      haveSeenOurPrefix = true;
 
       // If they don't, and either:
       // 1) We have a prefix (so we'd be redeclaring this prefix to point to a
       //    different namespace) or
       // 2) We're looking at an existing default namespace decl on aElement (so
       //    we can't create a new default namespace decl for this URI)
       // then generate a new prefix.  Note that we do NOT generate new prefixes
       // if we happen to have aPrefix == decl->mPrefix == "" and mismatching
@@ -539,51 +539,51 @@ nsXMLContentSerializer::ConfirmPrefix(ns
         // against the full namespace stack again.  Note that just restarting
         // the while loop is ok, since we haven't changed aURI, so the
         // closestURIMatch and uriMatch state is not affected.
         index = count - 1;
         haveSeenOurPrefix = false;
         continue;
       }
     }
-    
+
     // If we've found a URI match, then record the first one
     if (!uriMatch && aURI.Equals(decl.mURI)) {
       // Need to check that decl->mPrefix is not declared anywhere closer to
       // us.  If it is, we can't use it.
       bool prefixOK = true;
       int32_t index2;
       for (index2 = count-1; index2 > index && prefixOK; --index2) {
         prefixOK = (mNameSpaceStack[index2].mPrefix != decl.mPrefix);
       }
-      
+
       if (prefixOK) {
         uriMatch = true;
         closestURIMatch.Assign(decl.mPrefix);
       }
     }
-    
+
     --index;
   }
 
   // At this point the following invariants hold:
   // 1) The prefix in closestURIMatch is mapped to aURI in our scope if
   //    uriMatch is set.
   // 2) There is nothing on the namespace stack that has aPrefix as the prefix
   //    and a _different_ URI, except for the case aPrefix.IsEmpty (and
   //    possible default namespaces on ancestors)
-  
+
   // So if uriMatch is set it's OK to use the closestURIMatch prefix.  The one
   // exception is when closestURIMatch is actually empty (default namespace
   // decl) and we must have a prefix.
   if (uriMatch && (!mustHavePrefix || !closestURIMatch.IsEmpty())) {
     aPrefix.Assign(closestURIMatch);
     return false;
   }
-  
+
   if (aPrefix.IsEmpty()) {
     // At this point, aPrefix is empty (which means we never had a prefix to
     // start with).  If we must have a prefix, just generate a new prefix and
     // then send it back through the namespace stack checks to make sure it's
     // OK.
     if (mustHavePrefix) {
       GenerateNewPrefix(aPrefix);
       return ConfirmPrefix(aPrefix, aURI, aElement, aIsAttribute);
@@ -649,17 +649,17 @@ nsXMLContentSerializer::SerializeAttr(co
   }
   else {
     // Depending on whether the attribute value contains quotes or apostrophes we
     // need to select the delimiter character and escape characters using
     // character entity references, ignoring the value of aDoEscapeEntities.
     // See http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2.2 for
     // the standard on character entity references in values.  We also have to
     // make sure to escape any '&' characters.
-    
+
     bool bIncludesSingle = false;
     bool bIncludesDouble = false;
     nsAString::const_iterator iCurr, iEnd;
     uint32_t uiSize, i;
     aValue.BeginReading(iCurr);
     aValue.EndReading(iEnd);
     for ( ; iCurr != iEnd; iCurr.advance(uiSize) ) {
       const char16_t * buf = iCurr.get();
@@ -681,17 +681,17 @@ nsXMLContentSerializer::SerializeAttr(co
     }
 
     // Delimiter and escaping is according to the following table
     //    bIncludesDouble     bIncludesSingle     Delimiter       Escape Double Quote
     //    FALSE               FALSE               "               FALSE
     //    FALSE               TRUE                "               FALSE
     //    TRUE                FALSE               '               FALSE
     //    TRUE                TRUE                "               TRUE
-    char16_t cDelimiter = 
+    char16_t cDelimiter =
         (bIncludesDouble && !bIncludesSingle) ? char16_t('\'') : char16_t('"');
     NS_ENSURE_TRUE(attrString.Append(char16_t('='), mozilla::fallible), false);
     NS_ENSURE_TRUE(attrString.Append(cDelimiter, mozilla::fallible), false);
     nsAutoString sValue(aValue);
     NS_ENSURE_TRUE(sValue.ReplaceSubstring(NS_LITERAL_STRING("&"),
                                            NS_LITERAL_STRING("&amp;"), mozilla::fallible), false);
     if (bIncludesDouble && bIncludesSingle) {
       NS_ENSURE_TRUE(sValue.ReplaceSubstring(NS_LITERAL_STRING("\""),
@@ -711,43 +711,45 @@ nsXMLContentSerializer::SerializeAttr(co
   }
   else {
     NS_ENSURE_TRUE(AppendToStringConvertLF(attrString, aStr), false);
   }
 
   return true;
 }
 
-uint32_t 
+uint32_t
 nsXMLContentSerializer::ScanNamespaceDeclarations(nsIContent* aContent,
                                                   nsIContent *aOriginalElement,
                                                   const nsAString& aTagNamespaceURI)
 {
   uint32_t index, count;
   nsAutoString uriStr, valueStr;
 
   count = aContent->GetAttrCount();
 
   // First scan for namespace declarations, pushing each on the stack
   uint32_t skipAttr = count;
   for (index = 0; index < count; index++) {
-    
-    const nsAttrName* name = aContent->GetAttrNameAt(index);
+
+    const BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
+    const nsAttrName* name = info.mName;
+
     int32_t namespaceID = name->NamespaceID();
     nsIAtom *attrName = name->LocalName();
-    
+
     if (namespaceID == kNameSpaceID_XMLNS ||
         // Also push on the stack attrs named "xmlns" in the null
         // namespace... because once we serialize those out they'll look like
         // namespace decls.  :(
         // XXXbz what if we have both "xmlns" in the null namespace and "xmlns"
         // in the xmlns namespace?
         (namespaceID == kNameSpaceID_None &&
          attrName == nsGkAtoms::xmlns)) {
-      aContent->GetAttr(namespaceID, attrName, uriStr);
+      info.mValue->ToString(uriStr);
 
       if (!name->GetPrefix()) {
         if (aTagNamespaceURI.IsEmpty() && !uriStr.IsEmpty()) {
           // If the element is in no namespace we need to add a xmlns
           // attribute to declare that. That xmlns attribute must not have a
           // prefix (see http://www.w3.org/TR/REC-xml-names/#dt-prefix), ie it
           // must declare the default namespace. We just found an xmlns
           // attribute that declares the default namespace to something
@@ -860,36 +862,36 @@ nsXMLContentSerializer::SerializeAttribu
       prefixStr.Truncate();
     }
 
     bool addNSAttr = false;
     if (kNameSpaceID_XMLNS != namespaceID) {
       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     }
-    
+
     aContent->GetAttr(namespaceID, attrName, valueStr);
 
     nsDependentAtomString nameStr(attrName);
     bool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr);
 
     NS_ENSURE_TRUE(SerializeAttr(prefixStr, nameStr, valueStr, aStr, !isJS), false);
-    
+
     if (addNSAttr) {
       NS_ASSERTION(!prefixStr.IsEmpty(),
                    "Namespaced attributes must have a prefix");
       NS_ENSURE_TRUE(SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, true), false);
       PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement);
     }
   }
 
   return true;
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendElementStart(Element* aElement,
                                            Element* aOriginalElement,
                                            nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
   nsIContent* content = aElement;
 
@@ -1021,17 +1023,17 @@ nsXMLContentSerializer::AppendEndOfEleme
     if (!AppendToString(kSpace, aStr)) {
       return false;
     }
   }
 
   return AppendToString(NS_LITERAL_STRING("/>"), aStr);
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsXMLContentSerializer::AppendElementEnd(Element* aElement,
                                          nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
   nsIContent* content = aElement;
 
   bool forceFormat = false, outputElementEnd;
@@ -1045,17 +1047,17 @@ nsXMLContentSerializer::AppendElementEnd
 
   if (!outputElementEnd) {
     PopNameSpaceDeclsFor(aElement);
     MaybeFlagNewlineForRootNode(aElement);
     return NS_OK;
   }
 
   nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
-  
+
   aElement->NodeInfo()->GetPrefix(tagPrefix);
   aElement->NodeInfo()->GetName(tagLocalName);
   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
 
 #ifdef DEBUG
   bool debugNeedToPushNamespace =
 #endif
   ConfirmPrefix(tagPrefix, tagNamespaceURI, aElement, false);
@@ -1116,17 +1118,17 @@ nsXMLContentSerializer::AppendDocumentSt
   aDocument->GetXMLDeclaration(version, encoding, standalone);
 
   if (version.IsEmpty())
     return NS_OK; // A declaration must have version, or there is no decl
 
   NS_NAMED_LITERAL_STRING(endQuote, "\"");
 
   aStr += NS_LITERAL_STRING("<?xml version=\"") + version + endQuote;
-  
+
   if (!mCharset.IsEmpty()) {
     aStr += NS_LITERAL_STRING(" encoding=\"") +
       NS_ConvertASCIItoUTF16(mCharset) + endQuote;
   }
   // Otherwise just don't output an encoding attr.  Not that we expect
   // mCharset to ever be empty.
 #ifdef DEBUG
   else {
@@ -1362,29 +1364,29 @@ nsXMLContentSerializer::DecrIndentation(
 }
 
 bool
 nsXMLContentSerializer::LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName)
 {
   return mAddSpace;
 }
 
-bool 
+bool
 nsXMLContentSerializer::LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName)
 {
   return false;
 }
 
-bool 
+bool
 nsXMLContentSerializer::LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName)
 {
   return mAddSpace;
 }
 
-bool 
+bool
 nsXMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName)
 {
   return false;
 }
 
 bool
 nsXMLContentSerializer::AppendToStringConvertLF(const nsAString& aStr,
                                                 nsAString& aOutputStr)
@@ -1576,21 +1578,21 @@ nsXMLContentSerializer::AppendWrapped_No
       // We have not yet reached the max column, we will continue to
       // fill the current line in the next outer loop iteration
       // (this one in AppendToStringWrapped)
       // make sure we return in this outer loop
       onceAgainBecauseWeAddedBreakInFront = false;
     }
     else { // we reach the max column
       if (!thisSequenceStartsAtBeginningOfLine &&
-          (mAddSpace || (!mDoFormat && aSequenceStartAfterAWhiteSpace))) { 
+          (mAddSpace || (!mDoFormat && aSequenceStartAfterAWhiteSpace))) {
           // when !mDoFormat, mAddSpace is not used, mAddSpace is always false
           // so, in the case where mDoWrap && !mDoFormat, if we want to enter in this condition...
 
-        // We can avoid to wrap. We try to add the whole block 
+        // We can avoid to wrap. We try to add the whole block
         // in an empty new line
 
         NS_ENSURE_TRUE(AppendNewLineToString(aOutputStr), false);
         aPos = aSequenceStart;
         thisSequenceStartsAtBeginningOfLine = true;
         onceAgainBecauseWeAddedBreakInFront = true;
       }
       else {
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1009,17 +1009,17 @@ NativeInterface2JSObjectAndThrowIfFailed
         aRetval.setObject(*obj);
         return true;
       }
   }
 
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!XPCConvert::NativeInterface2JSObject(aRetval, nullptr, aHelper, aIID,
-                                            nullptr, aAllowNativeWrapper, &rv)) {
+                                            aAllowNativeWrapper, &rv)) {
     // I can't tell if NativeInterface2JSObject throws JS exceptions
     // or not.  This is a sloppy stab at the right semantics; the
     // method really ought to be fixed to behave consistently.
     if (!JS_IsExceptionPending(aCx)) {
       Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
     }
     return false;
   }
@@ -2020,18 +2020,19 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   JS::Rooted<JSObject*> aObj(aCx, aObjArg);
   const DOMJSClass* domClass = GetDOMClass(aObj);
 
   // DOM things are always parented to globals.
   JS::Rooted<JSObject*> oldParent(aCx,
                                   js::GetGlobalForObjectCrossCompartment(aObj));
   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(oldParent) == oldParent);
 
-  JS::Rooted<JSObject*> newParent(aCx, domClass->mGetParent(aCx, aObj));
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(newParent) == newParent);
+  JS::Rooted<JSObject*> newParent(aCx,
+                                  domClass->mGetAssociatedGlobal(aCx, aObj));
+  MOZ_ASSERT(JS_IsGlobalObject(newParent));
 
   JSAutoCompartment oldAc(aCx, oldParent);
 
   JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent);
   JSCompartment* newCompartment = js::GetObjectCompartment(newParent);
   if (oldCompartment == newCompartment) {
     MOZ_ASSERT(oldParent == newParent);
     return NS_OK;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1519,159 +1519,184 @@ WrapObject(JSContext* cx, JSObject& p, J
 }
 
 // Given an object "p" that inherits from nsISupports, wrap it and return the
 // result.  Null is returned on wrapping failure.  This is somewhat similar to
 // WrapObject() above, but does NOT allow Xrays around the result, since we
 // don't want those for our parent object.
 template<typename T>
 static inline JSObject*
-WrapNativeISupportsParent(JSContext* cx, T* p, nsWrapperCache* cache)
+WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
 {
   qsObjectHelper helper(ToSupports(p), cache);
   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
   JS::Rooted<JS::Value> v(cx);
   return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
          v.toObjectOrNull() :
          nullptr;
 }
 
 
 // Fallback for when our parent is not a WebIDL binding object.
 template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct WrapNativeParentFallback
+struct WrapNativeFallback
 {
   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
   {
     return nullptr;
   }
 };
 
 // Fallback for when our parent is not a WebIDL binding object but _is_ an
 // nsISupports object.
 template<typename T >
-struct WrapNativeParentFallback<T, true >
+struct WrapNativeFallback<T, true >
 {
   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
   {
-    return WrapNativeISupportsParent(cx, parent, cache);
+    return WrapNativeISupports(cx, parent, cache);
   }
 };
 
 // Wrapping of our native parent, for cases when it's a WebIDL object (though
 // possibly preffed off).
 template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
-struct WrapNativeParentHelper
+struct WrapNativeHelper
 {
   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
   {
     MOZ_ASSERT(cache);
 
     JSObject* obj;
     if ((obj = cache->GetWrapper())) {
+      // GetWrapper always unmarks gray.
+      MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
       return obj;
     }
 
     // Inline this here while we have non-dom objects in wrapper caches.
     if (!CouldBeDOMBinding(parent)) {
-      obj = WrapNativeParentFallback<T>::Wrap(cx, parent, cache);
+      // WrapNativeFallback never returns a gray thing.
+      obj = WrapNativeFallback<T>::Wrap(cx, parent, cache);
+      MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
     } else {
+      // WrapObject never returns a gray thing.
       obj = parent->WrapObject(cx, nullptr);
+      MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
     }
 
     return obj;
   }
 };
 
 // Wrapping of our native parent, for cases when it's not a WebIDL object.  In
 // this case it must be nsISupports.
 template<typename T>
-struct WrapNativeParentHelper<T, false>
+struct WrapNativeHelper<T, false>
 {
   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
   {
     JSObject* obj;
     if (cache && (obj = cache->GetWrapper())) {
 #ifdef DEBUG
       JS::Rooted<JSObject*> rootedObj(cx, obj);
-      NS_ASSERTION(WrapNativeISupportsParent(cx, parent, cache) == rootedObj,
+      NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
                    "Unexpected object in nsWrapperCache");
       obj = rootedObj;
 #endif
+      MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
       return obj;
     }
 
-    return WrapNativeISupportsParent(cx, parent, cache);
+    obj = WrapNativeISupports(cx, parent, cache);
+    MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
+    return obj;
   }
 };
 
-// Wrapping of our native parent.
+// Finding the associated global for an object.
 template<typename T>
 static inline JSObject*
-WrapNativeParent(JSContext* cx, T* p, nsWrapperCache* cache,
-                 bool useXBLScope = false)
+FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
+                     bool useXBLScope = false)
 {
   if (!p) {
     return JS::CurrentGlobalOrNull(cx);
   }
 
-  JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
-  if (!parent || !useXBLScope) {
-    return parent;
+  JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
+  if (!obj) {
+    return nullptr;
+  }
+  MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
+
+  obj = js::GetGlobalForObjectCrossCompartment(obj);
+
+  if (!useXBLScope) {
+    return obj;
   }
 
   // If useXBLScope is true, it means that the canonical reflector for this
   // native object should live in the content XBL scope. Note that we never put
   // anonymous content inside an add-on scope.
-  if (xpc::IsInContentXBLScope(parent)) {
-    return parent;
+  if (xpc::IsInContentXBLScope(obj)) {
+    return obj;
   }
-  JS::Rooted<JSObject*> rootedParent(cx, parent);
-  JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScope(cx, rootedParent));
-  NS_ENSURE_TRUE(xblScope, nullptr);
-  JSAutoCompartment ac(cx, xblScope);
-  if (NS_WARN_IF(!JS_WrapObject(cx, &rootedParent))) {
-    return nullptr;
-  }
-
-  return rootedParent;
+  JS::Rooted<JSObject*> rootedObj(cx, obj);
+  JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
+  MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
+  MOZ_ASSERT_IF(xblScope, !JS::ObjectIsMarkedGray(xblScope));
+  return xblScope;
 }
 
-// Wrapping of our native parent, when we don't want to explicitly pass in
-// things like the nsWrapperCache for it.
+// Finding of the associated global for an object, when we don't want to
+// explicitly pass in things like the nsWrapperCache for it.
 template<typename T>
 static inline JSObject*
-WrapNativeParent(JSContext* cx, const T& p)
+FindAssociatedGlobal(JSContext* cx, const T& p)
 {
-  return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
+  return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
 }
 
 // Specialization for the case of nsIGlobalObject, since in that case
 // we can just get the JSObject* directly.
 template<>
 inline JSObject*
-WrapNativeParent(JSContext* cx, nsIGlobalObject* const& p)
+FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
 {
-  return p ? p->GetGlobalJSObject() : JS::CurrentGlobalOrNull(cx);
+  if (!p) {
+    return JS::CurrentGlobalOrNull(cx);
+  }
+
+  JSObject* global = p->GetGlobalJSObject();
+  if (!global) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(JS_IsGlobalObject(global));
+  // This object could be gray if the nsIGlobalObject is the only thing keeping
+  // it alive.
+  JS::ExposeObjectToActiveJS(global);
+  return global;
 }
 
-template<typename T, bool WrapperCached=NativeHasMember<T>::GetParentObject>
-struct GetParentObject
+template<typename T,
+         bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
+struct FindAssociatedGlobalForNative
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
     T* native = UnwrapDOMObject<T>(obj);
-    JSObject* wrappedParent = WrapNativeParent(cx, native->GetParentObject());
-    return wrappedParent ? js::GetGlobalForObjectCrossCompartment(wrappedParent) : nullptr;
+    return FindAssociatedGlobal(cx, native->GetParentObject());
   }
 };
 
 template<typename T>
-struct GetParentObject<T, false>
+struct FindAssociatedGlobalForNative<T, false>
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
     MOZ_CRASH();
     return nullptr;
   }
 };
 
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -368,22 +368,28 @@ public:
   }
 
   explicit CallbackObjectHolder(XPCOMCallbackT* aCallback)
     : mPtrBits(reinterpret_cast<uintptr_t>(aCallback) | XPCOMCallbackFlag)
   {
     NS_IF_ADDREF(aCallback);
   }
 
-  explicit CallbackObjectHolder(const CallbackObjectHolder& aOther)
+  CallbackObjectHolder(CallbackObjectHolder&& aOther)
     : mPtrBits(aOther.mPtrBits)
   {
-    NS_IF_ADDREF(GetISupports());
+    aOther.mPtrBits = 0;
+    static_assert(sizeof(CallbackObjectHolder) == sizeof(void*),
+                  "This object is expected to be as small as a pointer, and it "
+                  "is currently passed by value in various places. If it is "
+                  "bloating, we may want to pass it by reference then.");
   }
 
+  CallbackObjectHolder(const CallbackObjectHolder& aOther) = delete;
+
   CallbackObjectHolder()
     : mPtrBits(0)
   {}
 
   ~CallbackObjectHolder()
   {
     UnlinkSelf();
   }
@@ -397,34 +403,44 @@ public:
 
   void operator=(XPCOMCallbackT* aCallback)
   {
     UnlinkSelf();
     mPtrBits = reinterpret_cast<uintptr_t>(aCallback) | XPCOMCallbackFlag;
     NS_IF_ADDREF(aCallback);
   }
 
-  void operator=(const CallbackObjectHolder& aOther)
+  void operator=(CallbackObjectHolder&& aOther)
   {
     UnlinkSelf();
     mPtrBits = aOther.mPtrBits;
-    NS_IF_ADDREF(GetISupports());
+    aOther.mPtrBits = 0;
   }
 
+  void operator=(const CallbackObjectHolder& aOther) = delete;
+
   nsISupports* GetISupports() const
   {
     return reinterpret_cast<nsISupports*>(mPtrBits & ~XPCOMCallbackFlag);
   }
 
   // Boolean conversion operator so people can use this in boolean tests
   explicit operator bool() const
   {
     return GetISupports();
   }
 
+  CallbackObjectHolder Clone() const
+  {
+    CallbackObjectHolder result;
+    result.mPtrBits = mPtrBits;
+    NS_IF_ADDREF(GetISupports());
+    return result;
+  }
+
   // Even if HasWebIDLCallback returns true, GetWebIDLCallback() might still
   // return null.
   bool HasWebIDLCallback() const
   {
     return !(mPtrBits & XPCOMCallbackFlag);
   }
 
   WebIDLCallbackT* GetWebIDLCallback() const
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -385,17 +385,17 @@ def DOMClass(descriptor):
     # padding.
     protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
 
     return fill(
         """
           { ${protoChain} },
           IsBaseOf<nsISupports, ${nativeType} >::value,
           ${hooks},
-          GetParentObject<${nativeType}>::Get,
+          FindAssociatedGlobalForNative<${nativeType}>::Get,
           GetProtoObjectHandle,
           GetCCParticipant<${nativeType}>::Get()
         """,
         protoChain=', '.join(protoList),
         nativeType=descriptor.nativeType,
         hooks=NativePropertyHooks(descriptor))
 
 
@@ -3577,33 +3577,34 @@ class CGWrapWithCacheMethod(CGAbstractMe
             $*{assertInheritance}
             MOZ_ASSERT(!aCache->GetWrapper(),
                        "You should probably not be using Wrap() directly; use "
                        "GetOrCreateDOMReflector instead");
 
             MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
                        "nsISupports must be on our primary inheritance chain");
 
-            JS::Rooted<JSObject*> parent(aCx, WrapNativeParent(aCx, aObject->GetParentObject()));
-            if (!parent) {
+            JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
+            if (!global) {
               return false;
             }
+            MOZ_ASSERT(JS_IsGlobalObject(global));
+            MOZ_ASSERT(!JS::ObjectIsMarkedGray(global));
 
             // That might have ended up wrapping us already, due to the wonders
             // of XBL.  Check for that, and bail out as needed.
             aReflector.set(aCache->GetWrapper());
             if (aReflector) {
             #ifdef DEBUG
               binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
             #endif // DEBUG
               return true;
             }
 
-            JSAutoCompartment ac(aCx, parent);
-            JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
+            JSAutoCompartment ac(aCx, global);
             $*{declareProto}
 
             $*{createObject}
 
             aCache->SetWrapper(aReflector);
             $*{unforgeable}
             $*{slots}
             creator.InitializationSucceeded();
@@ -8560,17 +8561,17 @@ class CGSpecializedGetter(CGAbstractStat
             Argument('JSContext*', 'cx'),
             Argument('JS::Handle<JSObject*>', 'obj'),
             Argument('%s*' % descriptor.nativeType, 'self'),
             Argument('JSJitGetterCallArgs', 'args')
         ]
         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
 
     def definition_body(self):
-        if self.attr.maplikeOrSetlike:
+        if self.attr.isMaplikeOrSetlikeAttr():
             # If the interface is maplike/setlike, there will be one getter
             # method for the size property of the backing object. Due to having
             # to unpack the backing object from the slot, this requires its own
             # generator.
             return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
         nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
                                                         self.attr)
         if self.attr.slotIndices is not None:
@@ -13083,16 +13084,26 @@ class ForwardDeclarationBuilder:
         Each tree node has a set of declarations |decls| and a dict |children|.
         Each declaration is a pair consisting of the class name and a boolean
         that is true iff the class is really a struct. |children| maps the
         names of inner namespaces to the declarations in that namespace.
         """
         self.decls = set()
         self.children = {}
 
+    def _ensureNonTemplateType(self, type):
+        if "<" in type:
+            # This is a templated type.  We don't really know how to
+            # forward-declare those, and trying to do it naively is not going to
+            # go well (e.g. we may have :: characters inside the type we're
+            # templated on!).  Just bail out.
+            raise TypeError("Attempt to use ForwardDeclarationBuilder on "
+                            "templated type %s.  We don't know how to do that "
+                            "yet." % type)
+
     def _listAdd(self, namespaces, name, isStruct=False):
         """
         Add a forward declaration, where |namespaces| is a list of namespaces.
         |name| should not contain any other namespaces.
         """
         if namespaces:
             child = self.children.setdefault(namespaces[0], ForwardDeclarationBuilder())
             child._listAdd(namespaces[1:], name, isStruct)
@@ -13100,23 +13111,25 @@ class ForwardDeclarationBuilder:
             assert '::' not in name
             self.decls.add((name, isStruct))
 
     def addInMozillaDom(self, name, isStruct=False):
         """
         Add a forward declaration to the mozilla::dom:: namespace. |name| should not
         contain any other namespaces.
         """
+        self._ensureNonTemplateType(name);
         self._listAdd(["mozilla", "dom"], name, isStruct)
 
     def add(self, nativeType, isStruct=False):
         """
         Add a forward declaration, where |nativeType| is a string containing
         the type and its namespaces, in the usual C++ way.
         """
+        self._ensureNonTemplateType(nativeType);
         components = nativeType.split('::')
         self._listAdd(components[:-1], components[-1], isStruct)
 
     def _build(self, atTopLevel):
         """
         Return a codegenerator for the forward declarations.
         """
         decls = []
@@ -13918,29 +13931,49 @@ class CGExampleMethod(CGNativeMember):
         CGNativeMember.__init__(self, descriptor, method,
                                 CGSpecializedMethod.makeNativeName(descriptor,
                                                                    method),
                                 signature,
                                 descriptor.getExtendedAttributes(method),
                                 breakAfter=breakAfter,
                                 variadicIsSequence=True)
 
+    def declare(self, cgClass):
+        assert self.member.isMethod()
+        # We skip declaring ourselves if this is a maplike/setlike/iterable
+        # method, because those get implemented automatically by the binding
+        # machinery, so the implementor of the interface doesn't have to worry
+        # about it.
+        if self.member.isMaplikeOrSetlikeOrIterableMethod():
+            return ''
+        return CGNativeMember.declare(self, cgClass);
+
     def define(self, cgClass):
         return ''
 
 
 class CGExampleGetter(CGNativeMember):
     def __init__(self, descriptor, attr):
         CGNativeMember.__init__(self, descriptor, attr,
                                 CGSpecializedGetter.makeNativeName(descriptor,
                                                                    attr),
                                 (attr.type, []),
                                 descriptor.getExtendedAttributes(attr,
                                                                  getter=True))
 
+    def declare(self, cgClass):
+        assert self.member.isAttr()
+        # We skip declaring ourselves if this is a maplike/setlike attr (in
+        # practice, "size"), because those get implemented automatically by the
+        # binding machinery, so the implementor of the interface doesn't have to
+        # worry about it.
+        if self.member.isMaplikeOrSetlikeAttr():
+            return ''
+        return CGNativeMember.declare(self, cgClass);
+
     def define(self, cgClass):
         return ''
 
 
 class CGExampleSetter(CGNativeMember):
     def __init__(self, descriptor, attr):
         CGNativeMember.__init__(self, descriptor, attr,
                                 CGSpecializedSetter.makeNativeName(descriptor,
@@ -14240,24 +14273,25 @@ class CGExampleRoot(CGThing):
         self.root = CGNamespace.build(["mozilla", "dom"], self.root)
 
         builder = ForwardDeclarationBuilder()
         for member in descriptor.interface.members:
             if not member.isAttr() and not member.isMethod():
                 continue
             if member.isStatic():
                 builder.addInMozillaDom("GlobalObject")
-            if member.isAttr():
+            if member.isAttr() and not member.isMaplikeOrSetlikeAttr():
                 builder.forwardDeclareForType(member.type, config)
             else:
                 assert member.isMethod()
-                for sig in member.signatures():
-                    builder.forwardDeclareForType(sig[0], config)
-                    for arg in sig[1]:
-                        builder.forwardDeclareForType(arg.type, config)
+                if not member.isMaplikeOrSetlikeOrIterableMethod():
+                    for sig in member.signatures():
+                        builder.forwardDeclareForType(sig[0], config)
+                        for arg in sig[1]:
+                            builder.forwardDeclareForType(arg.type, config)
 
         self.root = CGList([builder.build(),
                             self.root], "\n")
 
         # Throw in our #includes
         self.root = CGHeaders([], [], [], [],
                               ["nsWrapperCache.h",
                                "nsCycleCollectionParticipant.h",
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -706,16 +706,23 @@ def getTypesFromDescriptor(descriptor):
     types = []
     for s in signatures:
         assert len(s) == 2
         (returnType, arguments) = s
         types.append(returnType)
         types.extend(a.type for a in arguments)
 
     types.extend(a.type for a in members if a.isAttr())
+
+    if descriptor.interface.maplikeOrSetlikeOrIterable:
+        maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
+        if maplikeOrSetlikeOrIterable.hasKeyType():
+            types.append(maplikeOrSetlikeOrIterable.keyType)
+        if maplikeOrSetlikeOrIterable.hasValueType():
+            types.append(maplikeOrSetlikeOrIterable.valueType)
     return types
 
 
 def getFlatTypes(types):
     retval = set()
     for type in types:
         type = type.unroll()
         if type.isUnion():
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -313,17 +313,18 @@ IsInstance(DOMObjectType type)
 
 inline
 bool
 IsInterfacePrototype(DOMObjectType type)
 {
   return type == eInterfacePrototype || type == eGlobalInterfacePrototype;
 }
 
-typedef JSObject* (*ParentGetter)(JSContext* aCx, JS::Handle<JSObject*> aObj);
+typedef JSObject* (*AssociatedGlobalGetter)(JSContext* aCx,
+                                            JS::Handle<JSObject*> aObj);
 
 typedef JSObject* (*ProtoGetter)(JSContext* aCx);
 
 /**
  * Returns a handle to the relevant WebIDL prototype object for the current
  * compartment global (which may be a handle to null on out of memory).  Once
  * allocated, the prototype object is guaranteed to exist as long as the global
  * does, since the global traces its array of WebIDL prototypes and
@@ -346,17 +347,20 @@ struct DOMJSClass
   // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
   // the proxy private if we use a proxy object.
   // Sometimes it's an nsISupports and sometimes it's not; this class tells
   // us which it is.
   const bool mDOMObjectIsISupports;
 
   const NativePropertyHooks* mNativeHooks;
 
-  ParentGetter mGetParent;
+  // A callback to find the associated global for our C++ object.  Note that
+  // this is used in cases when that global is _changing_, so it will not match
+  // the global of the JSObject* passed in to this function!
+  AssociatedGlobalGetter mGetAssociatedGlobal;
   ProtoHandleGetter mGetProto;
 
   // This stores the CC participant for the native, null if this class does not
   // implement cycle collection or if it inherits from nsISupports (we can get
   // the CC participant by QI'ing in that case).
   nsCycleCollectionParticipant* mParticipant;
 
   static const DOMJSClass* FromJSClass(const JSClass* base) {
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -104,25 +104,27 @@ SOURCES += [
 # must be included in libxul. This breaks the "no test classes are exported"
 # rule stated in the test/ directory, but it's the only way this will work.
 # Test classes are only built in debug mode, and all tests requiring use of
 # them are only run in debug mode.
 if CONFIG['MOZ_DEBUG']:
     EXPORTS.mozilla.dom += [
         "test/TestFunctions.h",
         "test/TestInterfaceIterableDouble.h",
+        "test/TestInterfaceIterableDoubleUnion.h",
         "test/TestInterfaceIterableSingle.h",
         "test/TestInterfaceMaplike.h",
         "test/TestInterfaceMaplikeObject.h",
         "test/TestInterfaceSetlike.h",
         "test/TestInterfaceSetlikeNode.h"
         ]
     UNIFIED_SOURCES += [
         "test/TestFunctions.cpp",
         "test/TestInterfaceIterableDouble.cpp",
+        "test/TestInterfaceIterableDoubleUnion.cpp",
         "test/TestInterfaceIterableSingle.cpp",
         "test/TestInterfaceMaplike.cpp",
         "test/TestInterfaceMaplikeObject.cpp",
         "test/TestInterfaceSetlike.cpp",
         "test/TestInterfaceSetlikeNode.cpp",
         ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -302,17 +302,21 @@ class WebIDLCodegenManager(LoggingMixin)
         return result
 
     def generate_example_files(self, interface):
         """Generates example files for a given interface."""
         from Codegen import CGExampleRoot
 
         root = CGExampleRoot(self.config, interface)
 
-        return self._maybe_write_codegen(root, *self._example_paths(interface))
+        example_paths = self._example_paths(interface)
+        for path in example_paths:
+            print "Generating %s" % path
+
+        return self._maybe_write_codegen(root, *example_paths)
 
     def _parse_webidl(self):
         import WebIDL
         from Configuration import Configuration
 
         self.log(logging.INFO, 'webidl_parse',
                  {'count': len(self._input_paths)},
                  'Parsing {count} WebIDL files.')
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/TestInterfaceIterableDoubleUnion.cpp
@@ -0,0 +1,83 @@
+/* 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 "mozilla/dom/TestInterfaceIterableDoubleUnion.h"
+#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeIterableBinding.h"
+#include "nsPIDOMWindow.h"
+#include "mozilla/dom/BindingUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestInterfaceIterableDoubleUnion, mParent)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TestInterfaceIterableDoubleUnion)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TestInterfaceIterableDoubleUnion)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestInterfaceIterableDoubleUnion)
+NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+TestInterfaceIterableDoubleUnion::TestInterfaceIterableDoubleUnion(nsPIDOMWindowInner* aParent)
+  : mParent(aParent)
+{
+  OwningStringOrLong a;
+  a.SetAsLong() = 1;
+  mValues.AppendElement(std::pair<nsString, OwningStringOrLong>(NS_LITERAL_STRING("long"),
+                                                                a));
+  a.SetAsString() = NS_LITERAL_STRING("a");
+  mValues.AppendElement(std::pair<nsString, OwningStringOrLong>(NS_LITERAL_STRING("string"),
+                                                                a));
+}
+
+//static
+already_AddRefed<TestInterfaceIterableDoubleUnion>
+TestInterfaceIterableDoubleUnion::Constructor(const GlobalObject& aGlobal,
+                                              ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!window) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  RefPtr<TestInterfaceIterableDoubleUnion> r = new TestInterfaceIterableDoubleUnion(window);
+  return r.forget();
+}
+
+JSObject*
+TestInterfaceIterableDoubleUnion::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return TestInterfaceIterableDoubleUnionBinding::Wrap(aCx, this, aGivenProto);
+}
+
+nsPIDOMWindowInner*
+TestInterfaceIterableDoubleUnion::GetParentObject() const
+{
+  return mParent;
+}
+
+size_t
+TestInterfaceIterableDoubleUnion::GetIterableLength()
+{
+  return mValues.Length();
+}
+
+nsAString&
+TestInterfaceIterableDoubleUnion::GetKeyAtIndex(uint32_t aIndex)
+{
+  MOZ_ASSERT(aIndex < mValues.Length());
+  return mValues.ElementAt(aIndex).first;
+}
+
+OwningStringOrLong&
+TestInterfaceIterableDoubleUnion::GetValueAtIndex(uint32_t aIndex)
+{
+  MOZ_ASSERT(aIndex < mValues.Length());
+  return mValues.ElementAt(aIndex).second;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/TestInterfaceIterableDoubleUnion.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 mozilla_dom_TestInterfaceIterableDoubleUnion_h
+#define mozilla_dom_TestInterfaceIterableDoubleUnion_h
+
+#include "nsWrapperCache.h"
+#include "nsCOMPtr.h"
+
+class nsPIDOMWindowInner;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class GlobalObject;
+
+// Implementation of test binding for webidl iterable interfaces, using
+// primitives for value type
+class TestInterfaceIterableDoubleUnion final : public nsISupports,
+                                               public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceIterableDoubleUnion)
+
+  explicit TestInterfaceIterableDoubleUnion(nsPIDOMWindowInner* aParent);
+  nsPIDOMWindowInner* GetParentObject() const;
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+  static already_AddRefed<TestInterfaceIterableDoubleUnion>
+    Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
+
+  size_t GetIterableLength();
+  nsAString& GetKeyAtIndex(uint32_t aIndex);
+  OwningStringOrLong& GetValueAtIndex(uint32_t aIndex);
+private:
+  virtual ~TestInterfaceIterableDoubleUnion() {}
+  nsCOMPtr<nsPIDOMWindowInner> mParent;
+  nsTArray<std::pair<nsString, OwningStringOrLong>> mValues;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_TestInterfaceIterableDoubleUnion_h
--- a/dom/bindings/test/test_iterable.html
+++ b/dom/bindings/test/test_iterable.html
@@ -169,13 +169,73 @@
        is(value.value, undefined, "IterableDouble: Value iterator value should be undefined");
        is(value.done, true, "IterableDouble: Value iterator done should be true");
        is(entry.value, undefined, "IterableDouble: Entry iterator value should be undefined");
        is(entry.done, true, "IterableDouble: Entry iterator done should be true");
        is(Object.prototype.toString.call(Object.getPrototypeOf(key_itr)),
           "[object TestInterfaceIterableDoubleIteratorPrototype]",
           "iterator prototype should have the right brand");
 
+       // Simple dual type iterable creation and functionality test
+       info("IterableDoubleUnion: Testing simple iterable creation and functionality");
+       itr = new TestInterfaceIterableDoubleUnion();
+       testExistence("IterableDoubleUnion: ", itr, base_properties);
+       is(itr.entries, itr[Symbol.iterator],
+          "IterableDoubleUnion: Should be using @@iterator for 'entries'");
+       var elements = [["long", 1], ["string", "a"]]
+       var keys = [...itr.keys()];
+       var values = [...itr.values()];
+       var entries = [...itr.entries()];
+       var key_itr = itr.keys();
+       var value_itr = itr.values();
+       var entries_itr = itr.entries();
+       for (var i = 0; i < elements.length; ++i) {
+         var key = key_itr.next();
+         var value = value_itr.next();
+         var entry = entries_itr.next();
+         is(key.value, elements[i][0], "IterableDoubleUnion: Key iterator value should be " + elements[i][0]);
+         is(key.value, keys[i],
+            "IterableDoubleUnion: Key iterator value should match destructuring " + i);
+         is(value.value, elements[i][1], "IterableDoubleUnion: Value iterator value should be " + elements[i][1]);
+         is(value.value, values[i],
+            "IterableDoubleUnion: Value iterator value should match destructuring " + i);
+         is(entry.value[0], elements[i][0], "IterableDoubleUnion: Entry iterator value 0 should be " + elements[i][0]);
+         is(entry.value[1], elements[i][1], "IterableDoubleUnion: Entry iterator value 1 should be " + elements[i][1]);
+         is(entry.value[0], entries[i][0],
+            "IterableDoubleUnion: Entry iterator value 0 should match destructuring " + i);
+         is(entry.value[1], entries[i][1],
+            "IterableDoubleUnion: Entry iterator value 1 should match destructuring " + i);
+       }
+
+       callsToForEachCallback = 0;
+       thisArg = {};
+       itr.forEach(function(value, key, obj) {
+         is(key, keys[callsToForEachCallback],
+            `IterableDoubleUnion: Should have the right key at ${callsToForEachCallback} calls to forEach callback`);
+         is(value, values[callsToForEachCallback],
+            `IterableDoubleUnion: Should have the right value at ${callsToForEachCallback} calls to forEach callback`);
+         is(this, thisArg,
+            "IterableDoubleUnion: Should have the right this value for forEach callback");
+         is(obj, itr,
+            "IterableSingle: Should have the right third arg for forEach callback");
+         ++callsToForEachCallback;
+       }, thisArg);
+       is(callsToForEachCallback, 2,
+          "IterableDoubleUnion: Should have right total number of calls to forEach callback");
+
+       var key = key_itr.next();
+       var value = value_itr.next();
+       var entry = entries_itr.next()
+       is(key.value, undefined, "IterableDoubleUnion: Key iterator value should be undefined");
+       is(key.done, true, "IterableDoubleUnion: Key iterator done should be true");
+       is(value.value, undefined, "IterableDoubleUnion: Value iterator value should be undefined");
+       is(value.done, true, "IterableDoubleUnion: Value iterator done should be true");
+       is(entry.value, undefined, "IterableDoubleUnion: Entry iterator value should be undefined");
+       is(entry.done, true, "IterableDoubleUnion: Entry iterator done should be true");
+       is(Object.prototype.toString.call(Object.getPrototypeOf(key_itr)),
+          "[object TestInterfaceIterableDoubleUnionIteratorPrototype]",
+          "iterator prototype should have the right brand");
+
        SimpleTest.finish();
      });
     </script>
   </body>
 </html>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -900,17 +900,17 @@ public:
   static void PreTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
       static_cast<CanvasRenderingContext2DUserData*>(aData);
     CanvasRenderingContext2D* context = self->mContext;
     if (!context || !context->mTarget)
       return;
 
-    context->ReturnTarget();
+    context->OnStableState();
   }
 
   static void DidTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
       static_cast<CanvasRenderingContext2DUserData*>(aData);
     if (self->mContext) {
       self->mContext->MarkContextClean();
@@ -1499,16 +1499,20 @@ CanvasRenderingContext2D::ScheduleStable
   nsContentUtils::RunInStableState(
     NewRunnableMethod(this, &CanvasRenderingContext2D::OnStableState)
   );
 }
 
 void
 CanvasRenderingContext2D::OnStableState()
 {
+  if (!mHasPendingStableStateCallback) {
+    return;
+  }
+
   ReturnTarget();
 
   mHasPendingStableStateCallback = false;
 }
 
 CanvasRenderingContext2D::RenderingMode
 CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
                                        RenderingMode aRenderingMode)
@@ -1524,26 +1528,26 @@ CanvasRenderingContext2D::EnsureTarget(c
   MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode);
 
   RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode) ? mRenderingMode : aRenderingMode;
 
   if (mTarget && mode == mRenderingMode) {
     return mRenderingMode;
   }
 
+  ScheduleStableStateCallback();
+
   if (mBufferProvider && mode == mRenderingMode) {
     gfx::Rect rect(0, 0, mWidth, mHeight);
     if (aCoveredRect && CurrentState().transform.TransformBounds(*aCoveredRect).Contains(rect)) {
       mTarget = mBufferProvider->BorrowDrawTarget(IntRect());
     } else {
       mTarget = mBufferProvider->BorrowDrawTarget(IntRect(0, 0, mWidth, mHeight));
     }
 
-    ScheduleStableStateCallback();
-
     if (mTarget) {
       // Restore clip and transform.
       for (uint32_t i = 0; i < mStyleStack.Length(); i++) {
         mTarget->SetTransform(mStyleStack[i].transform);
         for (uint32_t c = 0; c < mStyleStack[i].clipsPushed.Length(); c++) {
           mTarget->PushClip(mStyleStack[i].clipsPushed[c]);
         }
       }
@@ -1726,17 +1730,17 @@ CanvasRenderingContext2D::ClearTarget()
       }
     }
   }
 }
 
 void
 CanvasRenderingContext2D::ReturnTarget()
 {
-  if (mTarget && mBufferProvider) {
+  if (mTarget && mBufferProvider && mTarget != sErrorTarget) {
     CurrentState().transform = mTarget->GetTransform();
     for (uint32_t i = 0; i < mStyleStack.Length(); i++) {
       for (uint32_t c = 0; c < mStyleStack[i].clipsPushed.Length(); c++) {
         mTarget->PopClip();
       }
     }
     mBufferProvider->ReturnDrawTarget(mTarget.forget());
   }
@@ -5688,17 +5692,17 @@ CanvasRenderingContext2D::GetBufferProvi
     return mBufferProvider;
   }
 
   if (mTarget) {
     mBufferProvider = new PersistentBufferProviderBasic(mTarget);
     return mBufferProvider;
   }
 
-  if (aManager) {
+  if (aManager && !mIsSkiaGL) {
     mBufferProvider = aManager->CreatePersistentBufferProvider(gfx::IntSize(mWidth, mHeight),
                                                                GetSurfaceFormat());
   }
 
   return mBufferProvider;
 }
 
 already_AddRefed<Layer>
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -5894,17 +5894,17 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__typedarrays__array-large-array-tests.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__typedarrays__array-unit-tests.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__typedarrays__data-view-crash.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__typedarrays__data-view-test.html]
-skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
+fail-if = 1
 [generated/test_2_conformance__typedarrays__typed-arrays-in-workers.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__uniforms__gl-uniform-arrays.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__uniforms__gl-uniform-bool.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__uniforms__gl-uniformmatrix4fv.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
@@ -6766,16 +6766,17 @@ skip-if = (os == 'android')
 [generated/test_conformance__textures__video__tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html]
 skip-if = (os == 'android')
 [generated/test_conformance__typedarrays__array-buffer-crash.html]
 [generated/test_conformance__typedarrays__array-buffer-view-crash.html]
 [generated/test_conformance__typedarrays__array-large-array-tests.html]
 [generated/test_conformance__typedarrays__array-unit-tests.html]
 [generated/test_conformance__typedarrays__data-view-crash.html]
 [generated/test_conformance__typedarrays__data-view-test.html]
+fail-if = 1
 [generated/test_conformance__typedarrays__typed-arrays-in-workers.html]
 [generated/test_conformance__uniforms__gl-uniform-arrays.html]
 [generated/test_conformance__uniforms__gl-uniform-bool.html]
 [generated/test_conformance__uniforms__gl-uniformmatrix4fv.html]
 [generated/test_conformance__uniforms__gl-unknown-uniform.html]
 [generated/test_conformance__uniforms__null-uniform-location.html]
 [generated/test_conformance__uniforms__out-of-bounds-uniform-array-access.html]
 skip-if = (os == 'android') || (os == 'mac' && os_version == '10.6')
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -28,16 +28,23 @@
 subsuite = webgl
 # Skip B2G for now, until we get a handle on the longer tail of emulator bugs.
 # Bug 1136181 disabled on Mulet for intermittent failures
 skip-if = os == 'b2g' || ((os == 'linux') && (buildapp == 'mulet'))
 
 [generated/test_..__always-fail.html]
 fail-if = 1
 
+[generated/test_conformance__typedarrays__data-view-test.html]
+# Test is out-of-date with spec.
+fail-if = 1
+[generated/test_2_conformance__typedarrays__data-view-test.html]
+# Test is out-of-date with spec.
+fail-if = 1
+
 ####################
 # Tests requesting non-local network connections.
 
 [generated/test_conformance__more__functions__readPixelsBadArgs.html]
 # (TODO) FATAL ERROR: Non-local network connections are disabled and a connection attempt to www.opengl.org (45.55.206.190) was made.
 skip-if = 1
 [generated/test_2_conformance__more__functions__readPixelsBadArgs.html]
 # (TODO) FATAL ERROR: Non-local network connections are disabled and a connection attempt to www.opengl.org (45.55.206.190) was made.
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -199,27 +199,31 @@ CryptoKey::GetAlgorithm(JSContext* cx, J
     case KeyAlgorithmProxy::AES:
       converted = ToJSValue(cx, mAlgorithm.mAes, &val);
       break;
     case KeyAlgorithmProxy::HMAC:
       converted = ToJSValue(cx, mAlgorithm.mHmac, &val);
       break;
     case KeyAlgorithmProxy::RSA: {
       RootedDictionary<RsaHashedKeyAlgorithm> rsa(cx);
-      mAlgorithm.mRsa.ToKeyAlgorithm(cx, rsa);
-      converted = ToJSValue(cx, rsa, &val);
+      converted = mAlgorithm.mRsa.ToKeyAlgorithm(cx, rsa);
+      if (converted) {
+        converted = ToJSValue(cx, rsa, &val);
+      }
       break;
     }
     case KeyAlgorithmProxy::EC:
       converted = ToJSValue(cx, mAlgorithm.mEc, &val);
       break;
     case KeyAlgorithmProxy::DH: {
       RootedDictionary<DhKeyAlgorithm> dh(cx);
-      mAlgorithm.mDh.ToKeyAlgorithm(cx, dh);
-      converted = ToJSValue(cx, dh, &val);
+      converted = mAlgorithm.mDh.ToKeyAlgorithm(cx, dh);
+      if (converted) {
+        converted = ToJSValue(cx, dh, &val);
+      }
       break;
     }
   }
   if (!converted) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
--- a/dom/crypto/KeyAlgorithmProxy.h
+++ b/dom/crypto/KeyAlgorithmProxy.h
@@ -20,42 +20,61 @@ namespace dom {
 // A heap-safe variant of RsaHashedKeyAlgorithm
 // The only difference is that it uses CryptoBuffer instead of Uint8Array
 struct RsaHashedKeyAlgorithmStorage {
   nsString mName;
   KeyAlgorithm mHash;
   uint16_t mModulusLength;
   CryptoBuffer mPublicExponent;
 
-  void
+  bool
   ToKeyAlgorithm(JSContext* aCx, RsaHashedKeyAlgorithm& aRsa) const
   {
+    JS::Rooted<JSObject*> exponent(aCx, mPublicExponent.ToUint8Array(aCx));
+    if (!exponent) {
+      return false;
+    }
+
     aRsa.mName = mName;
     aRsa.mModulusLength = mModulusLength;
     aRsa.mHash.mName = mHash.mName;
-    aRsa.mPublicExponent.Init(mPublicExponent.ToUint8Array(aCx));
+    aRsa.mPublicExponent.Init(exponent);
     aRsa.mPublicExponent.ComputeLengthAndData();
+
+    return true;
   }
 };
 
 // A heap-safe variant of DhKeyAlgorithm
 // The only difference is that it uses CryptoBuffers instead of Uint8Arrays
 struct DhKeyAlgorithmStorage {
   nsString mName;
   CryptoBuffer mPrime;
   CryptoBuffer mGenerator;
 
-  void
+  bool
   ToKeyAlgorithm(JSContext* aCx, DhKeyAlgorithm& aDh) const
   {
+    JS::Rooted<JSObject*> prime(aCx, mPrime.ToUint8Array(aCx));
+    if (!prime) {
+      return false;
+    }
+
+    JS::Rooted<JSObject*> generator(aCx, mGenerator.ToUint8Array(aCx));
+    if (!generator) {
+      return false;
+    }
+
     aDh.mName = mName;
-    aDh.mPrime.Init(mPrime.ToUint8Array(aCx));
+    aDh.mPrime.Init(prime);
     aDh.mPrime.ComputeLengthAndData();
-    aDh.mGenerator.Init(mGenerator.ToUint8Array(aCx));
+    aDh.mGenerator.Init(generator);
     aDh.mGenerator.ComputeLengthAndData();
+
+    return true;
   }
 };
 
 // This class encapuslates a KeyAlgorithm object, and adds several
 // methods that make WebCrypto operations simpler.
 struct KeyAlgorithmProxy
 {
   enum KeyAlgorithmType {
--- a/dom/events/DataTransferItem.cpp
+++ b/dom/events/DataTransferItem.cpp
@@ -32,17 +32,17 @@ FileMimeNameData kFileMimeNameMap[] = {
 };
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItem, mData,
-                                      mPrincipal, mParent)
+                                      mPrincipal, mParent, mCachedFile)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItem)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransferItem)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransferItem)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -110,16 +110,29 @@ IsWebkitPrefixSupportEnabled()
     sIsPrefCached = true;
     Preferences::AddBoolVarCache(&sIsWebkitPrefixSupportEnabled,
                                  "layout.css.prefixes.webkit");
   }
 
   return sIsWebkitPrefixSupportEnabled;
 }
 
+static bool
+IsPrefixedPointerLockEnabled()
+{
+  static bool sIsPrefixedPointerLockEnabled;
+  static bool sIsPrefCached = false;
+  if (!sIsPrefCached) {
+    sIsPrefCached = true;
+    Preferences::AddBoolVarCache(&sIsPrefixedPointerLockEnabled,
+                                 "pointer-lock-api.prefixed.enabled");
+  }
+  return sIsPrefixedPointerLockEnabled;
+}
+
 EventListenerManagerBase::EventListenerManagerBase()
   : mNoListenerForEvent(eVoidEvent)
   , mMayHavePaintEventListener(false)
   , mMayHaveMutationListeners(false)
   , mMayHaveCapturingListeners(false)
   , mMayHaveSystemGroupListeners(false)
   , mMayHaveTouchEventListener(false)
   , mMayHaveMouseEnterLeaveEventListener(false)
@@ -232,17 +245,17 @@ already_AddRefed<nsPIDOMWindowInner>
 EventListenerManager::GetTargetAsInnerWindow() const
 {
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mTarget);
   return window.forget();
 }
 
 void
 EventListenerManager::AddEventListenerInternal(
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         EventMessage aEventMessage,
                         nsIAtom* aTypeAtom,
                         const nsAString& aTypeString,
                         const EventListenerFlags& aFlags,
                         bool aHandler,
                         bool aAllEvents)
 {
   MOZ_ASSERT(// Main thread
@@ -273,17 +286,16 @@ EventListenerManager::AddEventListenerIn
     }
   }
 
   mNoListenerForEvent = eVoidEvent;
   mNoListenerForEventAtom = nullptr;
 
   listener = aAllEvents ? mListeners.InsertElementAt(0) :
                           mListeners.AppendElement();
-  listener->mListener = aListenerHolder;
   listener->mEventMessage = aEventMessage;
   listener->mTypeString = aTypeString;
   listener->mTypeAtom = aTypeAtom;
   listener->mFlags = aFlags;
   listener->mListenerIsHandler = aHandler;
   listener->mHandlerIsString = false;
   listener->mAllEvents = aAllEvents;
   listener->mIsChrome = mIsMainThreadELM &&
@@ -296,16 +308,17 @@ EventListenerManager::AddEventListenerIn
     listener->mListenerType = Listener::eJSEventListener;
   } else if (aListenerHolder.HasWebIDLCallback()) {
     listener->mListenerType = Listener::eWebIDLListener;
   } else if ((wjs = do_QueryInterface(aListenerHolder.GetXPCOMCallback()))) {
     listener->mListenerType = Listener::eWrappedJSListener;
   } else {
     listener->mListenerType = Listener::eNativeListener;
   }
+  listener->mListener = Move(aListenerHolder);
 
 
   if (aFlags.mInSystemGroup) {
     mMayHaveSystemGroupListeners = true;
   }
   if (aFlags.mCapture) {
     mMayHaveCapturingListeners = true;
   }
@@ -343,27 +356,21 @@ EventListenerManager::AddEventListenerIn
   } else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
     EnableDevice(eDeviceMotion);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   } else if (aTypeAtom == nsGkAtoms::onorientationchange) {
     EnableDevice(eOrientationChange);
 #endif
 #ifdef MOZ_B2G
   } else if (aTypeAtom == nsGkAtoms::onmoztimechange) {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      window->EnableTimeChangeNotifications();
-    }
+    EnableDevice(eTimeChange);
   } else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      window->EnableNetworkEvent(eNetworkUpload);
-    }
+    EnableDevice(eNetworkUpload);
   } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      window->EnableNetworkEvent(eNetworkDownload);
-    }
+    EnableDevice(eNetworkDownload);
 #endif // MOZ_B2G
   } else if (aTypeAtom == nsGkAtoms::ontouchstart ||
              aTypeAtom == nsGkAtoms::ontouchend ||
              aTypeAtom == nsGkAtoms::ontouchmove ||
              aTypeAtom == nsGkAtoms::ontouchcancel) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindowInner* window = GetInnerWindowForTarget();
     // we don't want touchevent listeners added by scrollbars to flip this flag
@@ -481,16 +488,21 @@ EventListenerManager::IsDeviceType(Event
     case eAbsoluteDeviceOrientation:
     case eDeviceMotion:
     case eDeviceLight:
     case eDeviceProximity:
     case eUserProximity:
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
     case eOrientationChange:
 #endif
+#ifdef MOZ_B2G
+    case eTimeChange:
+    case eNetworkUpload:
+    case eNetworkDownload:
+#endif
       return true;
     default:
       break;
   }
   return false;
 }
 
 void
@@ -531,16 +543,25 @@ EventListenerManager::EnableDevice(Event
       window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
       window->EnableDeviceSensor(SENSOR_GYROSCOPE);
       break;
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
     case eOrientationChange:
       window->EnableOrientationChangeListener();
       break;
 #endif
+#ifdef MOZ_B2G
+    case eTimeChange:
+      window->EnableTimeChangeNotifications();
+      break;
+    case eNetworkUpload:
+    case eNetworkDownload:
+      window->EnableNetworkEvent(aEventMessage);
+      break;
+#endif
     default:
       NS_WARNING("Enabling an unknown device sensor.");
       break;
   }
 }
 
 void
 EventListenerManager::DisableDevice(EventMessage aEventMessage)
@@ -577,103 +598,104 @@ EventListenerManager::DisableDevice(Even
     case eDeviceLight:
       window->DisableDeviceSensor(SENSOR_LIGHT);
       break;
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
     case eOrientationChange:
       window->DisableOrientationChangeListener();
       break;
 #endif
+#ifdef MOZ_B2G
+    case eTimeChange:
+      window->DisableTimeChangeNotifications();
+      break;
+    case eNetworkUpload:
+    case eNetworkDownload:
+      window->DisableNetworkEvent(aEventMessage);
+      break;
+#endif // MOZ_B2G
     default:
       NS_WARNING("Disabling an unknown device sensor.");
       break;
   }
 }
 
 void
+EventListenerManager::NotifyEventListenerRemoved(nsIAtom* aUserType)
+{
+  // If the following code is changed, other callsites of EventListenerRemoved
+  // and NotifyAboutMainThreadListenerChange should be changed too.
+  mNoListenerForEvent = eVoidEvent;
+  mNoListenerForEventAtom = nullptr;
+  if (mTarget && aUserType) {
+    mTarget->EventListenerRemoved(aUserType);
+  }
+  if (mIsMainThreadELM && mTarget) {
+    EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
+                                                              aUserType);
+  }
+}
+
+void
 EventListenerManager::RemoveEventListenerInternal(
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         EventMessage aEventMessage,
                         nsIAtom* aUserType,
                         const nsAString& aTypeString,
                         const EventListenerFlags& aFlags,
                         bool aAllEvents)
 {
   if (!aListenerHolder || !aEventMessage || mClearingListeners) {
     return;
   }
 
   Listener* listener;
 
   uint32_t count = mListeners.Length();
   uint32_t typeCount = 0;
   bool deviceType = IsDeviceType(aEventMessage);
-#ifdef MOZ_B2G
-  bool timeChangeEvent = (aEventMessage == eTimeChange);
-  bool networkEvent = (aEventMessage == eNetworkUpload ||
-                       aEventMessage == eNetworkDownload);
-#endif // MOZ_B2G
 
   for (uint32_t i = 0; i < count; ++i) {
     listener = &mListeners.ElementAt(i);
     if (EVENT_TYPE_EQUALS(listener, aEventMessage, aUserType, aTypeString,
                           aAllEvents)) {
       ++typeCount;
       if (listener->mListener == aListenerHolder &&
           listener->mFlags.EqualsForRemoval(aFlags)) {
         RefPtr<EventListenerManager> kungFuDeathGrip(this);
         mListeners.RemoveElementAt(i);
         --count;
-        mNoListenerForEvent = eVoidEvent;
-        mNoListenerForEventAtom = nullptr;
-        if (mTarget && aUserType) {
-          mTarget->EventListenerRemoved(aUserType);
-        }
-        if (mIsMainThreadELM && mTarget) {
-          EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
-                                                                    aUserType);
-        }
-
-        if (!deviceType
-#ifdef MOZ_B2G
-            && !timeChangeEvent && !networkEvent
-#endif // MOZ_B2G
-            ) {
+        NotifyEventListenerRemoved(aUserType);
+        if (!deviceType) {
           return;
         }
         --typeCount;
       }
     }
   }
 
   if (!aAllEvents && deviceType && typeCount == 0) {
     DisableDevice(aEventMessage);
-#ifdef MOZ_B2G
-  } else if (timeChangeEvent && typeCount == 0) {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      window->DisableTimeChangeNotifications();
-    }
-  } else if (!aAllEvents && networkEvent && typeCount == 0) {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      window->DisableNetworkEvent(aEventMessage);
-    }
-#endif // MOZ_B2G
   }
 }
 
 bool
 EventListenerManager::ListenerCanHandle(const Listener* aListener,
                                         const WidgetEvent* aEvent,
                                         EventMessage aEventMessage) const
 
 {
   MOZ_ASSERT(aEventMessage == aEvent->mMessage ||
              aEventMessage == GetLegacyEventMessage(aEvent->mMessage),
              "aEvent and aEventMessage should agree, modulo legacyness");
 
+  // The listener has been removed, it cannot handle anything.
+  if (aListener->mListenerType == Listener::eNoListener) {
+    return false;
+  }
   // This is slightly different from EVENT_TYPE_EQUALS in that it returns
   // true even when aEvent->mMessage == eUnidentifiedEvent and
   // aListener=>mEventMessage != eUnidentifiedEvent as long as the atoms are
   // the same
   if (aListener->mAllEvents) {
     return true;
   }
   if (aEvent->mMessage == eUnidentifiedEvent) {
@@ -692,40 +714,42 @@ EventListenerManager::ListenerCanHandle(
     }
   }
   MOZ_ASSERT(mIsMainThreadELM);
   return aListener->mEventMessage == aEventMessage;
 }
 
 void
 EventListenerManager::AddEventListenerByType(
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         const nsAString& aType,
                         const EventListenerFlags& aFlags)
 {
   nsCOMPtr<nsIAtom> atom;
   EventMessage message = mIsMainThreadELM ?
     nsContentUtils::GetEventMessageAndAtomForListener(aType,
                                                       getter_AddRefs(atom)) :
     eUnidentifiedEvent;
-  AddEventListenerInternal(aListenerHolder, message, atom, aType, aFlags);
+  AddEventListenerInternal(Move(aListenerHolder),
+                           message, atom, aType, aFlags);
 }
 
 void
 EventListenerManager::RemoveEventListenerByType(
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         const nsAString& aType,
                         const EventListenerFlags& aFlags)
 {
   nsCOMPtr<nsIAtom> atom;
   EventMessage message = mIsMainThreadELM ?
     nsContentUtils::GetEventMessageAndAtomForListener(aType,
                                                       getter_AddRefs(atom)) :
     eUnidentifiedEvent;
-  RemoveEventListenerInternal(aListenerHolder, message, atom, aType, aFlags);
+  RemoveEventListenerInternal(Move(aListenerHolder),
+                              message, atom, aType, aFlags);
 }
 
 EventListenerManager::Listener*
 EventListenerManager::FindEventHandler(EventMessage aEventMessage,
                                        nsIAtom* aTypeAtom,
                                        const nsAString& aTypeString)
 {
   // Run through the listeners for this type and see if a script
@@ -759,19 +783,18 @@ EventListenerManager::SetEventHandlerInt
     // If we didn't find a script listener or no listeners existed
     // create and add a new one.
     EventListenerFlags flags;
     flags.mListenerIsJSListener = true;
 
     nsCOMPtr<JSEventHandler> jsEventHandler;
     NS_NewJSEventHandler(mTarget, aName,
                          aTypedHandler, getter_AddRefs(jsEventHandler));
-    EventListenerHolder listenerHolder(jsEventHandler);
-    AddEventListenerInternal(listenerHolder, eventMessage, aName, aTypeString,
-                             flags, true);
+    AddEventListenerInternal(EventListenerHolder(jsEventHandler),
+                             eventMessage, aName, aTypeString, flags, true);
 
     listener = FindEventHandler(eventMessage, aName, aTypeString);
   } else {
     JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
     MOZ_ASSERT(jsEventHandler,
                "How can we have an event handler with no JSEventHandler?");
 
     bool same = jsEventHandler->GetTypedEventHandler() == aTypedHandler;
@@ -895,24 +918,17 @@ EventListenerManager::RemoveEventHandler
     return;
   }
 
   EventMessage eventMessage = nsContentUtils::GetEventMessage(aName);
   Listener* listener = FindEventHandler(eventMessage, aName, aTypeString);
 
   if (listener) {
     mListeners.RemoveElementAt(uint32_t(listener - &mListeners.ElementAt(0)));
-    mNoListenerForEvent = eVoidEvent;
-    mNoListenerForEventAtom = nullptr;
-    if (mTarget && aName) {
-      mTarget->EventListenerRemoved(aName);
-    }
-    if (mIsMainThreadELM && mTarget) {
-      EventListenerService::NotifyAboutMainThreadListenerChange(mTarget, aName);
-    }
+    NotifyEventListenerRemoved(aName);
   }
 }
 
 nsresult
 EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
                                                   const nsAString* aBody,
                                                   Element* aElement)
 {
@@ -1087,17 +1103,18 @@ EventListenerManager::CompileEventHandle
 }
 
 nsresult
 EventListenerManager::HandleEventSubType(Listener* aListener,
                                          nsIDOMEvent* aDOMEvent,
                                          EventTarget* aCurrentTarget)
 {
   nsresult result = NS_OK;
-  EventListenerHolder listenerHolder(aListener->mListener);  // strong ref
+  // strong ref
+  EventListenerHolder listenerHolder(aListener->mListener.Clone());
 
   // If this is a script handler and we haven't yet
   // compiled the event handler itself
   if ((aListener->mListenerType == Listener::eJSEventListener) &&
       aListener->mHandlerIsString) {
     result = CompileEventHandlerInternal(aListener, nullptr, nullptr);
     aListener = nullptr;
   }
@@ -1123,29 +1140,39 @@ EventListenerManager::HandleEventSubType
   return result;
 }
 
 EventMessage
 EventListenerManager::GetLegacyEventMessage(EventMessage aEventMessage) const
 {
   // (If we're off-main-thread, we can't check the pref; so we just behave as
   // if it's disabled.)
-  if (mIsMainThreadELM && IsWebkitPrefixSupportEnabled()) {
-    // webkit-prefixed legacy events:
-    if (aEventMessage == eTransitionEnd) {
-      return eWebkitTransitionEnd;
+  if (mIsMainThreadELM) {
+    if (IsWebkitPrefixSupportEnabled()) {
+      // webkit-prefixed legacy events:
+      if (aEventMessage == eTransitionEnd) {
+        return eWebkitTransitionEnd;
+      }
+      if (aEventMessage == eAnimationStart) {
+        return eWebkitAnimationStart;
+      }
+      if (aEventMessage == eAnimationEnd) {
+        return eWebkitAnimationEnd;
+      }
+      if (aEventMessage == eAnimationIteration) {
+        return eWebkitAnimationIteration;
+      }
     }
-    if (aEventMessage == eAnimationStart) {
-      return eWebkitAnimationStart;
-    }
-    if (aEventMessage == eAnimationEnd) {
-      return eWebkitAnimationEnd;
-    }
-    if (aEventMessage == eAnimationIteration) {
-      return eWebkitAnimationIteration;
+    if (IsPrefixedPointerLockEnabled()) {
+      if (aEventMessage == ePointerLockChange) {
+        return eMozPointerLockChange;
+      }
+      if (aEventMessage == ePointerLockError) {
+        return eMozPointerLockError;
+      }
     }
   }
 
   switch (aEventMessage) {
     case eFullscreenChange:
       return eMozFullscreenChange;
     case eFullscreenError:
       return eMozFullscreenError;
@@ -1177,16 +1204,17 @@ EventListenerManager::HandleEventInterna
   Maybe<nsAutoPopupStatePusher> popupStatePusher;
   if (mIsMainThreadELM) {
     popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent));
   }
 
   bool hasListener = false;
   bool hasListenerForCurrentGroup = false;
   bool usingLegacyMessage = false;
+  bool hasRemovedListener = false;
   EventMessage eventMessage = aEvent->mMessage;
 
   while (true) {
     nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
     Maybe<EventMessageAutoOverride> legacyAutoOverride;
     while (iter.HasMore()) {
       if (aEvent->mFlags.mImmediatePropagationStopped) {
         break;
@@ -1241,16 +1269,25 @@ EventListenerManager::HandleEventInterna
                   timelines->AddMarkerForDocShell(docShell, Move(
                     MakeUnique<EventTimelineMarker>(
                       typeStr, phase, MarkerTracingType::START)));
                 }
               }
             }
 
             aEvent->mFlags.mInPassiveListener = listener->mFlags.mPassive;
+            Maybe<Listener> listenerHolder;
+            if (listener->mFlags.mOnce) {
+              // Move the listener to the stack before handling the event.
+              // The order is important, otherwise the listener could be
+              // called again inside the listener.
+              listenerHolder.emplace(Move(*listener));
+              listener = listenerHolder.ptr();
+              hasRemovedListener = true;
+            }
             if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
               aEvent->mFlags.mExceptionWasRaised = true;
             }
             aEvent->mFlags.mInPassiveListener = false;
 
             if (needsEndEventMarker) {
               timelines->AddMarkerForDocShell(
                 docShell, "DOMEvent", MarkerTracingType::END);
@@ -1277,16 +1314,46 @@ EventListenerManager::HandleEventInterna
 
     // Recheck our listeners, using the legacy event message we just looked up:
     eventMessage = legacyEventMessage;
     usingLegacyMessage = true;
   }
 
   aEvent->mCurrentTarget = nullptr;
 
+  if (hasRemovedListener) {
+    // If there are any once listeners replaced with a placeholder in
+    // the loop above, we need to clean up them here. Note that, this
+    // could clear once listeners handled in some outer level as well,
+    // but that should not affect the result.
+    mListeners.RemoveElementsBy([](const Listener& aListener) {
+      return aListener.mListenerType == Listener::eNoListener;
+    });
+    NotifyEventListenerRemoved(aEvent->mSpecifiedEventType);
+    if (IsDeviceType(aEvent->mMessage)) {
+      // This is a device-type event, we need to check whether we can
+      // disable device after removing the once listeners.
+      bool hasAnyListener = false;
+      nsAutoTObserverArray<Listener, 2>::ForwardIterator iter(mListeners);
+      while (iter.HasMore()) {
+        Listener* listener = &iter.GetNext();
+        if (EVENT_TYPE_EQUALS(listener, aEvent->mMessage,
+                              aEvent->mSpecifiedEventType,
+                              aEvent->mSpecifiedEventTypeString,
+                              /* all events */ false)) {
+          hasAnyListener = true;
+          break;
+        }
+      }
+      if (!hasAnyListener) {
+        DisableDevice(aEvent->mMessage);
+      }
+    }
+  }
+
   if (mIsMainThreadELM && !hasListener) {
     mNoListenerForEvent = aEvent->mMessage;
     mNoListenerForEventAtom = aEvent->mSpecifiedEventType;
   }
 
   if (aEvent->DefaultPrevented()) {
     *aEventStatus = nsEventStatus_eConsumeNoDefault;
   }
@@ -1297,101 +1364,100 @@ EventListenerManager::Disconnect()
 {
   mTarget = nullptr;
   RemoveAllListeners();
 }
 
 void
 EventListenerManager::AddEventListener(
                         const nsAString& aType,
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         bool aUseCapture,
                         bool aWantsUntrusted)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
   flags.mAllowUntrustedEvents = aWantsUntrusted;
-  return AddEventListenerByType(aListenerHolder, aType, flags);
+  return AddEventListenerByType(Move(aListenerHolder), aType, flags);
 }
 
 void
 EventListenerManager::AddEventListener(
                         const nsAString& aType,
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         const dom::AddEventListenerOptionsOrBoolean& aOptions,
                         bool aWantsUntrusted)
 {
   EventListenerFlags flags;
   if (aOptions.IsBoolean()) {
     flags.mCapture = aOptions.GetAsBoolean();
   } else {
     const auto& options = aOptions.GetAsAddEventListenerOptions();
     flags.mCapture = options.mCapture;
     flags.mInSystemGroup = options.mMozSystemGroup;
     flags.mPassive = options.mPassive;
+    flags.mOnce = options.mOnce;
   }
   flags.mAllowUntrustedEvents = aWantsUntrusted;
-  return AddEventListenerByType(aListenerHolder, aType, flags);
+  return AddEventListenerByType(Move(aListenerHolder), aType, flags);
 }
 
 void
 EventListenerManager::RemoveEventListener(
                         const nsAString& aType,
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         bool aUseCapture)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
-  RemoveEventListenerByType(aListenerHolder, aType, flags);
+  RemoveEventListenerByType(Move(aListenerHolder), aType, flags);
 }
 
 void
 EventListenerManager::RemoveEventListener(
                         const nsAString& aType,
-                        const EventListenerHolder& aListenerHolder,
+                        EventListenerHolder aListenerHolder,
                         const dom::EventListenerOptionsOrBoolean& aOptions)
 {
   EventListenerFlags flags;
   if (aOptions.IsBoolean()) {
     flags.mCapture = aOptions.GetAsBoolean();
   } else {
     const auto& options = aOptions.GetAsEventListenerOptions();
     flags.mCapture = options.mCapture;
     flags.mInSystemGroup = options.mMozSystemGroup;
   }
-  RemoveEventListenerByType(aListenerHolder, aType, flags);
+  RemoveEventListenerByType(Move(aListenerHolder), aType, flags);
 }
 
 void
 EventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aDOMListener,
                                               bool aUseCapture,
                                               bool aWantsUntrusted,
                                               bool aSystemEventGroup)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
   flags.mAllowUntrustedEvents = aWantsUntrusted;
   flags.mInSystemGroup = aSystemEventGroup;
-  EventListenerHolder listenerHolder(aDOMListener);
-  AddEventListenerInternal(listenerHolder, eAllEvents, nullptr, EmptyString(),
-                           flags, false, true);
+  AddEventListenerInternal(EventListenerHolder(aDOMListener), eAllEvents,
+                           nullptr, EmptyString(), flags, false, true);
 }
 
 void
 EventListenerManager::RemoveListenerForAllEvents(
                         nsIDOMEventListener* aDOMListener,
                         bool aUseCapture,
                         bool aSystemEventGroup)
 {
   EventListenerFlags flags;
   flags.mCapture = aUseCapture;
   flags.mInSystemGroup = aSystemEventGroup;
-  EventListenerHolder listenerHolder(aDOMListener);
-  RemoveEventListenerInternal(listenerHolder, eAllEvents, nullptr,
-                              EmptyString(), flags, true);
+  RemoveEventListenerInternal(EventListenerHolder(aDOMListener), eAllEvents,
+                              nullptr, EmptyString(), flags, true);
 }
 
 bool
 EventListenerManager::HasMutationListeners()
 {
   if (mMayHaveMutationListeners) {
     uint32_t count = mListeners.Length();
     for (uint32_t i = 0; i < count; ++i) {
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -56,39 +56,42 @@ public:
   // system group.
   bool mInSystemGroup : 1;
   // If mAllowUntrustedEvents is true, the listener is listening to the
   // untrusted events too.
   bool mAllowUntrustedEvents : 1;
   // If mPassive is true, the listener will not be calling preventDefault on the
   // event. (If it does call preventDefault, we should ignore it).
   bool mPassive : 1;
+  // If mOnce is true, the listener will be removed from the manager before it
+  // is invoked, so that it would only be invoked once.
+  bool mOnce : 1;
 
   EventListenerFlags() :
     mListenerIsJSListener(false),
     mCapture(false), mInSystemGroup(false), mAllowUntrustedEvents(false),
-    mPassive(false)
+    mPassive(false), mOnce(false)
   {
   }
 
   bool EqualsForAddition(const EventListenerFlags& aOther) const
   {
     return (mCapture == aOther.mCapture &&
             mInSystemGroup == aOther.mInSystemGroup &&
             mListenerIsJSListener == aOther.mListenerIsJSListener &&
             mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
-            // Don't compare mPassive
+            // Don't compare mPassive or mOnce
   }
 
   bool EqualsForRemoval(const EventListenerFlags& aOther) const
   {
     return (mCapture == aOther.mCapture &&
             mInSystemGroup == aOther.mInSystemGroup &&
             mListenerIsJSListener == aOther.mListenerIsJSListener);
-            // Don't compare mAllowUntrustedEvents or mPassive
+            // Don't compare mAllowUntrustedEvents, mPassive, or mOnce
   }
 };
 
 inline EventListenerFlags TrustedEventsAtBubble()
 {
   EventListenerFlags flags;
   return flags;
 }
@@ -180,42 +183,66 @@ public:
   {
     EventListenerHolder mListener;
     nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
     nsString mTypeString; // for non-main-threads
     EventMessage mEventMessage;
 
     enum ListenerType : uint8_t
     {
-      eNativeListener = 0,
+      eNoListener,
+      eNativeListener,
       eJSEventListener,
       eWrappedJSListener,
       eWebIDLListener,
-      eListenerTypeCount
     };
-    uint8_t mListenerType;
+    ListenerType mListenerType;
 
     bool mListenerIsHandler : 1;
     bool mHandlerIsString : 1;
     bool mAllEvents : 1;
     bool mIsChrome : 1;
 
     EventListenerFlags mFlags;
 
     JSEventHandler* GetJSEventHandler() const
     {
       return (mListenerType == eJSEventListener) ?
         static_cast<JSEventHandler*>(mListener.GetXPCOMCallback()) :
         nullptr;
     }
 
     Listener()
+      : mEventMessage(eVoidEvent)
+      , mListenerType(eNoListener)
+      , mListenerIsHandler(false)
+      , mHandlerIsString(false)
+      , mAllEvents(false)
+      , mIsChrome(false)
     {
-      MOZ_ASSERT(sizeof(mListenerType) == 1);
-      MOZ_ASSERT(eListenerTypeCount < 255);
+    }
+
+    Listener(Listener&& aOther)
+      : mListener(Move(aOther.mListener))
+      , mTypeAtom(aOther.mTypeAtom.forget())
+      , mTypeString(aOther.mTypeString)
+      , mEventMessage(aOther.mEventMessage)
+      , mListenerType(aOther.mListenerType)
+      , mListenerIsHandler(aOther.mListenerIsHandler)
+      , mHandlerIsString(aOther.mHandlerIsString)
+      , mAllEvents(aOther.mAllEvents)
+      , mIsChrome(aOther.mIsChrome)
+    {
+      aOther.mTypeString.Truncate();
+      aOther.mEventMessage = eVoidEvent;
+      aOther.mListenerType = eNoListener;
+      aOther.mListenerIsHandler = false;
+      aOther.mHandlerIsString = false;
+      aOther.mAllEvents = false;
+      aOther.mIsChrome = false;
     }
 
     ~Listener()
     {
       if ((mListenerType == eJSEventListener) && mListener) {
         static_cast<JSEventHandler*>(
           mListener.GetXPCOMCallback())->Disconnect();
       }
@@ -240,40 +267,38 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)
 
   void AddEventListener(const nsAString& aType,
                         nsIDOMEventListener* aListener,
                         bool aUseCapture,
                         bool aWantsUntrusted)
   {
-    EventListenerHolder holder(aListener);
-    AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
+    AddEventListener(aType, EventListenerHolder(aListener),
+                     aUseCapture, aWantsUntrusted);
   }
   void AddEventListener(const nsAString& aType,
                         dom::EventListener* aListener,
                         const dom::AddEventListenerOptionsOrBoolean& aOptions,
                         bool aWantsUntrusted)
   {
-    EventListenerHolder holder(aListener);
-    AddEventListener(aType, holder, aOptions, aWantsUntrusted);
+    AddEventListener(aType, EventListenerHolder(aListener),
+                     aOptions, aWantsUntrusted);
   }
   void RemoveEventListener(const nsAString& aType,
                            nsIDOMEventListener* aListener,
                            bool aUseCapture)
   {
-    EventListenerHolder holder(aListener);
-    RemoveEventListener(aType, holder, aUseCapture);
+    RemoveEventListener(aType, EventListenerHolder(aListener), aUseCapture);
   }
   void RemoveEventListener(const nsAString& aType,
                            dom::EventListener* aListener,
                            const dom::EventListenerOptionsOrBoolean& aOptions)
   {
-    EventListenerHolder holder(aListener);
-    RemoveEventListener(aType, holder, aOptions);
+    RemoveEventListener(aType, EventListenerHolder(aListener), aOptions);
   }
 
   void AddListenerForAllEvents(nsIDOMEventListener* aListener,
                                bool aUseCapture,
                                bool aWantsUntrusted,
                                bool aSystemEventGroup);
   void RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
                                   bool aUseCapture,
@@ -282,30 +307,28 @@ public:
   /**
   * Sets events listeners of all types. 
   * @param an event listener
   */
   void AddEventListenerByType(nsIDOMEventListener *aListener,
                               const nsAString& type,
                               const EventListenerFlags& aFlags)
   {
-    EventListenerHolder holder(aListener);
-    AddEventListenerByType(holder, type, aFlags);
+    AddEventListenerByType(EventListenerHolder(aListener), type, aFlags);
   }
-  void AddEventListenerByType(const EventListenerHolder& aListener,
+  void AddEventListenerByType(EventListenerHolder aListener,
                               const nsAString& type,
                               const EventListenerFlags& aFlags);
   void RemoveEventListenerByType(nsIDOMEventListener *aListener,
                                  const nsAString& type,
                                  const EventListenerFlags& aFlags)
   {
-    EventListenerHolder holder(aListener);
-    RemoveEventListenerByType(holder, type, aFlags);
+    RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags);
   }
-  void RemoveEventListenerByType(const EventListenerHolder& aListener,
+  void RemoveEventListenerByType(EventListenerHolder aListener,
                                  const nsAString& type,
                                  const EventListenerFlags& aFlags);
 
   /**
    * Sets the current "inline" event listener for aName to be a
    * function compiled from aFunc if !aDeferCompilation.  If
    * aDeferCompilation, then we assume that we can get the string from
    * mTarget later and compile lazily.
@@ -549,44 +572,45 @@ protected:
   /**
    * Helper method for implementing the various Get*EventHandler above.  Will
    * return null if we don't have an event handler for this event name.
    */
   const TypedEventHandler* GetTypedEventHandler(nsIAtom* aEventName,
                                                 const nsAString& aTypeString);
 
   void AddEventListener(const nsAString& aType,
-                        const EventListenerHolder& aListener,
+                        EventListenerHolder aListener,
                         const dom::AddEventListenerOptionsOrBoolean& aOptions,
                         bool aWantsUntrusted);
   void AddEventListener(const nsAString& aType,
-                        const EventListenerHolder& aListener,
+                        EventListenerHolder aListener,
                         bool aUseCapture,
                         bool aWantsUntrusted);
   void RemoveEventListener(const nsAString& aType,
-                           const EventListenerHolder& aListener,
+                           EventListenerHolder aListener,
                            const dom::EventListenerOptionsOrBoolean& aOptions);
   void RemoveEventListener(const nsAString& aType,
-                           const EventListenerHolder& aListener,
+                           EventListenerHolder aListener,
                            bool aUseCapture);
 
-  void AddEventListenerInternal(const EventListenerHolder& aListener,
+  void AddEventListenerInternal(EventListenerHolder aListener,
                                 EventMessage aEventMessage,
                                 nsIAtom* aTypeAtom,
                                 const nsAString& aTypeString,
                                 const EventListenerFlags& aFlags,
                                 bool aHandler = false,
                                 bool aAllEvents = false);
-  void RemoveEventListenerInternal(const EventListenerHolder& aListener,
+  void RemoveEventListenerInternal(EventListenerHolder aListener,
                                    EventMessage aEventMessage,
                                    nsIAtom* aUserType,
                                    const nsAString& aTypeString,
                                    const EventListenerFlags& aFlags,
                                    bool aAllEvents = false);
   void RemoveAllListeners();
+  void NotifyEventListenerRemoved(nsIAtom* aUserType);
   const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
   const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);
   nsPIDOMWindowInner* GetInnerWindowForTarget();
   already_AddRefed<nsPIDOMWindowInner> GetTargetAsInnerWindow() const;
 
   bool ListenerCanHandle(const Listener* aListener,
                          const WidgetEvent* aEvent,
                          EventMessage aEventMessage) const;
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -318,20 +318,28 @@ EVENT(mozfullscreenchange,
       eMozFullscreenChange,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozfullscreenerror,
       eMozFullscreenError,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozpointerlockchange,
+      eMozPointerLockChange,
+      EventNameType_HTML,
+      eBasicEventClass)
+EVENT(mozpointerlockerror,
+      eMozPointerLockError,
+      EventNameType_HTML,
+      eBasicEventClass)
+EVENT(pointerlockchange,
       ePointerLockChange,
       EventNameType_HTML,
       eBasicEventClass)
-EVENT(mozpointerlockerror,
+EVENT(pointerlockerror,
       ePointerLockError,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(pointerdown,
       ePointerDown,
       EventNameType_All,
       ePointerEventClass)
 EVENT(pointermove,
--- a/dom/events/test/test_dom_mouse_event.html
+++ b/dom/events/test/test_dom_mouse_event.html
@@ -104,18 +104,16 @@ function testInitializingUntrustedEvent(
         continue;
       }
       is(e[attr], kTest[attr], description + attr + " returns wrong value");
     }
     is(e.isTrusted, false, description + "isTrusted returns wrong value");
     is(e.buttons, 0, description + "buttons returns wrong value");
     is(e.movementX, 0, description + "movementX returns wrong value");
     is(e.movementY, 0, description + "movementY returns wrong value");
-    is(e.movementX, e.mozMovementX);
-    is(e.movementY, e.mozMovementY);
 
     // getModifierState() tests
     is(e.getModifierState("Shift"), kTest.shiftKey,
        description + "getModifierState(\"Shift\") returns wrong value");
     is(e.getModifierState("Control"), kTest.ctrlKey,
        description + "getModifierState(\"Control\") returns wrong value");
     is(e.getModifierState("Alt"), kTest.altKey,
        description + "getModifierState(\"Alt\") returns wrong value");
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -78,18 +78,18 @@ class nsGeolocationRequest final
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSIGEOLOCATIONUPDATE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
 
   nsGeolocationRequest(Geolocation* aLocator,
-                       const GeoPositionCallback& aCallback,
-                       const GeoPositionErrorCallback& aErrorCallback,
+                       GeoPositionCallback aCallback,
+                       GeoPositionErrorCallback aErrorCallback,
                        PositionOptions* aOptions,
                        uint8_t aProtocolType,
                        bool aWatchPositionRequest = false,
                        int32_t aWatchId = 0);
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
 
   void Shutdown();
@@ -342,25 +342,25 @@ PositionError::NotifyCallback(const GeoP
     }
   }
 }
 ////////////////////////////////////////////////////
 // nsGeolocationRequest
 ////////////////////////////////////////////////////
 
 nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
-                                           const GeoPositionCallback& aCallback,
-                                           const GeoPositionErrorCallback& aErrorCallback,
+                                           GeoPositionCallback aCallback,
+                                           GeoPositionErrorCallback aErrorCallback,
                                            PositionOptions* aOptions,
                                            uint8_t aProtocolType,
                                            bool aWatchPositionRequest,
                                            int32_t aWatchId)
   : mIsWatchPositionRequest(aWatchPositionRequest),
-    mCallback(aCallback),
-    mErrorCallback(aErrorCallback),
+    mCallback(Move(aCallback)),
+    mErrorCallback(Move(aErrorCallback)),
     mOptions(aOptions),
     mLocator(aLocator),
     mWatchId(aWatchId),
     mShutdown(false),
     mProtocolType(aProtocolType)
 {
   if (nsCOMPtr<nsPIDOMWindowInner> win =
       do_QueryReferent(mLocator->GetOwner())) {
@@ -1385,57 +1385,53 @@ Geolocation::ClearPendingRequest(nsGeolo
 }
 
 void
 Geolocation::GetCurrentPosition(PositionCallback& aCallback,
                                 PositionErrorCallback* aErrorCallback,
                                 const PositionOptions& aOptions,
                                 ErrorResult& aRv)
 {
-  GeoPositionCallback successCallback(&aCallback);
-  GeoPositionErrorCallback errorCallback(aErrorCallback);
-
-  nsresult rv = GetCurrentPosition(successCallback, errorCallback,
+  nsresult rv = GetCurrentPosition(GeoPositionCallback(&aCallback),
+                                   GeoPositionErrorCallback(aErrorCallback),
                                    CreatePositionOptionsCopy(aOptions));
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 
   return;
 }
 
 NS_IMETHODIMP
 Geolocation::GetCurrentPosition(nsIDOMGeoPositionCallback* aCallback,
                                 nsIDOMGeoPositionErrorCallback* aErrorCallback,
                                 PositionOptions* aOptions)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
 
-  GeoPositionCallback successCallback(aCallback);
-  GeoPositionErrorCallback errorCallback(aErrorCallback);
-
-  return GetCurrentPosition(successCallback, errorCallback, aOptions);
+  return GetCurrentPosition(GeoPositionCallback(aCallback),
+                            GeoPositionErrorCallback(aErrorCallback), aOptions);
 }
 
 nsresult
-Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
-                                GeoPositionErrorCallback& errorCallback,
+Geolocation::GetCurrentPosition(GeoPositionCallback callback,
+                                GeoPositionErrorCallback errorCallback,
                                 PositionOptions *options)
 {
   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Count the number of requests per protocol/scheme.
   Telemetry::Accumulate(Telemetry::GEOLOCATION_GETCURRENTPOSITION_SECURE_ORIGIN,
                         static_cast<uint8_t>(mProtocolType));
 
   RefPtr<nsGeolocationRequest> request =
-    new nsGeolocationRequest(this, callback, errorCallback, options,
+    new nsGeolocationRequest(this, Move(callback), Move(errorCallback), options,
                              static_cast<uint8_t>(mProtocolType), false);
 
   if (!sGeoEnabled) {
     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
@@ -1474,20 +1470,18 @@ Geolocation::GetCurrentPositionReady(nsG
 
 int32_t
 Geolocation::WatchPosition(PositionCallback& aCallback,
                            PositionErrorCallback* aErrorCallback,
                            const PositionOptions& aOptions,
                            ErrorResult& aRv)
 {
   int32_t ret = 0;
-  GeoPositionCallback successCallback(&aCallback);
-  GeoPositionErrorCallback errorCallback(aErrorCallback);
-
-  nsresult rv = WatchPosition(successCallback, errorCallback,
+  nsresult rv = WatchPosition(GeoPositionCallback(&aCallback),
+                              GeoPositionErrorCallback(aErrorCallback),
                               CreatePositionOptionsCopy(aOptions), &ret);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 
   return ret;
 }
@@ -1495,42 +1489,42 @@ Geolocation::WatchPosition(PositionCallb
 NS_IMETHODIMP
 Geolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
                            nsIDOMGeoPositionErrorCallback *aErrorCallback,
                            PositionOptions *aOptions,
                            int32_t* aRv)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
 
-  GeoPositionCallback successCallback(aCallback);
-  GeoPositionErrorCallback errorCallback(aErrorCallback);
-
-  return WatchPosition(successCallback, errorCallback, aOptions, aRv);
+  return WatchPosition(GeoPositionCallback(aCallback),
+                       GeoPositionErrorCallback(aErrorCallback),
+                       aOptions, aRv);
 }
 
 nsresult
-Geolocation::WatchPosition(GeoPositionCallback& aCallback,
-                           GeoPositionErrorCallback& aErrorCallback,
+Geolocation::WatchPosition(GeoPositionCallback aCallback,
+                           GeoPositionErrorCallback aErrorCallback,
                            PositionOptions* aOptions,
                            int32_t* aRv)
 {
   if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Count the number of requests per protocol/scheme.
   Telemetry::Accumulate(Telemetry::GEOLOCATION_WATCHPOSITION_SECURE_ORIGIN,
                         static_cast<uint8_t>(mProtocolType));
 
   // The watch ID:
   *aRv = mLastWatchId++;
 
   RefPtr<nsGeolocationRequest> request =
-    new nsGeolocationRequest(this, aCallback, aErrorCallback, aOptions,
-                             static_cast<uint8_t>(mProtocolType), true, *aRv);
+    new nsGeolocationRequest(this, Move(aCallback), Move(aErrorCallback),
+                             aOptions, static_cast<uint8_t>(mProtocolType),
+                             true, *aRv);
 
   if (!sGeoEnabled) {
     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
   if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -184,18 +184,22 @@ public:
 
   // Notification from the service:
   void ServiceReady();
 
 private:
 
   ~Geolocation();
 
-  nsresult GetCurrentPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, PositionOptions* aOptions);
-  nsresult WatchPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, PositionOptions* aOptions, int32_t* aRv);
+  nsresult GetCurrentPosition(GeoPositionCallback aCallback,
+                              GeoPositionErrorCallback aErrorCallback,
+                              PositionOptions* aOptions);
+  nsresult WatchPosition(GeoPositionCallback aCallback,
+                         GeoPositionErrorCallback aErrorCallback,
+                         PositionOptions* aOptions, int32_t* aRv);
 
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
   // Methods for the service when it's ready to process requests:
   nsresult GetCurrentPositionReady(nsGeolocationRequest* aRequest);
   nsresult WatchPositionReady(nsGeolocationRequest* aRequest);
 
   // Check if clearWatch is already called
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -411,30 +411,30 @@ void
 HTMLMenuItemElement::WalkRadioGroup(Visitor* aVisitor)
 {
   nsIContent* parent = GetParent();
   if (!parent) {
     aVisitor->Visit(this);
     return;
   }
 
-  nsAttrInfo info1(GetAttrInfo(kNameSpaceID_None,
+  BorrowedAttrInfo info1(GetAttrInfo(kNameSpaceID_None,
                                nsGkAtoms::radiogroup));
   bool info1Empty = !info1.mValue || info1.mValue->IsEmptyString();
 
   for (nsIContent* cur = parent->GetFirstChild();
        cur;
        cur = cur->GetNextSibling()) {
     HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromContent(cur);
 
     if (!menuitem || menuitem->GetType() != CMD_TYPE_RADIO) {
       continue;
     }
 
-    nsAttrInfo info2(menuitem->GetAttrInfo(kNameSpaceID_None,
+    BorrowedAttrInfo info2(menuitem->GetAttrInfo(kNameSpaceID_None,
                                            nsGkAtoms::radiogroup));
     bool info2Empty = !info2.mValue || info2.mValue->IsEmptyString();
 
     if (info1Empty != info2Empty ||
         (info1.mValue && info2.mValue && !info1.mValue->Equals(*info2.mValue))) {
       continue;
     }
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -2230,18 +2230,16 @@ nsHTMLDocument::NamedGetter(JSContext* c
   nsISupports* supp = ResolveName(aName, &cache);
   if (!supp) {
     aFound = false;
     aRetval.set(nullptr);
     return;
   }
 
   JS::Rooted<JS::Value> val(cx);
-  // XXXbz Should we call the (slightly misnamed, really) WrapNativeParent
-  // here?
   if (!dom::WrapObject(cx, supp, cache, nullptr, &val)) {
     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
   aFound = true;
   aRetval.set(&val.toObject());
 }
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -362,16 +362,17 @@ IDBRequest::SetResultCallback(ResultCall
 
   AutoJSAPI autoJS;
   Maybe<JSAutoCompartment> ac;
 
   if (GetScriptOwner()) {
     // If we have a script owner we want the SafeJSContext and then to enter the
     // script owner's compartment.
     autoJS.Init();
+    JS::ExposeObjectToActiveJS(GetScriptOwner());
     ac.emplace(autoJS.cx(), GetScriptOwner());
   } else {
     // Otherwise our owner is a window and we use that to initialize.
     MOZ_ASSERT(GetOwner());
     if (!autoJS.Init(GetOwner())) {
       IDB_WARNING("Failed to initialize AutoJSAPI!");
       SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1084,18 +1084,16 @@ TabChild::GetDimensions(uint32_t aFlags,
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::SetFocus()
 {
-  NS_WARNING("TabChild::SetFocus not supported in TabChild");
-
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TabChild::GetVisibility(bool* aVisibility)
 {
   *aVisibility = true;
   return NS_OK;
@@ -1130,18 +1128,16 @@ TabChild::GetSiteWindow(void** aSiteWind
   NS_WARNING("TabChild::GetSiteWindow not supported in TabChild");
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TabChild::Blur()
 {
-  NS_WARNING("TabChild::Blur not supported in TabChild");
-
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TabChild::FocusNextElement(bool aForDocumentNavigation)
 {
   SendMoveFocus(true, aForDocumentNavigation);
   return NS_OK;
@@ -1334,17 +1330,17 @@ TabChild::RecvLoadURL(const nsCString& a
     ApplyShowInfo(aInfo);
 
     SetProcessNameToAppName();
   }
 
   nsresult rv =
     WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(),
                              nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-                             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER,
+                             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL,
                              nullptr, nullptr, nullptr);
   if (NS_FAILED(rv)) {
       NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
   }
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
 #endif
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -289,23 +289,36 @@ ThreadedDriver::Stop()
     mThread->Shutdown();
     mThread = nullptr;
   }
 }
 
 SystemClockDriver::SystemClockDriver(MediaStreamGraphImpl* aGraphImpl)
   : ThreadedDriver(aGraphImpl),
     mInitialTimeStamp(TimeStamp::Now()),
-    mLastTimeStamp(TimeStamp::Now())
+    mLastTimeStamp(TimeStamp::Now()),
+    mIsFallback(false)
 {}
 
 SystemClockDriver::~SystemClockDriver()
 { }
 
 void
+SystemClockDriver::MarkAsFallback()
+{
+  mIsFallback = true;
+}
+
+bool
+SystemClockDriver::IsFallback()
+{
+  return mIsFallback;
+}
+
+void
 ThreadedDriver::RunThread()
 {
   AutoProfilerUnregisterThread autoUnregister;
 
   bool stillProcessing = true;
   while (stillProcessing) {
     mIterationStart = IterationEnd();
     mIterationEnd += GetIntervalForIteration();
@@ -540,16 +553,17 @@ AudioCallbackDriver::AudioCallbackDriver
   , mInputChannels(1)
   , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
   , mStarted(false)
   , mAudioInput(nullptr)
   , mAudioChannel(aGraphImpl->AudioChannel())
   , mAddedMixer(false)
   , mInCallback(false)
   , mMicrophoneActive(false)
+  , mFromFallback(false)
 {
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
 }
 
 AudioCallbackDriver::~AudioCallbackDriver()
 {
   MOZ_ASSERT(mPromisesForOperation.IsEmpty());
 }
@@ -631,23 +645,30 @@ AudioCallbackDriver::Init()
       NS_WARN_IF_FALSE(rv == CUBEB_OK,
           "Could not set the audio stream volume in GraphDriver.cpp");
       CubebUtils::ReportCubebBackendUsed();
     } else {
 #ifdef MOZ_WEBRTC
       StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
 #endif
       NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
-      CubebUtils::ReportCubebStreamInitFailure(firstStream);
+      // Only report failures when we're not coming from a driver that was
+      // created itself as a fallback driver because of a previous audio driver
+      // failure.
+      if (!mFromFallback) {
+        CubebUtils::ReportCubebStreamInitFailure(firstStream);
+      }
       // Fall back to a driver using a normal thread.
       MonitorAutoLock lock(GraphImpl()->GetMonitor());
-      SetNextDriver(new SystemClockDriver(GraphImpl()));
-      NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
-      mGraphImpl->SetCurrentDriver(NextDriver());
-      NextDriver()->Start();
+      SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
+      SetNextDriver(nextDriver);
+      nextDriver->MarkAsFallback();
+      nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
+      mGraphImpl->SetCurrentDriver(nextDriver);
+      nextDriver->Start();
       return;
     }
   }
   bool aec;
   Unused << mGraphImpl->AudioTrackPresent(aec);
   SetMicrophoneActive(aec);
 
   cubeb_stream_register_device_changed_callback(mAudioStream,
@@ -684,16 +705,18 @@ AudioCallbackDriver::Start()
       LIFECYCLE_LOG("Releasing audio driver off main thread.");
       RefPtr<AsyncCubebTask> releaseEvent =
         new AsyncCubebTask(mPreviousDriver->AsAudioCallbackDriver(),
                            AsyncCubebOperation::SHUTDOWN);
       releaseEvent->Dispatch();
       mPreviousDriver = nullptr;
     } else {
       LIFECYCLE_LOG("Dropping driver reference for SystemClockDriver.");
+      MOZ_ASSERT(mPreviousDriver->AsSystemClockDriver());
+      mFromFallback = mPreviousDriver->AsSystemClockDriver()->IsFallback();
       mPreviousDriver = nullptr;
     }
   }
 
   LIFECYCLE_LOG("Starting new audio driver off main thread, "
                 "to ensure it runs after previous shutdown.");
   RefPtr<AsyncCubebTask> initEvent =
     new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -49,16 +49,17 @@ static const int SCHEDULE_SAFETY_MARGIN_
  */
 static const int AUDIO_TARGET_MS = 2*MEDIA_GRAPH_TARGET_PERIOD_MS +
     SCHEDULE_SAFETY_MARGIN_MS;
 
 class MediaStreamGraphImpl;
 
 class AudioCallbackDriver;
 class OfflineClockDriver;
+class SystemClockDriver;
 
 /**
  * A driver is responsible for the scheduling of the processing, the thread
  * management, and give the different clocks to a MediaStreamGraph. This is an
  * abstract base class. A MediaStreamGraph can be driven by an
  * OfflineClockDriver, if the graph is offline, or a SystemClockDriver, if the
  * graph is real time.
  * A MediaStreamGraph holds an owning reference to its driver.
@@ -160,16 +161,20 @@ public:
   virtual AudioCallbackDriver* AsAudioCallbackDriver() {
     return nullptr;
   }
 
   virtual OfflineClockDriver* AsOfflineClockDriver() {
     return nullptr;
   }
 
+  virtual SystemClockDriver* AsSystemClockDriver() {
+    return nullptr;
+  }
+
   /**
    * Tell the driver it has to stop and return the current time of the graph, so
    * another driver can start from the right point in time.
    */
   virtual void SwitchAtNextIteration(GraphDriver* aDriver);
 
   /**
    * Set the time for a graph, on a driver. This is used so a new driver just
@@ -291,23 +296,30 @@ protected:
 class SystemClockDriver : public ThreadedDriver
 {
 public:
   explicit SystemClockDriver(MediaStreamGraphImpl* aGraphImpl);
   virtual ~SystemClockDriver();
   MediaTime GetIntervalForIteration() override;
   void WaitForNextIteration() override;
   void WakeUp() override;
-
+  void MarkAsFallback();
+  bool IsFallback();
+  SystemClockDriver* AsSystemClockDriver() override {
+    return this;
+  }
 
 private:
   // Those are only modified (after initialization) on the graph thread. The
   // graph thread does not run during the initialization.
   TimeStamp mInitialTimeStamp;
   TimeStamp mLastTimeStamp;
+  // This is true if this SystemClockDriver runs the graph because we could not
+  // open an audio stream.
+  bool mIsFallback;
 };
 
 /**
  * An OfflineClockDriver runs the graph as fast as possible, without waiting
  * between iteration.
  */
 class OfflineClockDriver : public ThreadedDriver
 {
@@ -520,16 +532,19 @@ private:
 
   /* This is atomic and is set by the audio callback thread. It can be read by
    * any thread safely. */
   Atomic<bool> mInCallback;
   /**
    * True if microphone is being used by this process. This is synchronized by
    * the graph's monitor. */
   bool mMicrophoneActive;
+  /* True if this driver was created from a driver created because of a previous
+   * AudioCallbackDriver failure. */
+  bool mFromFallback;
 };
 
 class AsyncCubebTask : public Runnable
 {
 public:
 
   AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation);
 
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -130,28 +130,28 @@ CopyArrayBufferViewOrArrayBufferData(con
     return;
   }
   aOutData.AppendElements(data.mData, data.mLength);
 }
 
 nsString
 KeySystemToGMPName(const nsAString& aKeySystem)
 {
-  if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
+  if (aKeySystem.EqualsASCII(kEMEKeySystemPrimetime)) {
     return NS_LITERAL_STRING("gmp-eme-adobe");
   }
-  if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
+  if (aKeySystem.EqualsASCII(kEMEKeySystemClearkey)) {
     return NS_LITERAL_STRING("gmp-clearkey");
   }
-  if (aKeySystem.EqualsLiteral("com.widevine.alpha")) {
+  if (aKeySystem.EqualsASCII(kEMEKeySystemWidevine)) {
     return NS_LITERAL_STRING("gmp-widevinecdm");
   }
   MOZ_ASSERT(false, "We should only call this for known GMPs");
   return EmptyString();
 }
 
 bool
 IsClearkeyKeySystem(const nsAString& aKeySystem)
 {
-  return aKeySystem.EqualsLiteral("org.w3.clearkey");
+  return aKeySystem.EqualsASCII(kEMEKeySystemClearkey);
 }
 
 } // namespace mozilla
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -8,16 +8,20 @@
 #define EME_LOG_H_
 
 #include "mozilla/Logging.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 
+static const char* const kEMEKeySystemClearkey = "org.w3.clearkey";
+static const char* const kEMEKeySystemWidevine = "com.widevine.alpha";
+static const char* const kEMEKeySystemPrimetime = "com.adobe.primetime";
+
 namespace dom {
 class ArrayBufferViewOrArrayBuffer;
 }
 
 #ifndef EME_LOG
   LogModule* GetEMELog();
   #define EME_LOG(...) MOZ_LOG(GetEMELog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
   #define EME_LOG_ENABLED() MOZ_LOG_TEST(GetEMELog(), mozilla::LogLevel::Debug)
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -186,17 +186,17 @@ MediaKeySystemAccess::IsGMPPresentOnDisk
                                                    &result, &message);
     aOutMessage = message;
     return ok && result;
   }
 
   bool isPresent = true;
 
 #if XP_WIN
-  if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
+  if (aKeySystem.EqualsASCII(kEMEKeySystemPrimetime)) {
     if (!AdobePluginDLLExists(aVersion)) {
       NS_WARNING("Adobe EME plugin disappeared from disk!");
       aOutMessage = NS_LITERAL_CSTRING("Adobe DLL was expected to be on disk but was not");
       isPresent = false;
     }
     if (!AdobePluginVoucherExists(aVersion)) {
       NS_WARNING("Adobe EME voucher disappeared from disk!");
       aOutMessage = NS_LITERAL_CSTRING("Adobe plugin voucher was expected to be on disk but was not");
@@ -271,39 +271,39 @@ MediaKeySystemAccess::GetKeySystemStatus
   MOZ_ASSERT(MediaPrefs::EMEEnabled() || IsClearkeyKeySystem(aKeySystem));
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (NS_WARN_IF(!mps)) {
     aOutMessage = NS_LITERAL_CSTRING("Failed to get GMP service");
     return MediaKeySystemStatus::Error;
   }
 
-  if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
+  if (aKeySystem.EqualsASCII(kEMEKeySystemClearkey)) {
     return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
   }
 
   if (Preferences::GetBool("media.gmp-eme-adobe.visible", false)) {
-    if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
+    if (aKeySystem.EqualsASCII(kEMEKeySystemPrimetime)) {
       if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
         aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
         return MediaKeySystemStatus::Cdm_disabled;
       }
 #ifdef XP_WIN
       // Win Vista and later only.
       if (!IsVistaOrLater()) {
         aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Adobe EME");
         return MediaKeySystemStatus::Cdm_not_supported;
       }
 #endif
       return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
     }
   }
 
   if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
-    if (aKeySystem.EqualsLiteral("com.widevine.alpha")) {
+    if (aKeySystem.EqualsASCII(kEMEKeySystemWidevine)) {
 #ifdef XP_WIN
       // Win Vista and later only.
       if (!IsVistaOrLater()) {
         aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Widevine EME");
         return MediaKeySystemStatus::Cdm_not_supported;
       }
 #endif
       if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
@@ -421,17 +421,17 @@ static const nsTArray<KeySystemConfig>&
 GetSupportedKeySystems()
 {
   if (!sKeySystemConfigs) {
     sKeySystemConfigs = new nsTArray<KeySystemConfig>();
     ClearOnShutdown(&sKeySystemConfigs);
 
     {
       KeySystemConfig clearkey;
-      clearkey.mKeySystem = NS_LITERAL_STRING("org.w3.clearkey");
+      clearkey.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemClearkey);
       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
       clearkey.mPersistentState = KeySystemFeatureSupport::Requestable;
       clearkey.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
       clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
       clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license);
 #if defined(XP_WIN)
@@ -453,17 +453,17 @@ GetSupportedKeySystems()
       clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS);
       clearkey.mWebM.SetCanDecrypt(GMP_CODEC_OPUS);
       clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VP8);
       clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VP9);
       sKeySystemConfigs->AppendElement(Move(clearkey));
     }
     {
       KeySystemConfig widevine;
-      widevine.mKeySystem = NS_LITERAL_STRING("com.widevine.alpha");
+      widevine.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemWidevine);
       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
       widevine.mPersistentState = KeySystemFeatureSupport::Requestable;
       widevine.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
       widevine.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
       widevine.mAudioRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO"));
       widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_DECODE"));
@@ -484,17 +484,17 @@ GetSupportedKeySystems()
       //widevine.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS);
       //widevine.mWebM.SetCanDecrypt(GMP_CODEC_OPUS);
       //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP8);
       //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP9);
       sKeySystemConfigs->AppendElement(Move(widevine));
     }
     {
       KeySystemConfig primetime;
-      primetime.mKeySystem = NS_LITERAL_STRING("com.adobe.primetime");
+      primetime.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemPrimetime);
       primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
       primetime.mPersistentState = KeySystemFeatureSupport::Required;
       primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required;
       primetime.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
       primetime.mMP4.SetCanDecryptAndDecode(GMP_CODEC_AAC);
       primetime.mMP4.SetCanDecryptAndDecode(GMP_CODEC_H264);
       sKeySystemConfigs->AppendElement(Move(primetime));
     }
@@ -559,17 +559,17 @@ CanDecryptAndDecode(mozIGeckoMediaPlugin
 
 #if defined(XP_WIN)
     // Widevine CDM doesn't include an AAC decoder. So if WMF can't
     // decode AAC, and a codec wasn't specified, be conservative
     // and reject the MediaKeys request, since our policy is to prevent
     //  the Adobe GMP's unencrypted AAC decoding path being used to
     // decode content decrypted by the Widevine CDM.
     if (codec == GMP_CODEC_AAC &&
-        aKeySystem.EqualsLiteral("com.widevine.alpha") &&
+        aKeySystem.EqualsASCII(kEMEKeySystemWidevine) &&
         !WMFDecoderModule::HasAAC()) {
       if (aDiagnostics) {
         aDiagnostics->SetKeySystemIssue(
           DecoderDoctorDiagnostics::eWidevineWithNoWMF);
       }
     }
 #endif
     return false;
@@ -1126,17 +1126,17 @@ GetSupportedConfig(mozIGeckoMediaPluginS
     }
   }
 
   // Note: Omitting steps 20-22. We don't ask for consent.
 
 #if defined(XP_WIN)
   // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC,
   // and a codec wasn't specified, be conservative and reject the MediaKeys request.
-  if (aKeySystem.mKeySystem.EqualsLiteral("com.widevine.alpha") &&
+  if (aKeySystem.mKeySystem.EqualsASCII(kEMEKeySystemWidevine) &&
       (aCandidate.mAudioCapabilities.IsEmpty() ||
        aCandidate.mVideoCapabilities.IsEmpty()) &&
      !WMFDecoderModule::HasAAC()) {
     if (aDiagnostics) {
       aDiagnostics->SetKeySystemIssue(
         DecoderDoctorDiagnostics::eWidevineWithNoWMF);
     }
     EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -137,18 +137,18 @@ MediaKeySystemAccessManager::Request(Det
                       minCdmVersion,
                       MediaKeySystemStatusValues::strings[(size_t)status].value,
                       cdmVersion.get(),
                       message.get());
   LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg));
 
   if ((status == MediaKeySystemStatus::Cdm_not_installed ||
        status == MediaKeySystemStatus::Cdm_insufficient_version) &&
-      (keySystem.EqualsLiteral("com.adobe.primetime") ||
-       keySystem.EqualsLiteral("com.widevine.alpha"))) {
+      (keySystem.EqualsASCII(kEMEKeySystemPrimetime) ||
+       keySystem.EqualsASCII(kEMEKeySystemWidevine))) {
     // These are cases which could be resolved by downloading a new(er) CDM.
     // When we send the status to chrome, chrome's GMPProvider will attempt to
     // download or update the CDM. In AwaitInstall() we add listeners to wait
     // for the update to complete, and we'll call this function again with
     // aType==Subsequent once the download has completed and the GMPService
     // has had a new plugin added. AwaitInstall() sets a timer to fail if the
     // update/download takes too long or fails.
     if (aType == RequestType::Initial &&
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -575,17 +575,17 @@ GMPParent::SupportsAPI(const nsCString& 
     nsTArray<nsCString>& tags = mCapabilities[i].mAPITags;
     for (uint32_t j = 0; j < tags.Length(); j++) {
       if (tags[j].Equals(aTag)) {
 #ifdef XP_WIN
         // Clearkey on Windows advertises that it can decode in its GMP info
         // file, but uses Windows Media Foundation to decode. That's not present
         // on Windows XP, and on some Vista, Windows N, and KN variants without
         // certain services packs.
-        if (tags[j].EqualsLiteral("org.w3.clearkey")) {
+        if (tags[j].Equals(kEMEKeySystemClearkey)) {
           if (mCapabilities[i].mAPIName.EqualsLiteral(GMP_API_VIDEO_DECODER)) {
             if (!WMFDecoderModule::HasH264()) {
               continue;
             }
           } else if (mCapabilities[i].mAPIName.EqualsLiteral(GMP_API_AUDIO_DECODER)) {
             if (!WMFDecoderModule::HasAAC()) {
               continue;
             }
@@ -893,17 +893,17 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFil
                       mDisplayName.get());
         return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
       }
 #endif
 #ifdef XP_WIN
       // Adobe GMP doesn't work without SSE2. Check the tags to see if
       // the decryptor is for the Adobe GMP, and refuse to load it if
       // SSE2 isn't supported.
-      if (cap.mAPITags.Contains(NS_LITERAL_CSTRING("com.adobe.primetime")) &&
+      if (cap.mAPITags.Contains(nsCString(kEMEKeySystemPrimetime)) &&
           !mozilla::supports_sse2()) {
         return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
       }
 #endif // XP_WIN
     }
 
     mCapabilities.AppendElement(Move(cap));
   }
@@ -948,21 +948,21 @@ GMPParent::ParseChromiumManifest(nsStrin
   }
 
   mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
   mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
   mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
 
   GMPCapability video(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER));
   video.mAPITags.AppendElement(NS_LITERAL_CSTRING("h264"));
-  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("com.widevine.alpha"));
+  video.mAPITags.AppendElement(nsCString(kEMEKeySystemWidevine));
   mCapabilities.AppendElement(Move(video));
 
   GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
-  decrypt.mAPITags.AppendElement(NS_LITERAL_CSTRING("com.widevine.alpha"));
+  decrypt.mAPITags.AppendElement(nsCString(kEMEKeySystemWidevine));
   mCapabilities.AppendElement(Move(decrypt));
 
   MOZ_ASSERT(mName.EqualsLiteral("widevinecdm"));
   mAdapter = NS_LITERAL_STRING("widevine");
 #ifdef XP_WIN
   mLibs = NS_LITERAL_CSTRING("dxva2.dll");
 #endif
 
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -7,23 +7,23 @@
 #include "content_decryption_module.h"
 #include "WidevineDecryptor.h"
 #include "WidevineUtils.h"
 #include "WidevineVideoDecoder.h"
 #include "gmp-api/gmp-entrypoints.h"
 #include "gmp-api/gmp-decryption.h"
 #include "gmp-api/gmp-video-codec.h"
 #include "gmp-api/gmp-platform.h"
+#include "mozilla/EMEUtils.h"
 #include "mozilla/StaticPtr.h"
 
 static const GMPPlatformAPI* sPlatform = nullptr;
 
 namespace mozilla {
 
-const char* WidevineKeySystem = "com.widevine.alpha";
 StaticRefPtr<CDMWrapper> sCDMWrapper;
 
 GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
   return sPlatform->getcurrenttime(aOutTime);
 }
 
 // Call on main thread only.
 GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
@@ -105,18 +105,18 @@ WidevineAdapter::GMPGetAPI(const char* a
         aAPIName, aHostAPI, aPluginAPI, this);
       return GMPGenericErr;
     }
 
     WidevineDecryptor* decryptor = new WidevineDecryptor();
 
     auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
       create(cdm::ContentDecryptionModule::kVersion,
-             WidevineKeySystem,
-             strlen(WidevineKeySystem),
+             kEMEKeySystemWidevine,
+             strlen(kEMEKeySystemWidevine),
              &GetCdmHost,
              decryptor));
     if (!cdm) {
       Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p FAILED to create cdm",
           aAPIName, aHostAPI, aPluginAPI, this);
       return GMPGenericErr;
     }
     Log("cdm: 0x%x", cdm);
--- a/dom/media/gtest/TestVideoTrackEncoder.cpp
+++ b/dom/media/gtest/TestVideoTrackEncoder.cpp
@@ -245,19 +245,16 @@ TEST(VP8VideoTrackEncoder, FetchMetaData
 
     // METADATA should be depend on how to initiate encoder.
     EXPECT_TRUE(vp8Meta->mWidth == params[i].mWidth);
     EXPECT_TRUE(vp8Meta->mHeight == params[i].mHeight);
   }
 }
 
 // Encode test
-// XXX(bug 1018402): Disable this test when compiled with VS2013 because it
-// crashes.
-#if !defined(_MSC_VER) || _MSC_VER < 1800
 TEST(VP8VideoTrackEncoder, FrameEncode)
 {
   // Initiate VP8 encoder
   TestVP8TrackEncoder encoder;
   InitParam param = {true, 640, 480, 90000};
   encoder.TestInit(param);
 
   // Create YUV images as source.
@@ -280,17 +277,16 @@ TEST(VP8VideoTrackEncoder, FrameEncode)
 
   // track change notification.
   encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, 0, segment);
 
   // Pull Encoded Data back from encoder.
   EncodedFrameContainer container;
   EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 }
-#endif // _MSC_VER
 
 // EOS test
 TEST(VP8VideoTrackEncoder, EncodeComplete)
 {
   // Initiate VP8 encoder
   TestVP8TrackEncoder encoder;
   InitParam param = {true, 640, 480, 90000};
   encoder.TestInit(param);
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -7,16 +7,17 @@
 #include "GMPDecoderModule.h"
 #include "DecoderDoctorDiagnostics.h"
 #include "GMPAudioDecoder.h"
 #include "GMPVideoDecoder.h"
 #include "MediaDataDecoderProxy.h"
 #include "MediaPrefs.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/EMEUtils.h"
 #include "mozilla/StaticMutex.h"
 #include "gmp-audio-decode.h"
 #include "gmp-video-decode.h"
 #ifdef XP_WIN
 #include "WMFDecoderModule.h"
 #endif
 
 namespace mozilla {
@@ -98,17 +99,17 @@ GMPDecoderModule::DecoderNeedsConversion
 static bool
 HasGMPFor(const nsACString& aAPI,
           const nsACString& aCodec,
           const nsACString& aGMP)
 {
 #ifdef XP_WIN
   // gmp-clearkey uses WMF for decoding, so if we're using clearkey we must
   // verify that WMF works before continuing.
-  if (aGMP.EqualsLiteral("org.w3.clearkey")) {
+  if (aGMP.Equals(kEMEKeySystemClearkey)) {
     RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
     if (aCodec.EqualsLiteral("aac") &&
         !pdm->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"),
                                /* DecoderDoctorDiagnostics* */ nullptr)) {
       return false;
     }
     if (aCodec.EqualsLiteral("h264") &&
         !pdm->SupportsMimeType(NS_LITERAL_CSTRING("video/avc"),
@@ -138,19 +139,19 @@ StaticMutex sGMPCodecsMutex;
 
 struct GMPCodecs {
   const char* mKeySystem;
   bool mHasAAC;
   bool mHasH264;
 };
 
 static GMPCodecs sGMPCodecs[] = {
-  { "org.w3.clearkey", false, false },
-  { "com.adobe.primetime", false, false },
-  { "com.widevine.alpha", false, false },
+  { kEMEKeySystemClearkey, false, false },
+  { kEMEKeySystemWidevine, false, false },
+  { kEMEKeySystemPrimetime, false, false },
 };
 
 void
 GMPDecoderModule::UpdateUsableCodecs()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   StaticMutexAutoLock lock(sGMPCodecsMutex);
@@ -177,27 +178,27 @@ GMPDecoderModule::Init()
 
 /* static */
 const Maybe<nsCString>
 GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
 {
   Maybe<nsCString> rv;
   if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
     switch (MediaPrefs::GMPAACPreferred()) {
-      case 1: rv.emplace(NS_LITERAL_CSTRING("org.w3.clearkey")); break;
-      case 2: rv.emplace(NS_LITERAL_CSTRING("com.adobe.primetime")); break;
+      case 1: rv.emplace(nsCString(kEMEKeySystemClearkey)); break;
+      case 2: rv.emplace(nsCString(kEMEKeySystemPrimetime)); break;
       default: break;
     }
   }
 
   if (aMimeType.EqualsLiteral("video/avc") ||
       aMimeType.EqualsLiteral("video/mp4")) {
     switch (MediaPrefs::GMPH264Preferred()) {
-      case 1: rv.emplace(NS_LITERAL_CSTRING("org.w3.clearkey")); break;
-      case 2: rv.emplace(NS_LITERAL_CSTRING("com.adobe.primetime")); break;
+      case 1: rv.emplace(nsCString(kEMEKeySystemClearkey)); break;
+      case 2: rv.emplace(nsCString(kEMEKeySystemPrimetime)); break;
       default: break;
     }
   }
 
   return rv;
 }
 
 /* static */
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -296,23 +296,27 @@ PresentationSessionInfo::Close(nsresult 
     case nsIPresentationSessionListener::STATE_CLOSED: {
       Shutdown(aReason);
       break;
     }
     case nsIPresentationSessionListener::STATE_TERMINATED: {
       if (!mControlChannel) {
         nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
         nsresult rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
-        if (NS_SUCCEEDED(rv)) {
-          SetControlChannel(ctrlChannel);
+        if (NS_FAILED(rv)) {
+          Shutdown(rv);
+          return rv;
         }
+
+        SetControlChannel(ctrlChannel);
         return rv;
       }
 
-      return mControlChannel->Terminate(mSessionId);
+      ContinueTermination();
+      return NS_OK;
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 PresentationSessionInfo::OnTerminate(nsIPresentationControlChannel* aControlChannel)
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
@@ -18,16 +18,17 @@ function debug(str) {
 
 const originalFactoryData = [];
 var sessionId; // Store the uuid generated by PresentationRequest.
 const address = Cc["@mozilla.org/supports-cstring;1"]
                   .createInstance(Ci.nsISupportsCString);
 address.data = "127.0.0.1";
 const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
 addresses.appendElement(address, false);
+var triggerControlChannelError = false; // For simulating error during control channel establishment.
 
 function mockChannelDescription(role) {
   this.QueryInterface = XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]);
   this.role = role;
   this.type = Ci.nsIPresentationChannelDescription.TYPE_TCP;
   this.tcpAddress = addresses;
   this.tcpPort = (role === 'sender' ? 1234 : 4321); // either sender or receiver
 }
@@ -257,16 +258,19 @@ const mockControlChannelOfReceiver = {
 };
 
 const mockDevice = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
   id:   'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
+    if (triggerControlChannelError) {
+      throw Cr.NS_ERROR_FAILURE;
+    }
     sendAsyncMessage('control-channel-established');
     return mockControlChannelOfSender;
   },
 };
 
 const mockDevicePrompt = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
                                          Ci.nsIFactory]),
@@ -392,16 +396,21 @@ function initMockAndListener() {
   });
 
   addMessageListener('trigger-control-channel-open', function(reason) {
     debug('Got message: trigger-control-channel-open');
     mockControlChannelOfSender.notifyConnected();
     mockControlChannelOfReceiver.notifyConnected();
   });
 
+  addMessageListener('trigger-control-channel-error', function(reason) {
+    debug('Got message: trigger-control-channel-open');
+    triggerControlChannelError = true;
+  });
+
   addMessageListener('trigger-on-offer', function() {
     debug('Got message: trigger-on-offer');
     mockControlChannelOfReceiver.onOffer(mockChannelDescriptionOfSender);
     mockServerSocket.onSocketAccepted(mockServerSocket, mockSocketTransport);
   });
 
   addMessageListener('trigger-on-answer', function() {
     debug('Got message: trigger-on-answer');
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/file_presentation_terminate_establish_connection_error.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <head>
+    <meta charset='utf-8'>
+    <title>Test for B2G PresentationReceiver at receiver side</title>
+  </head>
+  <body>
+    <div id='content'></div>
+<script type='application/javascript;version=1.7'>
+
+'use strict';
+
+function is(a, b, msg) {
+  if (a === b) {
+    alert('OK ' + msg);
+  } else {
+    alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
+  }
+}
+
+function ok(a, msg) {
+  alert((a ? 'OK ' : 'KO ') + msg);
+}
+
+function info(msg) {
+  alert('INFO ' + msg);
+}
+
+function command(name, data) {
+  alert('COMMAND ' + JSON.stringify({name: name, data: data}));
+}
+
+function finish() {
+  alert('DONE');
+}
+
+var connection;
+
+function testConnectionAvailable() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionAvailable ---');
+    ok(navigator.presentation, 'Receiver: navigator.presentation should be available.');
+    ok(navigator.presentation.receiver, 'Receiver: navigator.presentation.receiver should be available.');
+
+    navigator.presentation.receiver.connectionList
+    .then((aList) => {
+      is(aList.connections.length, 1, 'Should get one connection.');
+      connection = aList.connections[0];
+      ok(connection.id, 'Connection ID should be set: ' + connection.id);
+      is(connection.state, 'connected', 'Connection state at receiver side should be connected.');
+      aResolve();
+    })
+    .catch((aError) => {
+      ok(false, 'Receiver: Error occurred when getting the connection: ' + aError);
+      finish();
+      aReject();
+    });
+  });
+}
+
+function testConnectionReady() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionReady ---');
+    connection.onconnect = function() {
+      connection.onconnect = null;
+      ok(false, 'Should not get |onconnect| event.')
+      aReject();
+    };
+    if (connection.state === 'connected') {
+      connection.onconnect = null;
+      is(connection.state, 'connected', 'Receiver: Connection state should become connected.');
+      aResolve();
+    }
+  });
+}
+
+function testConnectionTerminate() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionTerminate ---');
+    connection.onterminate = function() {
+      connection.onterminate = null;
+      // Using window.alert at this stage will cause window.close() fail.
+      // Only trigger it if verdict fail.
+      if (connection.state !== 'terminated') {
+        is(connection.state, 'terminated', 'Receiver: Connection should be terminated.');
+      }
+      aResolve();
+    };
+
+    window.addEventListener('hashchange', function hashchangeHandler(evt) {
+      var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
+      if (message.type === 'ready-to-terminate') {
+        info('Receiver: --- ready-to-terminate ---');
+        connection.terminate();
+      }
+    });
+
+
+    command('forward-command', JSON.stringify({ name: 'prepare-for-terminate' }));
+  });
+}
+
+function runTests() {
+  testConnectionAvailable()
+  .then(testConnectionReady)
+  .then(testConnectionTerminate)
+}
+
+runTests();
+
+</script>
+  </body>
+</html>
--- a/dom/presentation/tests/mochitest/mochitest.ini
+++ b/dom/presentation/tests/mochitest/mochitest.ini
@@ -12,16 +12,18 @@ support-files =
   file_presentation_receiver_inner_iframe.html
   file_presentation_1ua_wentaway.html
   test_presentation_1ua_connection_wentaway.js
   file_presentation_receiver_auxiliary_navigation.html
   test_presentation_receiver_auxiliary_navigation.js
   file_presentation_sandboxed_presentation.html
   file_presentation_terminate.html
   test_presentation_terminate.js
+  file_presentation_terminate_establish_connection_error.html
+  test_presentation_terminate_establish_connection_error.js
 
 [test_presentation_dc_sender.html]
 [test_presentation_dc_receiver.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_dc_receiver_oop.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_1ua_sender_and_receiver.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
@@ -47,11 +49,15 @@ skip-if = (e10s || toolkit == 'gonk' || 
 [test_presentation_receiver_auxiliary_navigation_inproc.html]
 skip-if = (e10s || toolkit == 'gonk')
 [test_presentation_receiver_auxiliary_navigation_oop.html]
 skip-if = (e10s || toolkit == 'gonk')
 [test_presentation_terminate_inproc.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android')
 [test_presentation_terminate_oop.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android')
+[test_presentation_terminate_establish_connection_error_inproc.html]
+skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android')
+[test_presentation_terminate_establish_connection_error_oop.html]
+skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android')
 [test_presentation_sender_on_terminate_request.html]
 skip-if = toolkit == 'android'
 [test_presentation_sandboxed_presentation.html]
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
@@ -0,0 +1,189 @@
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
+
+function debug(str) {
+  // info(str);
+}
+
+var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
+var receiverUrl = SimpleTest.getTestFileURL('file_presentation_terminate_establish_connection_error.html');
+var request;
+var connection;
+var receiverIframe;
+
+function postMessageToIframe(aType) {
+  receiverIframe.src = receiverUrl + "#" +
+                       encodeURIComponent(JSON.stringify({ type: aType }));
+}
+
+function setup() {
+  gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+    debug('Got message: device-prompt');
+    gScript.removeMessageListener('device-prompt', devicePromptHandler);
+    gScript.sendAsyncMessage('trigger-device-prompt-select');
+  });
+
+  gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+    gScript.removeMessageListener('control-channel-established',
+                                  controlChannelEstablishedHandler);
+    gScript.sendAsyncMessage('trigger-control-channel-open');
+  });
+
+  gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
+    debug('Got message: sender-launch');
+    gScript.removeMessageListener('sender-launch', senderLaunchHandler);
+    is(url, receiverUrl, 'Receiver: should receive the same url');
+    receiverIframe = document.createElement('iframe');
+    receiverIframe.setAttribute('mozbrowser', 'true');
+    receiverIframe.setAttribute('mozpresentation', receiverUrl);
+    var oop = location.pathname.indexOf('_inproc') == -1;
+    receiverIframe.setAttribute('remote', oop);
+
+    receiverIframe.setAttribute('src', receiverUrl);
+    receiverIframe.addEventListener('mozbrowserloadend', function mozbrowserloadendHander() {
+      receiverIframe.removeEventListener('mozbrowserloadend', mozbrowserloadendHander);
+      info('Receiver loaded.');
+    });
+
+    // This event is triggered when the iframe calls 'alert'.
+    receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(evt) {
+      var message = evt.detail.message;
+      if (/^OK /.exec(message)) {
+        ok(true, message.replace(/^OK /, ''));
+      } else if (/^KO /.exec(message)) {
+        ok(false, message.replace(/^KO /, ''));
+      } else if (/^INFO /.exec(message)) {
+        info(message.replace(/^INFO /, ''));
+      } else if (/^COMMAND /.exec(message)) {
+        var command = JSON.parse(message.replace(/^COMMAND /, ''));
+        gScript.sendAsyncMessage(command.name, command.data);
+      } else if (/^DONE$/.exec(message)) {
+        ok(true, 'Messaging from iframe complete.');
+        receiverIframe.removeEventListener('mozbrowsershowmodalprompt',
+                                            receiverListener);
+      }
+    }, false);
+
+    var promise = new Promise(function(aResolve, aReject) {
+      document.body.appendChild(receiverIframe);
+      aResolve(receiverIframe);
+    });
+
+    var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
+                           .getService(SpecialPowers.Ci.nsIObserverService);
+    obs.notifyObservers(promise, 'setup-request-promise', null);
+  });
+
+  gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
+    debug('Got message: promise-setup-ready');
+    gScript.removeMessageListener('promise-setup-ready',
+                                  promiseSetupReadyHandler);
+    gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
+  });
+
+  gScript.addMessageListener('offer-sent', function offerSentHandler() {
+    debug('Got message: offer-sent');
+    gScript.removeMessageListener('offer-sent', offerSentHandler);
+    gScript.sendAsyncMessage('trigger-on-offer');
+  });
+
+  gScript.addMessageListener('answer-sent', function answerSentHandler() {
+    debug('Got message: answer-sent');
+    gScript.removeMessageListener('answer-sent', answerSentHandler);
+    gScript.sendAsyncMessage('trigger-on-answer');
+  });
+
+  return Promise.resolve();
+}
+
+function testCreateRequest() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testCreateRequest ---');
+    request = new PresentationRequest(receiverUrl);
+    request.getAvailability().then((aAvailability) => {
+      aAvailability.onchange = function() {
+        aAvailability.onchange = null;
+        ok(aAvailability.value, 'Sender: Device should be available.');
+        aResolve();
+      }
+    }).catch((aError) => {
+      ok(false, 'Sender: Error occurred when getting availability: ' + aError);
+      teardown();
+      aReject();
+    });
+
+    gScript.sendAsyncMessage('trigger-device-add');
+  });
+}
+
+function testStartConnection() {
+  return new Promise(function(aResolve, aReject) {
+    request.start().then((aConnection) => {
+      connection = aConnection;
+      ok(connection, 'Sender: Connection should be available.');
+      ok(connection.id, 'Sender: Connection ID should be set.');
+      is(connection.state, 'connecting', 'Sender: The initial state should be connecting.');
+      connection.onconnect = function() {
+        connection.onconnect = null;
+        is(connection.state, 'connected', 'Connection should be connected.');
+        aResolve();
+      };
+    }).catch((aError) => {
+      ok(false, 'Sender: Error occurred when establishing a connection: ' + aError);
+      teardown();
+      aReject();
+    });
+  });
+}
+
+function testConnectionTerminate() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testConnectionTerminate---');
+    gScript.addMessageListener('prepare-for-terminate', function prepareForTerminateHandler() {
+      debug('Got message: prepare-for-terminate');
+      gScript.removeMessageListener('prepare-for-terminate', prepareForTerminateHandler);
+      connection.onclose = function() {
+        connection.onclose = null;
+        is(connection.state, 'closed', 'Sender: Connection should be closed.');
+      };
+      gScript.sendAsyncMessage('trigger-control-channel-error');
+      receiverIframe.addEventListener('mozbrowserclose', function() {
+        ok(true, 'observe receiver page closing');
+        aResolve();
+      });
+      postMessageToIframe('ready-to-terminate');
+    });
+  });
+}
+
+function teardown() {
+  gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
+    debug('Got message: teardown-complete');
+    gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
+    gScript.destroy();
+    SimpleTest.finish();
+  });
+  gScript.sendAsyncMessage('teardown');
+}
+
+function runTests() {
+  setup().then(testCreateRequest)
+         .then(testStartConnection)
+         .then(testConnectionTerminate)
+         .then(teardown);
+}
+
+SpecialPowers.pushPermissions([
+  {type: 'presentation-device-manage', allow: false, context: document},
+  {type: 'presentation', allow: true, context: document},
+  {type: 'browser', allow: true, context: document},
+], () => {
+  SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
+                                      ['dom.presentation.test.enabled', true],
+                                      ['dom.mozBrowserFramesEnabled', true],
+                                      ['dom.ipc.tabs.disabled', false],
+                                      ['dom.presentation.test.stage', 0]]},
+                            runTests);
+});
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_inproc.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <!-- Any copyright is dedicated to the Public Domain.
+    - http://creativecommons.org/publicdomain/zero/1.0/ -->
+  <head>
+    <meta charset='utf-8'>
+    <title>Test for control channel establish error during PresentationConnection.terminate()</title>
+    <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
+    <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
+  </head>
+  <body>
+    <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
+      Test for constrol channel establish error during PresentationConnection.terminate()</a>
+    <script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_oop.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <!-- Any copyright is dedicated to the Public Domain.
+    - http://creativecommons.org/publicdomain/zero/1.0/ -->
+  <head>
+    <meta charset='utf-8'>
+    <title>Test for control channel establish error during PresentationConnection.terminate()</title>
+    <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
+    <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
+  </head>
+  <body>
+    <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
+      Test for constrol channel establish error during PresentationConnection.terminate()</a>
+    <script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
+    </script>
+  </body>
+</html>
--- a/dom/svg/SVGElementFactory.cpp
+++ b/dom/svg/SVGElementFactory.cpp
@@ -99,24 +99,16 @@ void
 SVGElementFactory::Shutdown()
 {
   if (sTagAtomTable) {
     PL_HashTableDestroy(sTagAtomTable);
     sTagAtomTable = nullptr;
   }
 }
 
-bool
-SVGElementFactory::Exists(nsIAtom *aTag)
-{
-  MOZ_ASSERT(sTagAtomTable, "no lookup table, needs SVGElementFactory::Init");
-  void* tag = PL_HashTableLookupConst(sTagAtomTable, aTag);
-  return tag != nullptr;
-}
-
 nsresult
 NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                  FromParser aFromParser)
 {
   NS_ASSERTION(sTagAtomTable, "no lookup table, needs SVGElementFactory::Init");
 
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
   nsIAtom* name = ni->NameAtom();
--- a/dom/svg/SVGElementFactory.h
+++ b/dom/svg/SVGElementFactory.h
@@ -11,16 +11,14 @@ class nsIAtom;
 
 namespace mozilla {
 namespace dom {
 
 class SVGElementFactory {
 public:
   static void Init();
   static void Shutdown();
-
-  static bool Exists(nsIAtom *aTag);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_SVGElementFactory_h */
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -294,27 +294,28 @@ SVGUseElement::CreateAnonymousContent()
                                             nsIDOMNode::ELEMENT_NODE);
 
     nsCOMPtr<nsIContent> svgNode;
     NS_NewSVGSVGElement(getter_AddRefs(svgNode), nodeInfo.forget(),
                         NOT_FROM_PARSER);
 
     if (!svgNode)
       return nullptr;
-    
+
     // copy attributes
-    const nsAttrName* name;
+    BorrowedAttrInfo info;
     uint32_t i;
-    for (i = 0; (name = newcontent->GetAttrNameAt(i)); i++) {
+    for (i = 0; (info = newcontent->GetAttrInfoAt(i)); i++) {
       nsAutoString value;
-      int32_t nsID = name->NamespaceID();
-      nsIAtom* lname = name->LocalName();
+      int32_t nsID = info.mName->NamespaceID();
+      nsIAtom* lname = info.mName->LocalName();
 
-      newcontent->GetAttr(nsID, lname, value);
-      svgNode->SetAttr(nsID, lname, name->GetPrefix(), value, false);
+      info.mValue->ToString(value);
+
+      svgNode->SetAttr(nsID, lname, info.mName->GetPrefix(), value, false);
     }
 
     // move the children over
     uint32_t num = newcontent->GetChildCount();
     for (i = 0; i < num; i++) {
       nsCOMPtr<nsIContent> child = newcontent->GetFirstChild();
       newcontent->RemoveChildAt(0, false);
       svgNode->InsertChildAt(child, i, true);
--- a/dom/tests/mochitest/gamepad/test_gamepad_connect_events.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_connect_events.html
@@ -19,36 +19,36 @@ var gamepad_index;
 
 function pressButton() {
   GamepadService.newButtonEvent(gamepad_index, 0, true);
   GamepadService.newButtonEvent(gamepad_index, 0, false);
 }
 
  // Add a gamepad
 function startTests() {
-   GamepadService.addGamepad("test gamepad", // id
-                             GamepadService.standardMapping,
-                             4, // buttons
-                             2).then(function(i) {
-                               gamepad_index = i;
-                               gamepad_connected()
-                             });
+  window.addEventListener("gamepadbuttondown", function() {
+    // Wait to ensure that all frames received the button press as well.
+    SpecialPowers.executeSoon(tests[testNum++]);
+  });
+
+  GamepadService.addGamepad("test gamepad", // id
+                            GamepadService.standardMapping,
+                            4, // buttons
+                            2).then(function(i) {
+                              gamepad_index = i;
+                              gamepad_connected()
+                            });
 }
 
 var f1, f2;
 function gamepad_connected() {
   f1 = document.getElementById('f1');
   pressButton();
 }
 
-window.addEventListener("gamepadbuttondown", function() {
-  // Wait to ensure that all frames received the button press as well.
-  SpecialPowers.executeSoon(tests[testNum++]);
-});
-
 var testNum = 0;
 var tests = [
   test1,
   test2,
 ];
 
 function test1() {
   is(f1.contentWindow.connectedEvents, 1, "right number of connection events in frame 1");
--- a/dom/tests/mochitest/pointerlock/file_allowPointerLockSandboxFlag.html
+++ b/dom/tests/mochitest/pointerlock/file_allowPointerLockSandboxFlag.html
@@ -58,34 +58,34 @@
           SimpleTest.waitForFocus(doStartTest, iframe.contentWindow);
         }
         function doStartTest() {
           contentDocument = iframe.contentDocument;
           iframeDiv = contentDocument.getElementById("div");
 
           numberOfRuns++;
 
-          contentDocument.addEventListener("mozpointerlockchange", function () {
-            if (contentDocument.mozPointerLockElement === iframeDiv) {
+          contentDocument.addEventListener("pointerlockchange", function () {
+            if (contentDocument.pointerLockElement === iframeDiv) {
               pointerLocked++;
               contentDocument.exitFullscreen();
             }
           });
 
-          contentDocument.addEventListener("mozpointerlockerror", function () {
+          contentDocument.addEventListener("pointerlockerror", function () {
             contentDocument.exitFullscreen();
           });
 
           contentDocument.addEventListener("fullscreenchange", function () {
             if (contentDocument.fullscreenElement) {
               ok(contentDocument.fullscreenElement === iframeDiv,
                  "Fullscreen element can only be iframe div");
               // during second run iframe won't have allow-pointer-lock flag and
-              // mozRequestPointerLock will fail, mozpointerlockerror should be fired
-              iframeDiv.mozRequestPointerLock();
+              // requestPointerLock will fail, pointerlockerror should be fired
+              iframeDiv.requestPointerLock();
             } else if (numberOfRuns === 1) {
               resetIframe();
             } else if (numberOfRuns === 2) {
               runTests();
             }
           });
 
         iframeDiv.requestFullscreen();
--- a/dom/tests/mochitest/pointerlock/file_changeLockElement.html
+++ b/dom/tests/mochitest/pointerlock/file_changeLockElement.html
@@ -52,64 +52,64 @@
       var tester = new ClickTester(block3);
       // It would be called in handler of load event in pointerlock_utils.js
       function start() {
         tester.synthesize(firstClick);
       }
 
       function firstClick(e) {
         is(e.target, block3, "Click is triggered inside block3");
-        document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1);
-        block1.mozRequestPointerLock();
+        document.addEventListener("pointerlockchange", lockedPointerOnBlock1);
+        block1.requestPointerLock();
       }
 
       function lockedPointerOnBlock1() {
-        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1);
-        is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1");
+        document.removeEventListener("pointerlockchange", lockedPointerOnBlock1);
+        is(document.pointerLockElement, block1, "Pointer should be locked on #block1");
         SimpleTest.executeSoon(() => {
           tester.synthesize(secondClick);
         });
       }
 
       function secondClick(e) {
         is(e.target, block1, "Event should be redirected to block1");
         // Use 2s to ensure that we never consider this as an extension of user input.
         setTimeout(() => {
-          document.addEventListener("mozpointerlockchange", lockedPointerOnBlock2);
-          block2.mozRequestPointerLock();
+          document.addEventListener("pointerlockchange", lockedPointerOnBlock2);
+          block2.requestPointerLock();
         }, 2000);
       }
 
       function lockedPointerOnBlock2() {
-        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock2);
-        is(document.mozPointerLockElement, block2, "Pointer should be locked on #block2");
+        document.removeEventListener("pointerlockchange", lockedPointerOnBlock2);
+        is(document.pointerLockElement, block2, "Pointer should be locked on #block2");
         SimpleTest.executeSoon(() => {
           tester.synthesize(thirdClick);
         });
       }
 
       function thirdClick(e) {
         is(e.target, block2, "Event should be redirected to block2");
         // Use 2s to ensure that we never consider this as an extension of user input.
         setTimeout(() => {
-          document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
-          block1.mozRequestPointerLock();
+          document.addEventListener("pointerlockchange", lockedPointerOnBlock1Again);
+          block1.requestPointerLock();
         }, 2000);
       }
 
       function lockedPointerOnBlock1Again() {
-        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
-        is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1 again");
+        document.removeEventListener("pointerlockchange", lockedPointerOnBlock1Again);
+        is(document.pointerLockElement, block1, "Pointer should be locked on #block1 again");
         SimpleTest.executeSoon(() => {
           tester.synthesize(fourthClick);
         });
       }
 
       function fourthClick(e) {
         is(e.target, block1, "Event should be redirected to block1 again");
-        document.addEventListener("mozpointerlockchange", () => SimpleTest.finish());
-        document.mozExitPointerLock();
+        document.addEventListener("pointerlockchange", () => SimpleTest.finish());
+        document.exitPointerLock();
       }
 
     </script>
   </div>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_childIframe.html
+++ b/dom/tests/mochitest/pointerlock/file_childIframe.html
@@ -59,76 +59,76 @@ https://bugzilla.mozilla.org/show_bug.cg
        */
 
       SimpleTest.waitForExplicitFinish();
 
       var parent = document.getElementById("parent")
         , childDiv = document.getElementById("childDiv")
         , iframe = document.getElementById("iframe");
 
-      function MozMovementStats() {
-        this.mozMovementX = false;
-        this.mozMovementY = false;
+      function MovementStats() {
+        this.movementX = false;
+        this.movementY = false;
       }
 
-      var firstMove = new MozMovementStats()
-        , secondMove = new MozMovementStats()
+      var firstMove = new MovementStats()
+        , secondMove = new MovementStats()
         , hoverIframe = false;
 
       function runTests () {
         ok(hoverIframe, "Pointer should be locked even when pointer " +
           "hovers over a child iframe");
-        is(firstMove.mozMovementX, secondMove.mozMovementX, "MovementX of first " +
+        is(firstMove.movementX, secondMove.movementX, "MovementX of first " +
           "move to childDiv should be equal to movementX of second move " +
           "to child div");
-        is(firstMove.mozMovementY, secondMove.mozMovementY, "MovementY of first " +
+        is(firstMove.movementY, secondMove.movementY, "MovementY of first " +
           "move to childDiv should be equal to movementY of second move " +
           "to child div");
       }
 
       var firstMoveChild = function (e) {
-        firstMove.mozMovementX = e.mozMovementX;
-        firstMove.mozMovementY = e.mozMovementY;
+        firstMove.movementX = e.movementX;
+        firstMove.movementY = e.movementY;
 
         parent.removeEventListener("mousemove", firstMoveChild);
         parent.addEventListener("mousemove", moveIframe);
 
         synthesizeMouseAtCenter(iframe, {type: "mousemove"}, window);
       };
 
       var moveIframe = function (e) {
-        hoverIframe = !!document.mozPointerLockElement;
+        hoverIframe = !!document.pointerLockElement;
 
         parent.removeEventListener("mousemove", moveIframe);
         parent.addEventListener("mousemove", secondMoveChild);
 
         synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
       };
 
       var secondMoveChild = function (e) {
-        secondMove.mozMovementX = e.mozMovementX;
-        secondMove.mozMovementY = e.mozMovementY;
+        secondMove.movementX = e.movementX;
+        secondMove.movementY = e.movementY;
         parent.removeEventListener("mousemove", secondMoveChild);
 
         addFullscreenChangeContinuation("exit", function() {
           runTests();
           SimpleTest.finish();
         });
         document.exitFullscreen();
       };
 
-      document.addEventListener("mozpointerlockchange", function () {
-        if (document.mozPointerLockElement === parent) {
+      document.addEventListener("pointerlockchange", function () {
+        if (document.pointerLockElement === parent) {
           parent.addEventListener("mousemove", firstMoveChild);
           synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
         }
       }, false);
 
       function start() {
         addFullscreenChangeContinuation("enter", function() {
-          parent.mozRequestPointerLock();
+          parent.requestPointerLock();
         });
         parent.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_doubleLock.html
+++ b/dom/tests/mochitest/pointerlock/file_doubleLock.html
@@ -19,48 +19,48 @@ https://bugzilla.mozilla.org/show_bug.cg
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
     Mozilla Bug 633602</a>
   <div id="div"></div>
   <pre id="test">
     <script type="text/javascript">
       /*
        * Test for Bug 633602
        * If element requests pointerlock on itself while in pointerlock state
-       * mozpointerlockchange event should be dispatched
+       * pointerlockchange event should be dispatched
        */
 
       SimpleTest.waitForExplicitFinish();
 
       var div = document.getElementById("div")
         , numberOfLocks = 0;
 
       function runTests () {
         is(numberOfLocks, 2, "Requesting pointer lock on a locked element " +
-          "should dispatch mozpointerlockchange event");
+          "should dispatch pointerlockchange event");
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
-        if (document.mozPointerLockElement === div) {
+      document.addEventListener("pointerlockchange", function (e) {
+        if (document.pointerLockElement === div) {
           if (numberOfLocks === 2) {
             addFullscreenChangeContinuation("exit", function() {
               runTests();
               SimpleTest.finish();
             });
             document.exitFullscreen();
           }
           else {
             numberOfLocks++;
-            div.mozRequestPointerLock();
+            div.requestPointerLock();
           }
         }
       }, false);
 
       function start() {
         console.log('started');
         addFullscreenChangeContinuation("enter", function() {
-          div.mozRequestPointerLock();
+          div.requestPointerLock();
         });
         div.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_escapeKey.html
+++ b/dom/tests/mochitest/pointerlock/file_escapeKey.html
@@ -30,36 +30,36 @@
 
       function start() {
         addFullscreenChangeContinuation("enter", enteredFullscreen);
         div.requestFullscreen();
       }
 
       function enteredFullscreen(e) {
         is(document.fullscreenElement, div, "Element #div should entered fullscreen");
-        ok(!document.mozPointerLockElement, "Pointer shouldn't have been locked");
-        document.addEventListener("mozpointerlockchange", lockedPointer);
-        div.mozRequestPointerLock();
+        ok(!document.pointerLockElement, "Pointer shouldn't have been locked");
+        document.addEventListener("pointerlockchange", lockedPointer);
+        div.requestPointerLock();
       }
 
       function lockedPointer(e) {
-        document.removeEventListener("mozpointerlockchange", lockedPointer);
-        is(document.mozPointerLockElement, div, "Pointer should have been locked on #div");
-        document.addEventListener("mozpointerlockchange", unlockedPointer);
+        document.removeEventListener("pointerlockchange", lockedPointer);
+        is(document.pointerLockElement, div, "Pointer should have been locked on #div");
+        document.addEventListener("pointerlockchange", unlockedPointer);
         addFullscreenChangeContinuation("exit", leavedFullscreen);
         SimpleTest.executeSoon(() => synthesizeKey("VK_ESCAPE", {}));
       }
 
       var pointerUnlocked = false;
       var exitedFullscreen = false;
 
       function unlockedPointer() {
-        document.removeEventListener("mozpointerlockchange", unlockedPointer);
+        document.removeEventListener("pointerlockchange", unlockedPointer);
         ok(!pointerUnlocked, "Shouldn't have unlocked pointer before");
-        ok(!document.mozPointerLockElement, "Pointer should have been unlocked now");
+        ok(!document.pointerLockElement, "Pointer should have been unlocked now");
         pointerUnlocked = true;
         finishTest();
       }
 
       function leavedFullscreen() {
         ok(!exitedFullscreen, "Shouldn't have exited fullscreen before");
         ok(!document.fullscreenElement, "Should have exited fullscreen now");
         exitedFullscreen = true;
--- a/dom/tests/mochitest/pointerlock/file_infiniteMovement.html
+++ b/dom/tests/mochitest/pointerlock/file_infiniteMovement.html
@@ -17,19 +17,19 @@ https://bugzilla.mozilla.org/show_bug.cg
       href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
       Mozilla Bug 633602
     </a>
     <div id="div"></div>
     <pre id="test">
       <script type="application/javascript">
         /*
          * Test for Bug 633602
-         * This test checks if mozMovementX and mozMovementY
+         * This test checks if movementX and movementY
          * are present in a mouse event object.
-         * It also checks the values for mozMovementXY.
+         * It also checks the values for movementXY.
          * They should be equal to the current screenXY minus
          * the last screenXY
          * This test will also test that the incremental movement is
          * not constrained to the width of the screen.
          */
 
         SimpleTest.waitForExplicitFinish();
 
@@ -68,36 +68,36 @@ https://bugzilla.mozilla.org/show_bug.cg
           addFullscreenChangeContinuation("exit", function() {
             info("Got fullscreenchange for exiting");
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
         }
 
-        document.addEventListener("mozpointerlockchange", function (e) {
-          if (document.mozPointerLockElement === div) {
-            info("Got mozpointerlockchange for entering");
+        document.addEventListener("pointerlockchange", function (e) {
+          if (document.pointerLockElement === div) {
+            info("Got pointerlockchange for entering");
             div.addEventListener("mousemove", firstMoveListener, false);
 
             divCenterWidth = Math.round(div.getBoundingClientRect().width / 2);
             divCenterHeight = Math.round(div.getBoundingClientRect().height / 2);
 
             synthesizeMouse(div, divCenterWidth, divCenterHeight, {
               type: "mousemove"
             }, window);
           } else {
-            info("Got mozpointerlockchange for exiting");
+            info("Got pointerlockchange for exiting");
           }
         }, false);
 
         function start() {
           info("Requesting fullscreen on parent");
           addFullscreenChangeContinuation("enter", function() {
             info("Got fullscreenchange for entering");
-            div.mozRequestPointerLock();
+            div.requestPointerLock();
           });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_locksvgelement.html
+++ b/dom/tests/mochitest/pointerlock/file_locksvgelement.html
@@ -30,33 +30,33 @@
          * Test locking non-html element.
          */
 
         SimpleTest.waitForExplicitFinish(1);
 
         var elem,
           elemWasLocked = false;
 
-        document.addEventListener("mozpointerlockchange", function (e) {
+        document.addEventListener("pointerlockchange", function (e) {
           if (document.fullscreenElement &&
-              document.mozPointerLockElement === elem) {
+              document.pointerLockElement === elem) {
             elemWasLocked = true;
-            document.mozExitPointerLock();
+            document.exitPointerLock();
           } else {
             addFullscreenChangeContinuation("exit", function() {
               ok(elemWasLocked, "Expected SVG elem to become locked.");
               SimpleTest.finish();
             });
             document.exitFullscreen();
           }
         }, false);
 
         function start() {
           elem = document.getElementById("svg-elem");
           addFullscreenChangeContinuation("enter", function() {
-            elem.mozRequestPointerLock();
+            elem.requestPointerLock();
           });
           elem.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_movementXY.html
+++ b/dom/tests/mochitest/pointerlock/file_movementXY.html
@@ -17,54 +17,54 @@ https://bugzilla.mozilla.org/show_bug.cg
       href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
       Mozilla Bug 633602
     </a>
     <div id="div"></div>
     <pre id="test">
       <script type="application/javascript">
         /*
          * Test for Bug 633602
-         * Checks if mozMovementX and mozMovementY are present
+         * Checks if movementX and movementY are present
          * in the mouse event object.
-         * It also checks the values for mozMovementXY.
+         * It also checks the values for movementXY.
          * They should be equal to the current screenXY minus
          * the last screenXY
          */
 
         SimpleTest.waitForExplicitFinish();
         SimpleTest.requestFlakyTimeout("We may need to wait for window's moving");
 
         function MouseMovementStats() {
           this.screenX = false;
           this.screenY = false;
-          this.mozMovementX = false;
-          this.mozMovementY = false;
+          this.movementX = false;
+          this.movementY = false;
         }
 
         var div = document.getElementById("div")
           , divCenterWidth = 0
           , divCenterHeight = 0
-          , mozMovementX = false
-          , mozMovementY = false
+          , movementX = false
+          , movementY = false
           , firstMove = new MouseMovementStats()
           , secondMove = new MouseMovementStats();
 
         function runTests () {
-          ok(mozMovementX && mozMovementY, "mozMovementX and " +
-            "mozMovementY should exist in mouse events objects.");
-          is(secondMove.mozMovementX, secondMove.screenX - firstMove.screenX,
-           "mozMovementX should be equal to eNow.screenX-ePrevious.screenX");
-          is(secondMove.mozMovementY, secondMove.screenY - firstMove.screenY,
-           "mozMovementY should be equal to eNow.screenY-ePrevious.screenY");
+          ok(movementX && movementY, "movementX and " +
+            "movementY should exist in mouse events objects.");
+          is(secondMove.movementX, secondMove.screenX - firstMove.screenX,
+           "movementX should be equal to eNow.screenX-ePrevious.screenX");
+          is(secondMove.movementY, secondMove.screenY - firstMove.screenY,
+           "movementY should be equal to eNow.screenY-ePrevious.screenY");
         }
 
         var moveMouse = function(e) {
           info("Got mouse move");
-          mozMovementX = ("mozMovementX" in e);
-          mozMovementY = ("mozMovementY" in e);
+          movementX = ("movementX" in e);
+          movementY = ("movementY" in e);
 
           div.removeEventListener("mousemove", moveMouse, false);
           div.addEventListener("mousemove", moveMouseAgain, false);
 
           firstMove.screenX = e.screenX;
           firstMove.screenY = e.screenY;
 
           divCenterWidth = Math.round(div.getBoundingClientRect().width / 2);
@@ -74,18 +74,18 @@ https://bugzilla.mozilla.org/show_bug.cg
             type: "mousemove"
           }, window);
         };
 
         var moveMouseAgain = function(e) {
           info("Got mouse move again");
           secondMove.screenX = e.screenX;
           secondMove.screenY = e.screenY;
-          secondMove.mozMovementX = e.mozMovementX;
-          secondMove.mozMovementY = e.mozMovementY;
+          secondMove.movementX = e.movementX;
+          secondMove.movementY = e.movementY;
 
           div.removeEventListener("mousemove", moveMouseAgain, false);
           addFullscreenChangeContinuation("exit", function() {
             info("Got fullscreenchange for exiting");
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
--- a/dom/tests/mochitest/pointerlock/file_nestedFullScreen.html
+++ b/dom/tests/mochitest/pointerlock/file_nestedFullScreen.html
@@ -34,43 +34,43 @@
       var parentDiv = document.getElementById("parentDiv")
         , childDiv = document.getElementById("childDiv")
         , parentDivLocked = false
         , parentDivFullScreen = false
         , pointerLocked = false;
 
       function runTests () {
         ok(parentDivLocked, "After requesting pointerlock on parentDiv " +
-          "document.mozPointerLockElement should be equal to " +
+          "document.pointerLockElement should be equal to " +
           " parentDiv element");
         isnot(pointerLocked, true, "Requesting fullscreen on " +
           "childDiv while parentDiv still in fullscreen should " +
           "unlock the pointer");
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
-        if (document.mozPointerLockElement === parentDiv) {
+      document.addEventListener("pointerlockchange", function (e) {
+        if (document.pointerLockElement === parentDiv) {
           parentDivLocked = true;
           addFullscreenChangeContinuation("enter", function() {
-            pointerLocked = !!document.mozPointerLockElement;
+            pointerLocked = !!document.pointerLockElement;
             addFullscreenChangeContinuation("exit", function() {
               addFullscreenChangeContinuation("exit", function() {
                 runTests();
                 SimpleTest.finish();
               });
               document.exitFullscreen();
             });
             document.exitFullscreen();
           });
           childDiv.requestFullscreen();
         }
       }, false);
 
       function start() {
         addFullscreenChangeContinuation("enter", function() {
           parentDivFullScreen = true;
-          parentDiv.mozRequestPointerLock();
+          parentDiv.requestPointerLock();
         });
         parentDiv.requestFullscreen();
       }
     </script>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_pointerLockPref.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerLockPref.html
@@ -33,43 +33,43 @@
 
         function runTests () {
           ok(prefEnabled, "Element should be able to lock the pointer " +
             "if pointer-lock pref is set to TRUE");
           ok(prefDisabled, "Element should NOT be able to lock the pointer " +
             "if pointer-lock pref is set to FALSE");
         }
 
-        document.addEventListener("mozpointerlockchange", function (e) {
-          if (document.mozPointerLockElement === div) {
+        document.addEventListener("pointerlockchange", function (e) {
+          if (document.pointerLockElement === div) {
             prefEnabled = true;
-            document.mozExitPointerLock();
+            document.exitPointerLock();
           }
           else {
             SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
                                       false );
-            div.mozRequestPointerLock();
+            div.requestPointerLock();
           }
         }, false);
 
-        document.addEventListener("mozpointerlockerror", function (e) {
+        document.addEventListener("pointerlockerror", function (e) {
           prefDisabled = true;
           addFullscreenChangeContinuation("exit", function() {
             SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
                                        true );
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
         }, false);
 
         function start() {
           addFullscreenChangeContinuation("enter", function() {
             SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
                                       true );
-            div.mozRequestPointerLock();
+            div.requestPointerLock();
           });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
@@ -32,73 +32,73 @@
         pointerLocked = false,
         hasExitPointerLock = false,
         pointerLockElement = false,
         hasMovementX = false,
         hasMovementY = false;
         gotContextMenuEvent = false;
 
       function runTests () {
-        ok(hasRequestPointerLock, "Element should have mozRequestPointerLock.");
+        ok(hasRequestPointerLock, "Element should have requestPointerLock.");
         ok(pointerLockChangeEventFired, "pointerlockchange event should fire.");
         ok(pointerUnlocked, "Should be able to unlock pointer locked element.");
         ok(pointerLocked, "Requested element should be able to lock.");
-        ok(hasExitPointerLock, "Document should have mozExitPointerLock");
+        ok(hasExitPointerLock, "Document should have exitPointerLock");
         ok(pointerLockElement, "Document should keep track of correct pointer locked element");
-        ok(hasMovementX, "Mouse Event should have mozMovementX.");
-        ok(hasMovementY, "Mouse Event should have mozMovementY.");
+        ok(hasMovementX, "Mouse Event should have movementX.");
+        ok(hasMovementY, "Mouse Event should have movementY.");
         ok(!gotContextMenuEvent, "Shouldn't have got a contextmenu event.");
       }
 
       function mouseMoveHandler(e) {
         info("Got mousemove");
         document.removeEventListener("mousemove", mouseMoveHandler, false);
 
-        hasMovementX = "mozMovementX" in e;
-        hasMovementY = "mozMovementY" in e;
+        hasMovementX = "movementX" in e;
+        hasMovementY = "movementY" in e;
 
-        hasExitPointerLock = "mozExitPointerLock" in document;
-        document.mozExitPointerLock();
+        hasExitPointerLock = "exitPointerLock" in document;
+        document.exitPointerLock();
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
+      document.addEventListener("pointerlockchange", function (e) {
         pointerLockChangeEventFired = true;
 
-        if (document.mozPointerLockElement) {
-          info("Got mozpointerlockchange for entering");
+        if (document.pointerLockElement) {
+          info("Got pointerlockchange for entering");
           pointerLocked = true;
-          pointerLockElement = document.mozPointerLockElement === div;
+          pointerLockElement = document.pointerLockElement === div;
  
           window.addEventListener("contextmenu",
                                   function() { gotContextMenuEvent = true; },
                                   true);
           synthesizeMouse(document.body, 4, 4,
                           { type: "contextmenu", button: 2 },
                           window);
 
           document.addEventListener("mousemove", mouseMoveHandler, false);
           synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
         } else {
-          info("Got mozpointerlockchange for exiting");
+          info("Got pointerlockchange for exiting");
           pointerUnlocked = true;
           addFullscreenChangeContinuation("exit", function() {
             info("Got fullscreenchange for exiting");
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
         }
       }, false);
 
       function start() {
         div = document.getElementById("div");
         info("Requesting fullscreen on parent");
         addFullscreenChangeContinuation("enter", function() {
           info("Got fullscreenchange for entering");
-          hasRequestPointerLock = "mozRequestPointerLock" in div;
-          div.mozRequestPointerLock();
+          hasRequestPointerLock = "requestPointerLock" in div;
+          div.requestPointerLock();
         });
         div.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_pointerlockerror.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerlockerror.html
@@ -20,22 +20,22 @@
     <script type="text/javascript">
       /*
        * Test for Bug 633602
        * Make sure pointerlockerror event fires.
        */
 
       SimpleTest.waitForExplicitFinish();
 
-      document.addEventListener("mozpointerlockerror", function (e) {
+      document.addEventListener("pointerlockerror", function (e) {
         ok(true, "pointerlockerror event should fire.");
         SimpleTest.finish();
       }, false);
 
       function start() {
         // element not in the DOM, not fullscreen, should fail to lock
         div = document.createElement("div");
-        div.mozRequestPointerLock();
+        div.requestPointerLock();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
+++ b/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
@@ -38,50 +38,50 @@ function listenOneDocEvent(type, handler
     document.removeEventListener(type, callback);
     SimpleTest.executeSoon(() => handler(event));
   }
   document.addEventListener(type, callback);
 }
 
 function checkPointerLockElement(elem) {
   if (elem) {
-    is(document.mozPointerLockElement, elem,
+    is(document.pointerLockElement, elem,
        `#${elem.id} should have locked the pointer`);
   } else {
-    ok(!document.mozPointerLockElement, "Pointer should have been unlocked");
+    ok(!document.pointerLockElement, "Pointer should have been unlocked");
   }
 }
 
 function start() {
   addFullscreenChangeContinuation("enter", enteredFullscreen);
   document.documentElement.requestFullscreen();
 }
 
 function enteredFullscreen() {
   is(document.fullscreenElement, document.documentElement,
      "Root element should have entered fullscreen");
-  listenOneDocEvent("mozpointerlockchange", lockedPointerOnDiv);
-  div.mozRequestPointerLock();
+  listenOneDocEvent("pointerlockchange", lockedPointerOnDiv);
+  div.requestPointerLock();
 }
 
 function lockedPointerOnDiv() {
   checkPointerLockElement(div);
-  listenOneDocEvent("mozpointerlockchange", unlockedPointerFromDiv);
+  listenOneDocEvent("pointerlockchange", unlockedPointerFromDiv);
   document.body.removeChild(div);
 }
 
 function unlockedPointerFromDiv() {
   checkPointerLockElement(null);
-  listenOneDocEvent("mozpointerlockchange", lockedPointerOnInner);
-  inner.mozRequestPointerLock();
+  listenOneDocEvent("pointerlockchange", lockedPointerOnInner);
+  inner.requestPointerLock();
 }
 
 function lockedPointerOnInner() {
   checkPointerLockElement(inner);
-  listenOneDocEvent("mozpointerlockchange", unlockedPointerFromInner);
+  listenOneDocEvent("pointerlockchange", unlockedPointerFromInner);
   document.body.removeChild(outer);
 }
 
 function unlockedPointerFromInner() {
   checkPointerLockElement(null);
   addFullscreenChangeContinuation("exit", exitedFullscreen);
   document.exitFullscreen();
 }
--- a/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html
+++ b/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html
@@ -175,33 +175,33 @@ https://bugzilla.mozilla.org/show_bug.cg
             info("Got fullscreenchange for exiting");
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
         });
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
-        if (document.mozPointerLockElement === parent) {
-          info("Got mozpointerlockchange for entering");
+      document.addEventListener("pointerlockchange", function (e) {
+        if (document.pointerLockElement === parent) {
+          info("Got pointerlockchange for entering");
           parent.addEventListener("mousemove", startMouseTests);
           child.addEventListener("mousemove", childMoveTest);
           SimpleTest.executeSoon(function () {
             synthesizeMouseAtCenter(parent, {type: "mousemove"}, window);
           });
         } else {
-          info("Got mozpointerlockchange for exiting");
+          info("Got pointerlockchange for exiting");
         }
       }, false);
 
       function start() {
         info("Requesting fullscreen on parent");
         addFullscreenChangeContinuation("enter", function() {
           info("Got fullscreenchange for entering");
-          parent.mozRequestPointerLock();
+          parent.requestPointerLock();
         });
         parent.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
+++ b/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
@@ -61,50 +61,50 @@ https://bugzilla.mozilla.org/show_bug.cg
           clientX: e.clientX,
           clientY: e.clientY
         };
 
         if (!firstCall) {
           return;
         }
 
-        isUnlocked = !document.mozPointerLockElement;
-        div.mozRequestPointerLock();
+        isUnlocked = !document.pointerLockElement;
+        div.requestPointerLock();
       }
 
       function moveLocked(e) {
         info("Got mousemove via moveLocked");
         div.removeEventListener("mousemove", moveLocked, false);
 
-        isLocked = !!document.mozPointerLockElement;
+        isLocked = !!document.pointerLockElement;
         lockedCoords = {
           screenX: e.screenX,
           screenY: e.screenY,
           clientX: e.clientX,
           clientY: e.clientY
         };
 
         addFullscreenChangeContinuation("exit", function() {
           info("Got fullscreenchange for exiting");
           runTests();
           SimpleTest.finish();
         });
         document.exitFullscreen();
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
-        if (document.mozPointerLockElement === div) {
-          info("Got mozpointerlockchange for entering");
+      document.addEventListener("pointerlockchange", function (e) {
+        if (document.pointerLockElement === div) {
+          info("Got pointerlockchange for entering");
           div.removeEventListener("mousemove", moveUnlocked, false);
           div.addEventListener("mousemove", moveLocked, false);
           divRect = div.getBoundingClientRect();
           synthesizeNativeMouseMove(div, (divRect.width / 4) * 3,
                                     (divRect.height / 4) * 3);
         } else {
-          info("Got mozpointerlockchange for exiting");
+          info("Got pointerlockchange for exiting");
         }
       }, false);
 
       function start() {
         div = document.getElementById("div");
         info("Requesting fullscreen on parent");
         addFullscreenChangeContinuation("enter", function() {
           info("Got fullscreenchange for entering");
--- a/dom/tests/mochitest/pointerlock/file_suppressSomeMouseEvents.html
+++ b/dom/tests/mochitest/pointerlock/file_suppressSomeMouseEvents.html
@@ -67,19 +67,19 @@ https://bugzilla.mozilla.org/show_bug.cg
            "parent's mouseover should not be firing in Full Screen and Pointer Lock.");
         is(parentStats.mouseLeave, false,
            "parent's mouseleave should not be firing in Full Screen and Pointer Lock.");
         is(parentStats.mouseOut, false,
            "parent's mouseout should not be firing in Full Screen and Pointer Lock.");
       }
 
       var parentMoveListener = function () {
-        isPointerLocked = !!document.mozPointerLockElement;
+        isPointerLocked = !!document.pointerLockElement;
         removeEventListeners();
-        document.mozExitPointerLock();
+        document.exitPointerLock();
       };
 
       var parentOutListener = function (e) {
           parentStats.mouseOut = true;
       };
       var parentLeaveListener = function (e) {
           parentStats.mouseLeave = true;
       };
@@ -126,33 +126,33 @@ https://bugzilla.mozilla.org/show_bug.cg
         parent.removeEventListener("mouseenter", parentEnterListener, false);
 
         child.removeEventListener("mouseout", childOutListener, false);
         child.removeEventListener("mouseleave", childLeaveListener, false);
         child.removeEventListener("mouseover"  , childOverListener, false);
         child.removeEventListener("mouseenter", childEnterListener, false);
       }
 
-      document.addEventListener("mozpointerlockchange", function (e) {
-        if (document.mozPointerLockElement === parent) {
+      document.addEventListener("pointerlockchange", function (e) {
+        if (document.pointerLockElement === parent) {
           addEventListeners();
           synthesizeMouseAtCenter(child, { type: "mousemove" }, window);
         }
         else {
           addFullscreenChangeContinuation("exit", function() {
             runTests();
             SimpleTest.finish();
           });
           document.exitFullscreen();
         }
       }, false);
 
       function start() {
         parent = document.getElementById("parent");
         child = document.getElementById("child");
         addFullscreenChangeContinuation("enter", function() {
-          parent.mozRequestPointerLock();
+          parent.requestPointerLock();
         });
         parent.requestFullscreen();
       }
   </script>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_targetOutOfFocus.html
+++ b/dom/tests/mochitest/pointerlock/file_targetOutOfFocus.html
@@ -37,21 +37,21 @@
           , divPointerLock = false;
 
         function runTests () {
           ok(divPointerLock, "Pointer should be locked even if " +
             "the element being locked is not focused");
         }
 
         input.addEventListener("focus", function() {
-          div.mozRequestPointerLock();
+          div.requestPointerLock();
         }, false);
 
-        document.addEventListener("mozpointerlockchange", function (e) {
-          if (document.mozPointerLockElement === div) {
+        document.addEventListener("pointerlockchange", function (e) {
+          if (document.pointerLockElement === div) {
             divPointerLock = true;
             addFullscreenChangeContinuation("exit", function() {
               runTests();
               SimpleTest.finish();
             });
             document.exitFullscreen();
           }
         }, false);
--- a/dom/tests/mochitest/pointerlock/file_withoutDOM.html
+++ b/dom/tests/mochitest/pointerlock/file_withoutDOM.html
@@ -34,21 +34,21 @@
         var div = document.createElement("div")
           , withouthDOM = false;
 
         function runTests () {
           ok(withouthDOM, "If an element is NOT in the " +
             "DOM Tree pointer should NOT be locked");
         }
 
-        document.addEventListener("mozpointerlockerror", function (e) {
+        document.addEventListener("pointerlockerror", function (e) {
           withouthDOM = true;
           runTests();
           SimpleTest.finish();
         }, false);
 
         function start() {
-          div.mozRequestPointerLock();
+          div.requestPointerLock();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/webcomponents/test_document_register.html
+++ b/dom/tests/mochitest/webcomponents/test_document_register.html
@@ -41,44 +41,34 @@ function startTest() {
 
   // If prototype is an interface prototype object for any interface object,
   // registration will throw.
   testRegisterSimple("x-html-elem", HTMLElement.prototype, true);
   testRegisterSimple("x-html-select", HTMLSelectElement.prototype, true);
   testRegisterSimple("some-elem", HTMLElement.prototype, true);
   testRegisterSimple("x-html-p", HTMLParagraphElement.prototype, true);
   testRegisterSimple("x-html-span", HTMLSpanElement.prototype, true);
-  testRegisterSimple("x-svg-proto", SVGElement.prototype, true);
 
   // Make sure the prototype on unresolved elements is HTMLElement not HTMLUnknownElement.
   var unresolved = document.getElementById("unresolved");
   is(unresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
 
   var anotherUnresolved = document.createElement("maybe-custom-element");
   is(anotherUnresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
 
   // Registering without a prototype should automatically create one inheriting from HTMLElement.
   testRegisterSimple("x-elem-no-proto", null, false);
-  var simpleElem = document.createElement("x-elem-no-proto");
-  is(simpleElem.__proto__.__proto__, HTMLElement.prototype, "Default prototype should inherit from HTMLElement");
 
   var simpleProto = Object.create(HTMLElement.prototype);
   testRegisterSimple("x-elem-simple-proto", simpleProto, false);
-  var simpleProtoElem = document.createElement("x-elem-simple-proto");
-  is(simpleProtoElem.__proto__, simpleProto, "Custom element should use registered prototype.");
-  var anotherSimpleElem = document.createElementNS("http://www.w3.org/1999/xhtml", "x-elem-simple-proto");
-  is(anotherSimpleElem.__proto__, simpleProto, "Custom element should use registered prototype.");
 
   // Test registering some invalid prototypes.
   testRegisterSimple("x-invalid-number", 42, true);
   testRegisterSimple("x-invalid-boolean", false, true);
   testRegisterSimple("x-invalid-float", 1.0, true);
-  // Can not register with a prototype that inherits from SVGElement
-  // without extending an existing element type.
-  testRegisterSimple("x-html-obj-svg", Object.create(SVGElement.prototype), true);
   // A prototype with a non-configurable "constructor" property must throw.
   var nonConfigProto = Object.create(HTMLElement.prototype,
     { constructor: { configurable: false, value: function() {} } });
   testRegisterSimple("x-non-config-proto", nonConfigProto, true);
 
   // Test invalid custom element names.
   testRegisterSimple("invalid", Object.create(HTMLElement.prototype), true);
   testRegisterSimple("annotation-xml", Object.create(HTMLElement.prototype), true);
@@ -91,32 +81,23 @@ function startTest() {
   testRegisterSimple("missing-glyph", Object.create(HTMLElement.prototype), true);
 
   // Test registering elements that extend from an existing element.
   testRegisterExtend("x-extend-span", "span", Object.create(HTMLElement.prototype), false);
   testRegisterExtend("x-extend-span-caps", "SPAN", Object.create(HTMLElement.prototype), false);
 
   // Test registering elements that extend from a non-existing element.
   testRegisterExtend("x-extend-span-nonexist", "nonexisting", Object.create(HTMLElement.prototype), true);
-  testRegisterExtend("x-extend-svg-nonexist", "nonexisting", Object.create(SVGElement.prototype), true);
 
   // Test registration with duplicate type.
   testRegisterSimple("x-dupe-me", Object.create(HTMLElement.prototype), false);
   testRegisterSimple("x-dupe-me", Object.create(HTMLElement.prototype), true);
   testRegisterSimple("X-DUPE-ME", Object.create(HTMLElement.prototype), true);
   testRegisterSimple("x-dupe-me", null, true);
   testRegisterExtend("x-dupe-me", "span", Object.create(HTMLElement.prototype), true);
-  testRegisterExtend("x-dupe-me", "shape", Object.create(SVGElement.prototype), true);
-
-  testRegisterExtend("x-svg-dupe-me", "circle", Object.create(SVGElement.prototype), false);
-  testRegisterSimple("x-svg-dupe-me", Object.create(HTMLElement.prototype), true);
-  testRegisterSimple("X-SVG-DUPE-ME", Object.create(HTMLElement.prototype), true);
-  testRegisterSimple("x-svg-dupe-me", null, true);
-  testRegisterExtend("x-svg-dupe-me", "span", Object.create(HTMLElement.prototype), true);
-  testRegisterExtend("x-svg-dupe-me", "shape", Object.create(SVGElement.prototype), true);
 
   // document.createElement with extended type.
   var extendedProto = Object.create(HTMLButtonElement.prototype);
   var buttonConstructor = document.registerElement("x-extended-button", { prototype: extendedProto, extends: "button" });
   var extendedButton = document.createElement("button", {is: "x-extended-button"});
   is(extendedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
   is(extendedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
   is(extendedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -248,20 +248,29 @@ partial interface Document {
 
   // Events handlers
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenchange;
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenerror;
 };
 
-// http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html#extensions-to-the-document-interface
+// https://w3c.github.io/pointerlock/#extensions-to-the-document-interface
+// https://w3c.github.io/pointerlock/#extensions-to-the-documentorshadowroot-mixin
 partial interface Document {
-    readonly attribute Element? mozPointerLockElement;
-    void mozExitPointerLock ();
+  readonly attribute Element? pointerLockElement;
+  [BinaryName="pointerLockElement", Pref="pointer-lock-api.prefixed.enabled"]
+  readonly attribute Element? mozPointerLockElement;
+  void exitPointerLock();
+  [BinaryName="exitPointerLock", Pref="pointer-lock-api.prefixed.enabled"]
+  void mozExitPointerLock();
+
+  // Event handlers
+  attribute EventHandler onpointerlockchange;
+  attribute EventHandler onpointerlockerror;
 };
 
 //http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
 partial interface Document {
     // this is deprecated from CustomElements v0
     [Throws, Func="CustomElementsRegistry::IsCustomElementsEnabled"]
     object registerElement(DOMString name, optional ElementRegistrationOptions options);
 };
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -125,25 +125,16 @@ interface Element : Node {
   /**
    * If this element has captured the mouse, release the capture. If another
    * element has captured the mouse, this method has no effect.
    */
   void releaseCapture();
 
   // Mozilla extensions
 
-  /**
-   * Requests that this element be made the pointer-locked element, as per the DOM
-   * pointer lock api.
-   *
-   * @see <http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html>
-   */
-  [UnsafeInPrerendering]
-  void mozRequestPointerLock();
-
   // Obsolete methods.
   Attr? getAttributeNode(DOMString name);
   [Throws]
   Attr? setAttributeNode(Attr newAttr);
   [Throws]
   Attr? removeAttributeNode(Attr oldAttr);
   Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
   [Throws]
@@ -269,8 +260,16 @@ partial interface Element {
    * The options parameter is non-standard. In Gecko, it can be:
    *  a RequestFullscreenOptions object
    */
   [Throws, UnsafeInPrerendering, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   void requestFullscreen(optional any options);
   [Throws, UnsafeInPrerendering, BinaryName="requestFullscreen"]
   void mozRequestFullScreen(optional any options);
 };
+
+// https://w3c.github.io/pointerlock/#extensions-to-the-element-interface
+partial interface Element {
+  [UnsafeInPrerendering]
+  void requestPointerLock();
+  [UnsafeInPrerendering, BinaryName="requestPointerLock", Pref="pointer-lock-api.prefixed.enabled"]
+  void mozRequestPointerLock();
+};
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -116,17 +116,19 @@ interface GlobalEventHandlers {
            attribute EventHandler ongotpointercapture;
            [Pref="dom.w3c_pointer_events.enabled"]
            attribute EventHandler onlostpointercapture;
 
            // Mozilla-specific handlers. Unprefixed handlers live in
            // Document rather than here.
            attribute EventHandler onmozfullscreenchange;
            attribute EventHandler onmozfullscreenerror;
+           [Pref="pointer-lock-api.prefixed.enabled"]
            attribute EventHandler onmozpointerlockchange;
+           [Pref="pointer-lock-api.prefixed.enabled"]
            attribute EventHandler onmozpointerlockerror;
 };
 
 [NoInterfaceObject]
 interface WindowEventHandlers {
            attribute EventHandler onafterprint;
            attribute EventHandler onbeforeprint;
            attribute OnBeforeUnloadEventHandler onbeforeunload;
--- a/dom/webidl/EventTarget.webidl
+++ b/dom/webidl/EventTarget.webidl
@@ -15,17 +15,17 @@ dictionary EventListenerOptions {
   boolean capture = false;
   /* Setting to true make the listener be added to the system group. */
   [Func="ThreadSafeIsChromeOrXBL"]
   boolean mozSystemGroup = false;
 };
 
 dictionary AddEventListenerOptions : EventListenerOptions {
   boolean passive = false;
-  // boolean once = false; Bug 1287706
+  boolean once = false;
 };
 
 [Exposed=(Window,Worker,WorkerDebugger,System)]
 interface EventTarget {
   /* Passing null for wantsUntrusted means "default behavior", which
      differs in content and chrome.  In content that default boolean
      value is true, while in chrome the default boolean value is
      false. */
--- a/dom/webidl/MouseEvent.webidl
+++ b/dom/webidl/MouseEvent.webidl
@@ -66,19 +66,19 @@ dictionary MouseEventInit : EventModifie
   // Pointer Lock
   long           movementX = 0;
   long           movementY = 0;
 };
 
 // Mozilla extensions
 partial interface MouseEvent
 {
-  [BinaryName="movementX"]
+  [BinaryName="movementX", Pref="pointer-lock-api.prefixed.enabled"]
   readonly attribute long mozMovementX;
-  [BinaryName="movementY"]
+  [BinaryName="movementY", Pref="pointer-lock-api.prefixed.enabled"]
   readonly attribute long mozMovementY;
 
   // Finger or touch pressure event value
   // ranges between 0.0 and 1.0
   readonly attribute float mozPressure;
 
   const unsigned short    MOZ_SOURCE_UNKNOWN    = 0;
   const unsigned short    MOZ_SOURCE_MOUSE      = 1;
--- a/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl
+++ b/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl
@@ -55,8 +55,14 @@ interface TestInterfaceIterableSingle {
 };
 
 [Constructor(),
  Pref="dom.expose_test_interfaces"]
 interface TestInterfaceIterableDouble {
   iterable<DOMString, DOMString>;
 };
 
+[Constructor(),
+ Pref="dom.expose_test_interfaces"]
+interface TestInterfaceIterableDoubleUnion {
+  iterable<DOMString, (DOMString or long)>;
+};
+
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -1287,16 +1287,33 @@ ServiceWorkerManager::NotifyUnregister(n
   RefPtr<ServiceWorkerUnregisterJob> job =
     new ServiceWorkerUnregisterJob(aPrincipal, scope,
                                     false /* send to parent */);
 
   queue->ScheduleJob(job);
   return NS_OK;
 }
 
+void
+ServiceWorkerManager::WorkerIsIdle(ServiceWorkerInfo* aWorker)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aWorker);
+
+  RefPtr<ServiceWorkerRegistrationInfo> reg =
+    GetRegistration(aWorker->GetPrincipal(), aWorker->Scope());
+  if (!reg) {
+    return;
+  }
+
+  if (reg->GetActive() == aWorker) {
+    reg->TryToActivateAsync();
+  }
+}
+
 already_AddRefed<ServiceWorkerJobQueue>
 ServiceWorkerManager::GetOrCreateJobQueue(const nsACString& aKey,
                                           const nsACString& aScope)
 {
   MOZ_ASSERT(!aKey.IsEmpty());
   ServiceWorkerManager::RegistrationDataPerPrincipal* data;
   if (!mRegistrationInfos.Get(aKey, &data)) {
     data = new RegistrationDataPerPrincipal();
@@ -2831,42 +2848,39 @@ ServiceWorkerManager::ClaimClients(nsIPr
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
     MaybeClaimClient(doc, registration);
   }
 
   return NS_OK;
 }
 
-nsresult
+void
 ServiceWorkerManager::SetSkipWaitingFlag(nsIPrincipal* aPrincipal,
                                          const nsCString& aScope,
                                          uint64_t aServiceWorkerID)
 {
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(aPrincipal, aScope);
   if (NS_WARN_IF(!registration)) {
-    return NS_ERROR_FAILURE;
+    return;
   }
 
-  if (registration->GetInstalling() &&
-      (registration->GetInstalling()->ID() == aServiceWorkerID)) {
-    registration->GetInstalling()->SetSkipWaitingFlag();
-  } else if (registration->GetWaiting() &&
-             (registration->GetWaiting()->ID() == aServiceWorkerID)) {
-    registration->GetWaiting()->SetSkipWaitingFlag();
-    if (registration->GetWaiting()->State() == ServiceWorkerState::Installed) {
-      registration->TryToActivateAsync();
-    }
-  } else {
-    NS_WARNING("Failed to set skipWaiting flag, no matching worker.");
-    return NS_ERROR_FAILURE;
+  RefPtr<ServiceWorkerInfo> worker =
+    registration->GetServiceWorkerInfoById(aServiceWorkerID);
+
+  if (NS_WARN_IF(!worker)) {
+    return;
   }
 
-  return NS_OK;
+  worker->SetSkipWaitingFlag();
+
+  if (worker->State() == ServiceWorkerState::Installed) {
+    registration->TryToActivateAsync();
+  }
 }
 
 void
 ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration)
 {
   AssertIsOnMainThread();
   for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
     if (iter.UserData() != aRegistration) {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -250,17 +250,17 @@ public:
 
   void
   MaybeClaimClient(nsIDocument* aDocument,
                    ServiceWorkerRegistrationInfo* aWorkerRegistration);
 
   nsresult
   ClaimClients(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aId);
 
-  nsresult
+  void
   SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope,
                      uint64_t aServiceWorkerID);
 
   static already_AddRefed<ServiceWorkerManager>
   GetInstance();
 
  void
  LoadRegistration(const ServiceWorkerRegistrationData& aRegistration);
@@ -289,16 +289,19 @@ public:
   SendPushEvent(const nsACString& aOriginAttributes,
                 const nsACString& aScope,
                 const nsAString& aMessageId,
                 const Maybe<nsTArray<uint8_t>>& aData);
 
   nsresult
   NotifyUnregister(nsIPrincipal* aPrincipal, const nsAString& aScope);
 
+  void
+  WorkerIsIdle(ServiceWorkerInfo* aWorker);
+
 private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
   void
   Init();
 
   already_AddRefed<ServiceWorkerJobQueue>
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -99,33 +99,70 @@ ServiceWorkerPrivate::~ServiceWorkerPriv
   MOZ_ASSERT(!mWorkerPrivate);
   MOZ_ASSERT(!mTokenCount);
   MOZ_ASSERT(!mInfo);
   MOZ_ASSERT(mSupportsArray.IsEmpty());
 
   mIdleWorkerTimer->Cancel();
 }
 
+namespace {
+
+class MessageWaitUntilHandler final : public PromiseNativeHandler
+{
+ nsMainThreadPtrHandle<nsISupports> mKeepAliveToken;
+
+  ~MessageWaitUntilHandler()
+  {
+  }
+
+public:
+  explicit MessageWaitUntilHandler(const nsMainThreadPtrHandle<nsISupports>& aKeepAliveToken)
+    : mKeepAliveToken(aKeepAliveToken)
+  {
+    MOZ_ASSERT(mKeepAliveToken);
+  }
+
+  void
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    mKeepAliveToken = nullptr;
+  }
+
+  void
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    mKeepAliveToken = nullptr;
+  }
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+};
+
+NS_IMPL_ISUPPORTS0(MessageWaitUntilHandler)
+
+} // anonymous namespace
+
 nsresult
 ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
                                        JS::Handle<JS::Value> aMessage,
                                        const Optional<Sequence<JS::Value>>& aTransferable,
                                        UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
 {
   ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr));
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
-  MOZ_ASSERT(mKeepAliveToken);
   nsMainThreadPtrHandle<nsISupports> token(
-    new nsMainThreadPtrHolder<nsISupports>(mKeepAliveToken));
+    new nsMainThreadPtrHolder<nsISupports>(CreateEventKeepAliveToken()));
+
+  RefPtr<PromiseNativeHandler> handler = new MessageWaitUntilHandler(token);
 
   mWorkerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
-                                             Move(aClientInfo), token,
+                                             Move(aClientInfo), handler,
                                              rv);
   return rv.StealNSResult();
 }
 
 namespace {
 
 class CheckScriptEvaluationWithCallback final : public WorkerRunnable
 {
@@ -185,19 +222,19 @@ private:
 } // anonymous namespace
 
 nsresult
 ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback)
 {
   nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  MOZ_ASSERT(mKeepAliveToken);
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r = new CheckScriptEvaluationWithCallback(mWorkerPrivate,
-                                                                   mKeepAliveToken,
+                                                                   token,
                                                                    aCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -675,21 +712,21 @@ LifecycleEventWorkerRunnable::DispatchLi
 nsresult
 ServiceWorkerPrivate::SendLifeCycleEvent(const nsAString& aEventType,
                                          LifeCycleEventCallback* aCallback,
                                          nsIRunnable* aLoadFailure)
 {
   nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, aLoadFailure);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  MOZ_ASSERT(mKeepAliveToken);
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r = new LifecycleEventWorkerRunnable(mWorkerPrivate,
-                                                                mKeepAliveToken,
-                                                                aEventType,
-                                                                aCallback);
+                                                              token,
+                                                              aEventType,
+                                                              aCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 #ifndef MOZ_SIMPLEPUSH
@@ -866,23 +903,23 @@ ServiceWorkerPrivate::SendPushEvent(cons
                                     ServiceWorkerRegistrationInfo* aRegistration)
 {
 #ifdef MOZ_SIMPLEPUSH
   return NS_ERROR_NOT_AVAILABLE;
 #else
   nsresult rv = SpawnWorkerIfNeeded(PushEvent, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  MOZ_ASSERT(mKeepAliveToken);
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
 
   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
     new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(aRegistration, false));
 
   RefPtr<WorkerRunnable> r = new SendPushEventRunnable(mWorkerPrivate,
-                                                       mKeepAliveToken,
+                                                       token,
                                                        aMessageId,
                                                        aData,
                                                        regInfo);
 
   if (mInfo->State() == ServiceWorkerState::Activating) {
     mPendingFunctionalEvents.AppendElement(r.forget());
     return NS_OK;
   }
@@ -901,19 +938,19 @@ nsresult
 ServiceWorkerPrivate::SendPushSubscriptionChangeEvent()
 {
 #ifdef MOZ_SIMPLEPUSH
   return NS_ERROR_NOT_AVAILABLE;
 #else
   nsresult rv = SpawnWorkerIfNeeded(PushSubscriptionChangeEvent, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  MOZ_ASSERT(mKeepAliveToken);
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r =
-    new SendPushSubscriptionChangeEventRunnable(mWorkerPrivate, mKeepAliveToken);
+    new SendPushSubscriptionChangeEventRunnable(mWorkerPrivate, token);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 #endif // MOZ_SIMPLEPUSH
 }
 
@@ -1191,18 +1228,20 @@ ServiceWorkerPrivate::SendNotificationEv
   } else {
     MOZ_ASSERT_UNREACHABLE("Invalid notification event name");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = SpawnWorkerIfNeeded(why, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
+
   RefPtr<WorkerRunnable> r =
-    new SendNotificationEventRunnable(mWorkerPrivate, mKeepAliveToken,
+    new SendNotificationEventRunnable(mWorkerPrivate, token,
                                       aEventName, aID, aTitle, aDir, aLang,
                                       aBody, aTag, aIcon, aData, aBehavior,
                                       aScope);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
@@ -1593,18 +1632,20 @@ ServiceWorkerPrivate::SendFetchEvent(nsI
   MOZ_ASSERT(swm);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     swm->GetRegistration(mInfo->GetPrincipal(), mInfo->Scope());
 
   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
     new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(registration, false));
 
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
+
   RefPtr<FetchEventRunnable> r =
-    new FetchEventRunnable(mWorkerPrivate, mKeepAliveToken, handle,
+    new FetchEventRunnable(mWorkerPrivate, token, handle,
                            mInfo->ScriptSpec(), regInfo,
                            aDocumentId, aIsReload);
   rv = r->Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mInfo->State() == ServiceWorkerState::Activating) {
@@ -1738,17 +1779,17 @@ ServiceWorkerPrivate::RemoveISupports(ns
 }
 
 void
 ServiceWorkerPrivate::TerminateWorker()
 {
   AssertIsOnMainThread();
 
   mIdleWorkerTimer->Cancel();
-  mKeepAliveToken = nullptr;
+  mIdleKeepAliveToken = nullptr;
   if (mWorkerPrivate) {
     if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
       if (os) {
         os->NotifyObservers(this, "service-worker-shutdown", nullptr);
       }
     }
 
@@ -1853,28 +1894,35 @@ ServiceWorkerPrivate::DetachDebugger()
     } else {
       TerminateWorker();
     }
   }
 
   return NS_OK;
 }
 
+bool
+ServiceWorkerPrivate::IsIdle() const
+{
+  AssertIsOnMainThread();
+  return mTokenCount == 0 || (mTokenCount == 1 && mIdleKeepAliveToken);
+}
+
 /* static */ void
 ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer, void* aPrivate)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrivate);
 
   RefPtr<ServiceWorkerPrivate> swp = static_cast<ServiceWorkerPrivate*>(aPrivate);
 
   MOZ_ASSERT(aTimer == swp->mIdleWorkerTimer, "Invalid timer!");
 
   // Release ServiceWorkerPrivate's token, since the grace period has ended.
-  swp->mKeepAliveToken = nullptr;
+  swp->mIdleKeepAliveToken = nullptr;
 
   if (swp->mWorkerPrivate) {
     // If we still have a workerPrivate at this point it means there are pending
     // waitUntil promises. Wait a bit more until we forcibly terminate the
     // worker.
     uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_extended_timeout");
     DebugOnly<nsresult> rv =
       swp->mIdleWorkerTimer->InitWithFuncCallback(ServiceWorkerPrivate::TerminateWorkerCallback,
@@ -1916,18 +1964,18 @@ ServiceWorkerPrivate::RenewKeepAliveToke
 
   // If there is at least one debugger attached to the worker, the idle worker
   // timeout was canceled when the first debugger attached to the worker. It
   // should not be reset until the last debugger detaches from the worker.
   if (!mDebuggerCount) {
     ResetIdleTimeout();
   }
 
-  if (!mKeepAliveToken) {
-    mKeepAliveToken = new KeepAliveToken(this);
+  if (!mIdleKeepAliveToken) {
+    mIdleKeepAliveToken = new KeepAliveToken(this);
   }
 }
 
 void
 ServiceWorkerPrivate::ResetIdleTimeout()
 {
   uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_timeout");
   DebugOnly<nsresult> rv =
@@ -1948,12 +1996,27 @@ void
 ServiceWorkerPrivate::ReleaseToken()
 {
   AssertIsOnMainThread();
 
   MOZ_ASSERT(mTokenCount > 0);
   --mTokenCount;
   if (!mTokenCount) {
     TerminateWorker();
+  } else if (IsIdle()) {
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (swm) {
+      swm->WorkerIsIdle(mInfo);
+    }
   }
 }
 
+already_AddRefed<KeepAliveToken>
+ServiceWorkerPrivate::CreateEventKeepAliveToken()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mWorkerPrivate);
+  MOZ_ASSERT(mIdleKeepAliveToken);
+  RefPtr<KeepAliveToken> ref = new KeepAliveToken(this);
+  return ref.forget();
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -141,16 +141,19 @@ public:
   GetDebugger(nsIWorkerDebugger** aResult);
 
   nsresult
   AttachDebugger();
 
   nsresult
   DetachDebugger();
 
+  bool
+  IsIdle() const;
+
 private:
   enum WakeUpReason {
     FetchEvent = 0,
     PushEvent,
     PushSubscriptionChangeEvent,
     MessageEvent,
     NotificationClickEvent,
     NotificationCloseEvent,
@@ -181,31 +184,34 @@ private:
   // if the script loader failed for some reason, but can be null.
   nsresult
   SpawnWorkerIfNeeded(WakeUpReason aWhy,
                       nsIRunnable* aLoadFailedRunnable,
                       nsILoadGroup* aLoadGroup = nullptr);
 
   ~ServiceWorkerPrivate();
 
+  already_AddRefed<KeepAliveToken>
+  CreateEventKeepAliveToken();
+
   // The info object owns us. It is possible to outlive it for a brief period
   // of time if there are pending waitUntil promises, in which case it
   // will be null and |SpawnWorkerIfNeeded| will always fail.
   ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
 
   // The WorkerPrivate object can only be closed by this class or by the
   // RuntimeService class if gecko is shutting down. Closing the worker
   // multiple times is OK, since the second attempt will be a no-op.
   RefPtr<WorkerPrivate> mWorkerPrivate;
 
   nsCOMPtr<nsITimer> mIdleWorkerTimer;
 
   // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
   // worker a grace period after each event.
-  RefPtr<KeepAliveToken> mKeepAliveToken;
+  RefPtr<KeepAliveToken> mIdleKeepAliveToken;
 
   uint64_t mDebuggerCount;
 
   uint64_t mTokenCount;
 
   // Meant for keeping objects alive while handling requests from the worker
   // on the main thread. Access to this array is provided through
   // |StoreISupports| and |RemoveISupports|. Note that the array is also
--- a/dom/workers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/workers/ServiceWorkerRegistrationInfo.cpp
@@ -39,16 +39,20 @@ public:
   }
 };
 
 } // anonymous namespace
 
 void
 ServiceWorkerRegistrationInfo::Clear()
 {
+  if (mEvaluatingWorker) {
+    mEvaluatingWorker = nullptr;
+  }
+
   if (mInstallingWorker) {
     mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
     mInstallingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mInstallingWorker = nullptr;
     // FIXME(nsm): Abort any inflight requests from installing worker.
   }
 
   if (mWaitingWorker) {
@@ -181,18 +185,22 @@ ServiceWorkerRegistrationInfo::RemoveLis
   mListeners.RemoveElement(aListener);
 
   return NS_OK;
 }
 
 already_AddRefed<ServiceWorkerInfo>
 ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId)
 {
+  AssertIsOnMainThread();
+
   RefPtr<ServiceWorkerInfo> serviceWorker;
-  if (mInstallingWorker && mInstallingWorker->ID() == aId) {
+  if (mEvaluatingWorker && mEvaluatingWorker->ID() == aId) {
+    serviceWorker = mEvaluatingWorker;
+  } else if (mInstallingWorker && mInstallingWorker->ID() == aId) {
     serviceWorker = mInstallingWorker;
   } else if (mWaitingWorker && mWaitingWorker->ID() == aId) {
     serviceWorker = mWaitingWorker;
   } else if (mActiveWorker && mActiveWorker->ID() == aId) {
     serviceWorker = mActiveWorker;
   }
 
   return serviceWorker.forget();
@@ -202,24 +210,26 @@ void
 ServiceWorkerRegistrationInfo::TryToActivateAsync()
 {
   MOZ_ALWAYS_SUCCEEDS(
     NS_DispatchToMainThread(NewRunnableMethod(this,
                                               &ServiceWorkerRegistrationInfo::TryToActivate)));
 }
 
 /*
- * TryToActivate should not be called directly, use TryToACtivateAsync instead.
+ * TryToActivate should not be called directly, use TryToActivateAsync instead.
  */
 void
 ServiceWorkerRegistrationInfo::TryToActivate()
 {
-  if (!IsControllingDocuments() ||
-      // Waiting worker will be removed if the registration is removed
-      (mWaitingWorker && mWaitingWorker->SkipWaitingFlag())) {
+  AssertIsOnMainThread();
+  bool controlling = IsControllingDocuments();
+  bool skipWaiting = mWaitingWorker && mWaitingWorker->SkipWaitingFlag();
+  bool idle = !mActiveWorker || mActiveWorker->WorkerPrivate()->IsIdle();
+  if (idle && (!controlling || skipWaiting)) {
     Activate();
   }
 }
 
 void
 ServiceWorkerRegistrationInfo::Activate()
 {
   if (!mWaitingWorker) {
@@ -359,16 +369,23 @@ ServiceWorkerRegistrationInfo::CheckAndC
                 IsLastUpdateCheckTimeOverOneDay());
 
   mUpdateState = NoUpdate;
 
   return result;
 }
 
 ServiceWorkerInfo*
+ServiceWorkerRegistrationInfo::GetEvaluating() const
+{
+  AssertIsOnMainThread();
+  return mEvaluatingWorker;
+}
+
+ServiceWorkerInfo*
 ServiceWorkerRegistrationInfo::GetInstalling() const
 {
   AssertIsOnMainThread();
   return mInstallingWorker;
 }
 
 ServiceWorkerInfo*
 ServiceWorkerRegistrationInfo::GetWaiting() const
@@ -380,39 +397,63 @@ ServiceWorkerRegistrationInfo::GetWaitin
 ServiceWorkerInfo*
 ServiceWorkerRegistrationInfo::GetActive() const
 {
   AssertIsOnMainThread();
   return mActiveWorker;
 }
 
 void
+ServiceWorkerRegistrationInfo::SetEvaluating(ServiceWorkerInfo* aServiceWorker)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aServiceWorker);
+  MOZ_ASSERT(!mEvaluatingWorker);
+  MOZ_ASSERT(!mInstallingWorker);
+  MOZ_ASSERT(mWaitingWorker != aServiceWorker);
+  MOZ_ASSERT(mActiveWorker != aServiceWorker);
+
+  mEvaluatingWorker = aServiceWorker;
+}
+
+void
+ServiceWorkerRegistrationInfo::ClearEvaluating()
+{
+  AssertIsOnMainThread();
+
+  if (!mEvaluatingWorker) {
+    return;
+  }
+
+  mEvaluatingWorker->UpdateState(ServiceWorkerState::Redundant);
+  mEvaluatingWorker = nullptr;
+}
+
+void
 ServiceWorkerRegistrationInfo::ClearInstalling()
 {
   AssertIsOnMainThread();
 
   if (!mInstallingWorker) {
     return;
   }
 
   mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
   mInstallingWorker = nullptr;
   NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER);
 }
 
 void
-ServiceWorkerRegistrationInfo::SetInstalling(ServiceWorkerInfo* aServiceWorker)
+ServiceWorkerRegistrationInfo::TransitionEvaluatingToInstalling()
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(aServiceWorker);
+  MOZ_ASSERT(mEvaluatingWorker);
   MOZ_ASSERT(!mInstallingWorker);
-  MOZ_ASSERT(mWaitingWorker != aServiceWorker);
-  MOZ_ASSERT(mActiveWorker != aServiceWorker);
 
-  mInstallingWorker = aServiceWorker;
+  mInstallingWorker = mEvaluatingWorker.forget();
   mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
   NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER);
 }
 
 void
 ServiceWorkerRegistrationInfo::TransitionInstallingToWaiting()
 {
   AssertIsOnMainThread();
--- a/dom/workers/ServiceWorkerRegistrationInfo.h
+++ b/dom/workers/ServiceWorkerRegistrationInfo.h
@@ -22,16 +22,17 @@ class ServiceWorkerRegistrationInfo fina
   {
     NoUpdate,
     NeedTimeCheckAndUpdate,
     NeedUpdate
   } mUpdateState;
 
   uint64_t mLastUpdateCheckTime;
 
+  RefPtr<ServiceWorkerInfo> mEvaluatingWorker;
   RefPtr<ServiceWorkerInfo> mActiveWorker;
   RefPtr<ServiceWorkerInfo> mWaitingWorker;
   RefPtr<ServiceWorkerInfo> mInstallingWorker;
 
   virtual ~ServiceWorkerRegistrationInfo();
 
 public:
   NS_DECL_ISUPPORTS
@@ -117,37 +118,49 @@ public:
 
   void
   MaybeScheduleUpdate();
 
   bool
   CheckAndClearIfUpdateNeeded();
 
   ServiceWorkerInfo*
+  GetEvaluating() const;
+
+  ServiceWorkerInfo*
   GetInstalling() const;
 
   ServiceWorkerInfo*
   GetWaiting() const;
 
   ServiceWorkerInfo*
   GetActive() const;
 
+  // Set the given worker as the evaluating service worker.  The worker
+  // state is not changed.
+  void
+  SetEvaluating(ServiceWorkerInfo* aServiceWorker);
+
+  // Remove an existing evaluating worker, if present.  The worker will
+  // be transitioned to the Redundant state.
+  void
+  ClearEvaluating();
+
   // Remove an existing installing worker, if present.  The worker will
   // be transitioned to the Redundant state.
   void
   ClearInstalling();
 
-  // Set a new installing worker.  This may only be called if there is no
-  // existing installing worker.  The worker is transitioned to the Installing
-  // state.
+  // Transition the current evaluating worker to be the installing worker.  The
+  // worker's state is update to Installing.
   void
-  SetInstalling(ServiceWorkerInfo* aServiceWorker);
+  TransitionEvaluatingToInstalling();
 
   // Transition the current installing worker to be the waiting worker.  The
-  // workers state is updated to Installed.
+  // worker's state is updated to Installed.
   void
   TransitionInstallingToWaiting();
 
   // Override the current active worker.  This is used during browser
   // initialization to load persisted workers.  Its also used to propagate
   // active workers across child processes in e10s.  This second use will
   // go away once the ServiceWorkerManager moves to the parent process.
   // The worker is transitioned to the Activated state.
--- a/dom/workers/ServiceWorkerUpdateJob.cpp
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -205,31 +205,25 @@ ServiceWorkerUpdateJob::FailUpdateJob(Er
   // step 12 of the Install algorithm.
   //
   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
   //
   // The spec currently only runs this after an install event fails,
   // but we must handle many more internal errors.  So we check for
   // cleanup on every non-successful exit.
   if (mRegistration) {
-    if (mServiceWorker) {
-      mServiceWorker->UpdateState(ServiceWorkerState::Redundant);
-      serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
-                                           mServiceWorker->CacheName());
-    }
-
+    mRegistration->ClearEvaluating();
     mRegistration->ClearInstalling();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (swm) {
       swm->MaybeRemoveRegistration(mRegistration);
     }
   }
 
-  mServiceWorker = nullptr;
   mRegistration = nullptr;
 
   Finish(aRv);
 }
 
 void
 ServiceWorkerUpdateJob::FailUpdateJob(nsresult aRv)
 {
@@ -413,26 +407,28 @@ ServiceWorkerUpdateJob::ComparisonResult
     Finish(NS_OK);
     return;
   }
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
 
   // Begin step 7 of the Update algorithm to evaluate the new script.
 
-  MOZ_ASSERT(!mServiceWorker);
-  mServiceWorker = new ServiceWorkerInfo(mRegistration->mPrincipal,
-                                         mRegistration->mScope,
-                                         mScriptSpec, aNewCacheName);
+  RefPtr<ServiceWorkerInfo> sw =
+    new ServiceWorkerInfo(mRegistration->mPrincipal,
+                          mRegistration->mScope,
+                          mScriptSpec, aNewCacheName);
+
+  mRegistration->SetEvaluating(sw);
 
   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
       new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(this));
   RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
 
-  ServiceWorkerPrivate* workerPrivate = mServiceWorker->WorkerPrivate();
+  ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate();
   MOZ_ASSERT(workerPrivate);
   rv = workerPrivate->CheckScriptEvaluation(callback);
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 }
@@ -470,19 +466,17 @@ ServiceWorkerUpdateJob::Install()
   MOZ_ASSERT(!Canceled());
 
   MOZ_ASSERT(!mRegistration->GetInstalling());
 
   // Begin step 2 of the Install algorithm.
   //
   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
 
-  MOZ_ASSERT(mServiceWorker);
-  mRegistration->SetInstalling(mServiceWorker);
-  mServiceWorker = nullptr;
+  mRegistration->TransitionEvaluatingToInstalling();
 
   // Step 6 of the Install algorithm resolving the job promise.
   InvokeResultCallbacks(NS_OK);
 
   // The job promise cannot be rejected after this point, but the job can
   // still fail; e.g. if the install event handler throws, etc.
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
--- a/dom/workers/ServiceWorkerUpdateJob.h
+++ b/dom/workers/ServiceWorkerUpdateJob.h
@@ -88,16 +88,15 @@ private:
   Install();
 
   // Utility method called after the install event is handled.
   void
   ContinueAfterInstallEvent(bool aInstallEventSuccess);
 
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-  RefPtr<ServiceWorkerInfo> mServiceWorker;
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkerupdatejob_h
--- a/dom/workers/ServiceWorkerWindowClient.cpp
+++ b/dom/workers/ServiceWorkerWindowClient.cpp
@@ -469,17 +469,17 @@ private:
     }
 
     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
     nsresult rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    loadInfo->SetOwner(aPrincipal);
+    loadInfo->SetTriggeringPrincipal(aPrincipal);
     loadInfo->SetReferrer(doc->GetOriginalURI());
     loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
     loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
     loadInfo->SetSourceDocShell(docShell);
     rv =
       docShell->LoadURI(aUrl, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
 
     if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -54,16 +54,17 @@
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseDebugging.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/Preferences.h"
@@ -659,35 +660,33 @@ private:
 };
 
 class MessageEventRunnable final : public WorkerRunnable
                                  , public StructuredCloneHolder
 {
   // This is only used for messages dispatched to a service worker.
   UniquePtr<ServiceWorkerClientInfo> mEventSource;
 
-  // This is only used to hold service workers alive while dispatching the
-  // message event.
-  nsMainThreadPtrHandle<nsISupports> mKeepAliveToken;
+  RefPtr<PromiseNativeHandler> mHandler;
 
 public:
   MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
                        TargetAndBusyBehavior aBehavior)
   : WorkerRunnable(aWorkerPrivate, aBehavior)
   , StructuredCloneHolder(CloningSupported, TransferringSupported,
                           SameProcessDifferentThread)
   {
   }
 
   void
   SetServiceWorkerData(UniquePtr<ServiceWorkerClientInfo>&& aSource,
-                       const nsMainThreadPtrHandle<nsISupports>& aKeepAliveToken)
+                       PromiseNativeHandler* aHandler)
   {
     mEventSource = Move(aSource);
-    mKeepAliveToken = aKeepAliveToken;
+    mHandler = aHandler;
   }
 
   bool
   DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                    DOMEventTargetHelper* aTarget, bool aIsMainThread)
   {
     nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(aTarget->GetParentObject());
 
@@ -736,42 +735,43 @@ public:
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return false;
     }
 
     nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
 
     nsCOMPtr<nsIDOMEvent> domEvent;
+    RefPtr<ExtendableMessageEvent> extendableEvent;
     // For messages dispatched to service worker, use ExtendableMessageEvent
     // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#extendablemessage-event-section
     if (mEventSource) {
       RefPtr<ServiceWorkerClient> client =
         new ServiceWorkerWindowClient(aTarget, *mEventSource);
 
       RootedDictionary<ExtendableMessageEventInit> init(aCx);
 
       init.mBubbles = false;
       init.mCancelable = false;
 
       init.mData = messageData;
       init.mPorts.Construct();
       init.mPorts.Value().SetNull();
 
       ErrorResult rv;
-      RefPtr<ExtendableMessageEvent> event = ExtendableMessageEvent::Constructor(
+      extendableEvent = ExtendableMessageEvent::Constructor(
         aTarget, NS_LITERAL_STRING("message"), init, rv);
       if (NS_WARN_IF(rv.Failed())) {
         rv.SuppressException();
         return false;
       }