merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 28 Jul 2016 17:43:03 +0200
changeset 307065 9ec789c0ee5bd3a5e765513c21027fdad953b022
parent 306916 afb47dfb71ed76d1bf86fe0101cda1a5e6038863 (current diff)
parent 307064 1a7af0fca900e297575b413fd1b2707f44ea2c41 (diff)
child 307066 2d6fced8b624ce179cef1053d9e3952dae7c726b
child 307084 54eb32559af3c72a14593fdcea471ecae7001da2
child 307144 e8ca183fb7ffff634610fcd7783959fa20a4c3a9
push id20145
push usercbook@mozilla.com
push dateThu, 28 Jul 2016 15:45:29 +0000
treeherderfx-team@2d6fced8b624 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone50.0a1
merge mozilla-inbound to mozilla-central a=merge
browser/components/extensions/test/browser/browser_ext_history.js
dom/ipc/ContentChild.cpp
layout/style/nsCSSProps.cpp
modules/libpref/init/all.js
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
toolkit/components/extensions/test/mochitest/file_download.html
toolkit/components/extensions/test/mochitest/file_download.txt
toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_download.html
toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html
toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_search.html
toolkit/components/extensions/test/mochitest/test_ext_alarms.html
toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html
toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html
toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html
toolkit/components/extensions/test/mochitest/test_ext_background_sub_windows.html
toolkit/components/extensions/test/mochitest/test_ext_background_window_properties.html
toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html
toolkit/components/extensions/test/mochitest/test_ext_downloads.html
toolkit/components/extensions/test/mochitest/test_ext_extension.html
toolkit/components/extensions/test/mochitest/test_ext_idle.html
toolkit/components/extensions/test/mochitest/test_ext_localStorage.html
toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html
toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html
toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html
toolkit/components/extensions/test/mochitest/test_ext_simple.html
toolkit/components/extensions/test/mochitest/test_ext_storage.html
--- 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/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.