Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 02 Sep 2016 13:17:30 -0700
changeset 312476 57fc4d13d23fb1a473882826ccad08811cd03a4a
parent 312475 38d0defa2db77fa8bf209cf60bde4232896660cc (current diff)
parent 312444 2fd65026fd36ca156b7179e448bf752fbfd7d5f4 (diff)
child 312477 63d190efe42e5e4984180d315e16b70f6d99618c
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
Merge inbound to m-c a=merge
browser/components/contextualidentity/test/browser/browser_newtabButton.js
browser/components/search/test/browser_eBay.js
browser/components/search/test/browser_eBay_behavior.js
browser/locales/en-US/searchplugins/eBay.xml
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/bindings/parser/tests/test_array.py
dom/bindings/parser/tests/test_array_of_interface.py
dom/events/EventStateManager.cpp
dom/ipc/ContentParent.cpp
dom/simplepush/Push.js
dom/simplepush/Push.manifest
dom/simplepush/PushService.jsm
dom/simplepush/PushServiceLauncher.js
dom/simplepush/moz.build
dom/simplepush/test/mochitest.ini
dom/simplepush/test/test_permissions.html
dom/simplepush/test/test_prefs.html
dom/simplepush/test/test_register.html
dom/webidl/SimplePushManager.webidl
gfx/gl/GLContextProviderGLX.cpp
layout/base/ServoRestyleManager.cpp
old-configure.in
testing/web-platform/meta/dom/nodes/DOMImplementation-createDocument.html.ini
testing/web-platform/meta/dom/nodes/Document-createElementNS.html.ini
widget/windows/nsWindow.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1299332 for the relanding of Bug 1299276.
+Bug 1289951 maybe needed a clobber to fix xpcshell tests?
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -85,20 +85,17 @@ EnableLogging(const char* aModulesStr)
     if (*token == ',')
       token++; // skip ',' char
   }
 }
 
 static void
 LogDocURI(nsIDocument* aDocumentNode)
 {
-  nsIURI* uri = aDocumentNode->GetDocumentURI();
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("uri: %s", spec.get());
+  printf("uri: %s", aDocumentNode->GetDocumentURI()->GetSpecOrDefault().get());
 }
 
 static void
 LogDocShellState(nsIDocument* aDocumentNode)
 {
   printf("docshell busy: ");
 
   nsAutoCString docShellBusy;
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -122,17 +122,17 @@ nsTextEquivUtils::AppendTextEquivFromTex
     if (parentContent) {
       nsIFrame *frame = parentContent->GetPrimaryFrame();
       if (frame) {
         // If this text is inside a block level frame (as opposed to span
         // level), we need to add spaces around that block's text, so we don't
         // get words jammed together in final name.
         const nsStyleDisplay* display = frame->StyleDisplay();
         if (display->IsBlockOutsideStyle() ||
-            display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
+            display->mDisplay == StyleDisplay::TableCell) {
           isHTMLBlock = true;
           if (!aString->IsEmpty()) {
             aString->Append(char16_t(' '));
           }
         }
       }
     }
     
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -85,25 +85,16 @@
             {
               // xul:toolbarbutton ("Close current tab")
               role: ROLE_PUSHBUTTON,
               children: []
             }
             );
         } else {
           SimpleTest.ok(true, "Testing Firefox tabbrowser UI.");
-          let newTabChildren = [];
-          if (SpecialPowers.getBoolPref("privacy.userContext.enabled")) {
-            newTabChildren = [
-              {
-                role: ROLE_MENUPOPUP,
-                children: []
-              }
-            ];
-          }
 
           // NB: The (3) buttons are not visible, unless manually hovered,
           //     probably due to size reduction in this test.
           tabsAccTree.children.splice(0, 0,
             {
               // xul:tab ("about:")
               role: ROLE_PAGETAB,
               children: [
@@ -123,17 +114,17 @@
                   role: ROLE_PUSHBUTTON,
                   children: []
                 }
               ]
             },
             {
               // xul:toolbarbutton ("Open a new tab")
               role: ROLE_PUSHBUTTON,
-              children: newTabChildren
+              children: []
             }
             // "List all tabs" dropdown
             // XXX: This child(?) is not present in this test.
             //      I'm not sure why (though probably expected).
             );
         }
 
         testAccessibleTree(tabBrowser().tabContainer, tabsAccTree);
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -284,20 +284,20 @@ exports.testActiveWindow = function*(ass
     onFocus(rawWindow3).then(resolve);
     window3.activate();
     assert.pass("activating window3");
   });
 
   assert.equal(windows.activeWindow.title, window3.title, "Correct active window - 3");
 
   yield close(rawWindow2);
-  assert.equal(rawWindow2.closed, true, 'window 2 is closed');
+  yield close(rawWindow3);
 
-  yield close(rawWindow3);
-  assert.equal(rawWindow3.closed, true, 'window 3 is closed');
+  assert.equal(windows.length, 1, "Correct number of browser windows");
+  assert.equal(window.closed, false, "Original window is still open");
 };
 
 exports.testTrackWindows = function(assert, done) {
   let windows = [];
   let actions = [];
 
   let expects = [
     "activate 0", "global activate 0", "deactivate 0", "global deactivate 0",
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -401,50 +401,16 @@ pref("dom.phonenumber.substringmatching.
 pref("dom.phonenumber.substringmatching.CO", 10);
 pref("dom.phonenumber.substringmatching.VE", 7);
 pref("dom.phonenumber.substringmatching.CL", 8);
 pref("dom.phonenumber.substringmatching.PE", 7);
 
 // WebAlarms
 pref("dom.mozAlarms.enabled", true);
 
-// SimplePush
-pref("services.push.enabled", true);
-// Debugging enabled.
-pref("services.push.debug", false);
-// Is the network connection allowed to be up?
-// This preference should be used in UX to enable/disable push.
-pref("services.push.connection.enabled", true);
-// serverURL to be assigned by services team
-pref("services.push.serverURL", "wss://push.services.mozilla.com/");
-pref("services.push.userAgentID", "");
-// Exponential back-off start is 5 seconds like in HTTP/1.1.
-// Maximum back-off is pingInterval.
-pref("services.push.retryBaseInterval", 5000);
-// Interval at which to ping PushServer to check connection status. In
-// milliseconds. If no reply is received within requestTimeout, the connection
-// is considered closed.
-pref("services.push.pingInterval", 1800000); // 30 minutes
-// How long before a DOMRequest errors as timeout
-pref("services.push.requestTimeout", 10000);
-pref("services.push.pingInterval.default", 180000);// 3 min
-pref("services.push.pingInterval.mobile", 180000); // 3 min
-pref("services.push.pingInterval.wifi", 180000);  // 3 min
-// Adaptive ping
-pref("services.push.adaptive.enabled", true);
-pref("services.push.adaptive.lastGoodPingInterval", 180000);// 3 min
-pref("services.push.adaptive.lastGoodPingInterval.mobile", 180000);// 3 min
-pref("services.push.adaptive.lastGoodPingInterval.wifi", 180000);// 3 min
-// Valid gap between the biggest good ping and the bad ping
-pref("services.push.adaptive.gap", 60000); // 1 minute
-// We limit the ping to this maximum value
-pref("services.push.adaptive.upperLimit", 1740000); // 29 min
-// enable udp wakeup support
-pref("services.push.udp.wakeupEnabled", true);
-
 // NetworkStats
 #ifdef MOZ_WIDGET_GONK
 pref("dom.mozNetworkStats.enabled", true);
 pref("dom.webapps.firstRunWithSIM", true);
 #endif
 
 // ResourceStats
 #ifdef MOZ_WIDGET_GONK
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -31,17 +31,16 @@ fi
 MOZ_USE_NATIVE_POPUP_WINDOWS=1
 
 MOZ_XULRUNNER=
 
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
 
 MOZ_TIME_MANAGER=1
 
-MOZ_SIMPLEPUSH=1
 MOZ_TOOLKIT_SEARCH=
 MOZ_B2G=1
 
 MOZ_JSDOWNLOADS=1
 
 MOZ_BUNDLED_FONTS=1
 
 export JS_GC_SMALL_CHUNK_SIZE=1
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -599,21 +599,17 @@
 @RESPATH@/components/XULStore.js
 @RESPATH@/components/XULStore.manifest
 @RESPATH@/components/Webapps.js
 @RESPATH@/components/Webapps.manifest
 @RESPATH@/components/AppsService.js
 @RESPATH@/components/AppsService.manifest
 @RESPATH@/components/Push.js
 @RESPATH@/components/Push.manifest
-#ifdef MOZ_SIMPLEPUSH
-@RESPATH@/components/PushServiceLauncher.js
-#else
 @RESPATH@/components/PushComponents.js
-#endif
 
 @RESPATH@/components/nsDOMIdentity.js
 @RESPATH@/components/nsIDService.js
 @RESPATH@/components/Identity.manifest
 
 @RESPATH@/components/SystemMessageInternal.js
 @RESPATH@/components/SystemMessageManager.js
 @RESPATH@/components/SystemMessageCache.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -114,26 +114,16 @@ tabbrowser {
 #TabsToolbar[customizing="true"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
   visibility: collapse;
 }
 
 #tabbrowser-tabs:not([overflow="true"])[using-closing-tabs-spacer] ~ #alltabs-button {
   visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
 }
 
-.tabs-newtab-button > .toolbarbutton-menu-dropmarker,
-#new-tab-button > .toolbarbutton-menu-dropmarker {
-  display: none;
-}
-
-.tabs-newtab-button > .toolbarbutton-icon,
-#new-tab-button > .toolbarbutton-icon {
-  margin-inline-end: 0;
-}
-
 .tabbrowser-tab {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
 }
 
 .tabbrowser-tab:not([pinned]) {
   -moz-box-flex: 100;
   max-width: 210px;
   min-width: 100px;
@@ -182,17 +172,16 @@ tabbrowser {
   z-index: 2;
   pointer-events: none; /* avoid blocking dragover events on scroll buttons */
 }
 
 .tabbrowser-tabs[movingtab] > .tabbrowser-tab[fadein]:not([selected]) {
   transition: transform 200ms ease-out;
 }
 
-.new-tab-popup,
 #alltabs-popup {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
 }
 
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -256,102 +256,92 @@ function UpdateBackForwardCommands(aWebN
   }
 }
 
 /**
  * Click-and-Hold implementation for the Back and Forward buttons
  * XXXmano: should this live in toolbarbutton.xml?
  */
 function SetClickAndHoldHandlers() {
+  var timer;
+
+  function openMenu(aButton) {
+    cancelHold(aButton);
+    aButton.firstChild.hidden = false;
+    aButton.open = true;
+  }
+
+  function mousedownHandler(aEvent) {
+    if (aEvent.button != 0 ||
+        aEvent.currentTarget.open ||
+        aEvent.currentTarget.disabled)
+      return;
+
+    // Prevent the menupopup from opening immediately
+    aEvent.currentTarget.firstChild.hidden = true;
+
+    aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false);
+    aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false);
+    timer = setTimeout(openMenu, 500, aEvent.currentTarget);
+  }
+
+  function mouseoutHandler(aEvent) {
+    let buttonRect = aEvent.currentTarget.getBoundingClientRect();
+    if (aEvent.clientX >= buttonRect.left &&
+        aEvent.clientX <= buttonRect.right &&
+        aEvent.clientY >= buttonRect.bottom)
+      openMenu(aEvent.currentTarget);
+    else
+      cancelHold(aEvent.currentTarget);
+  }
+
+  function mouseupHandler(aEvent) {
+    cancelHold(aEvent.currentTarget);
+  }
+
+  function cancelHold(aButton) {
+    clearTimeout(timer);
+    aButton.removeEventListener("mouseout", mouseoutHandler, false);
+    aButton.removeEventListener("mouseup", mouseupHandler, false);
+  }
+
+  function clickHandler(aEvent) {
+    if (aEvent.button == 0 &&
+        aEvent.target == aEvent.currentTarget &&
+        !aEvent.currentTarget.open &&
+        !aEvent.currentTarget.disabled) {
+      let cmdEvent = document.createEvent("xulcommandevent");
+      cmdEvent.initCommandEvent("command", true, true, window, 0,
+                                aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
+                                aEvent.metaKey, null);
+      aEvent.currentTarget.dispatchEvent(cmdEvent);
+    }
+  }
+
+  function _addClickAndHoldListenersOnElement(aElm) {
+    aElm.addEventListener("mousedown", mousedownHandler, true);
+    aElm.addEventListener("click", clickHandler, true);
+  }
+
   // Bug 414797: Clone the back/forward buttons' context menu into both buttons.
   let popup = document.getElementById("backForwardMenu").cloneNode(true);
   popup.removeAttribute("id");
   // Prevent the back/forward buttons' context attributes from being inherited.
   popup.setAttribute("context", "");
 
   let backButton = document.getElementById("back-button");
   backButton.setAttribute("type", "menu");
   backButton.appendChild(popup);
-  addClickAndHoldListenersOnElement(backButton);
+  _addClickAndHoldListenersOnElement(backButton);
 
   let forwardButton = document.getElementById("forward-button");
   popup = popup.cloneNode(true);
   forwardButton.setAttribute("type", "menu");
   forwardButton.appendChild(popup);
-  addClickAndHoldListenersOnElement(forwardButton);
-}
-
-let holdTimersMap = new Map();
-function holdMousedownHandler(aEvent) {
-  if (aEvent.button != 0 ||
-      aEvent.currentTarget.open ||
-      aEvent.currentTarget.disabled)
-    return;
-
-  // Prevent the menupopup from opening immediately
-  aEvent.currentTarget.firstChild.hidden = true;
-
-  aEvent.currentTarget.addEventListener("mouseout", holdMouseoutHandler, false);
-  aEvent.currentTarget.addEventListener("mouseup", holdMouseupHandler, false);
-  holdTimersMap.set(aEvent.currentTarget, setTimeout(holdOpenMenu, 500, aEvent.currentTarget));
-}
-
-function holdClickHandler(aEvent) {
-  if (aEvent.button == 0 &&
-      aEvent.target == aEvent.currentTarget &&
-      !aEvent.currentTarget.open &&
-      !aEvent.currentTarget.disabled) {
-    let cmdEvent = document.createEvent("xulcommandevent");
-    cmdEvent.initCommandEvent("command", true, true, window, 0,
-                              aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
-                              aEvent.metaKey, null);
-    aEvent.currentTarget.dispatchEvent(cmdEvent);
-  }
-  // This is here to cancel the XUL default event
-  // dom.click() triggers a command even if there is a click handler
-  // however this can now be prevented with preventDefault().
-  aEvent.preventDefault();
-}
-
-function holdOpenMenu(aButton) {
-  cancelHold(aButton);
-  aButton.firstChild.hidden = false;
-  aButton.open = true;
-}
-
-function holdMouseoutHandler(aEvent) {
-  let buttonRect = aEvent.currentTarget.getBoundingClientRect();
-  if (aEvent.clientX >= buttonRect.left &&
-      aEvent.clientX <= buttonRect.right &&
-      aEvent.clientY >= buttonRect.bottom)
-    holdOpenMenu(aEvent.currentTarget);
-  else
-    cancelHold(aEvent.currentTarget);
-}
-
-function holdMouseupHandler(aEvent) {
-  cancelHold(aEvent.currentTarget);
-}
-
-function cancelHold(aButton) {
-  clearTimeout(holdTimersMap.get(aButton));
-  aButton.removeEventListener("mouseout", holdMouseoutHandler, false);
-  aButton.removeEventListener("mouseup", holdMouseupHandler, false);
-}
-
-function removeClickAndHoldListenersOnElement(aElm) {
-  aElm.removeEventListener("mousedown", holdMousedownHandler, true);
-  aElm.removeEventListener("click", holdClickHandler, true);
-}
-
-function addClickAndHoldListenersOnElement(aElm) {
-  holdTimersMap.delete(aElm);
-
-  aElm.addEventListener("mousedown", holdMousedownHandler, true);
-  aElm.addEventListener("click", holdClickHandler, true);
+  _addClickAndHoldListenersOnElement(forwardButton);
 }
 
 const gSessionHistoryObserver = {
   observe: function(subject, topic, data)
   {
     if (topic != "browser:purge-session-history")
       return;
 
@@ -7386,16 +7376,18 @@ var gIdentityHandler = {
     let stateLabel = document.createElement("label");
     stateLabel.setAttribute("flex", "1");
     stateLabel.setAttribute("class", "identity-popup-permission-state-label");
     stateLabel.textContent = SitePermissions.getStateLabel(
       aPermission.id, aPermission.state, aPermission.inUse || false);
 
     let button = document.createElement("button");
     button.setAttribute("class", "identity-popup-permission-remove-button");
+    let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
+    button.setAttribute("tooltiptext", tooltiptext);
     button.addEventListener("command", () => {
       this._permissionList.removeChild(container);
       if (aPermission.inUse &&
           ["camera", "microphone", "screen"].includes(aPermission.id)) {
         let windowId = this._sharingState.windowId;
         if (aPermission.id == "screen") {
           windowId = "screen:" + windowId;
         } else {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4941,17 +4941,17 @@
                            onmouseover="document.getBindingParent(this)._enterNewTab();"
                            onmouseout="document.getBindingParent(this)._leaveNewTab();"
                            tooltip="dynamic-shortcut-tooltip"/>
         <xul:spacer class="closing-tabs-spacer" anonid="closing-tabs-spacer"
                     style="width: 0;"/>
       </xul:arrowscrollbox>
     </content>
 
-    <implementation implements="nsIDOMEventListener, nsIObserver">
+    <implementation implements="nsIDOMEventListener">
       <constructor>
         <![CDATA[
           this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
 
           var tab = this.firstChild;
           tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
           tab.setAttribute("crop", "end");
           tab.setAttribute("onerror", "this.removeAttribute('image');");
@@ -4960,31 +4960,19 @@
           window.addEventListener("load", this, false);
 
           try {
             this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
           } catch (ex) {
             this._tabAnimationLoggingEnabled = false;
           }
           this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
-          this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
-          Services.prefs.addObserver("privacy.userContext.enabled", this, false);
         ]]>
       </constructor>
 
-      <destructor>
-        <![CDATA[
-          Services.prefs.removeObserver("privacy.userContext.enabled", this);
-        ]]>
-      </destructor>
-
-      <field name="newtabUndoCloseTab" readonly="true">
-        document.getAnonymousElementByAttribute(this, "anonid", "newtab_undoCloseTab");
-      </field>
-
       <field name="tabbrowser" readonly="true">
         document.getElementById(this.getAttribute("tabbrowser"));
       </field>
 
       <field name="tabbox" readonly="true">
         this.tabbrowser.mTabBox;
       </field>
 
@@ -5000,64 +4988,16 @@
 
       <field name="_firstTab">null</field>
       <field name="_lastTab">null</field>
       <field name="_afterSelectedTab">null</field>
       <field name="_beforeHoveredTab">null</field>
       <field name="_afterHoveredTab">null</field>
       <field name="_hoveredTab">null</field>
 
-      <method name="observe">
-        <parameter name="aSubject"/>
-        <parameter name="aTopic"/>
-        <parameter name="aData"/>
-        <body><![CDATA[
-          switch (aTopic) {
-            case "nsPref:changed":
-              // This is the only pref observed.
-              let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
-
-              const newTab = document.getElementById("new-tab-button");
-              const newTab2 = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button")
-
-              if (containersEnabled) {
-                for (let parent of [newTab, newTab2]) {
-                  if (!parent)
-                    continue;
-                  let popup = document.createElementNS(
-                                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
-                                "menupopup");
-                  if (parent.id) {
-                    popup.id = "newtab-popup";
-                  } else {
-                    popup.setAttribute("anonid", "newtab-popup");
-                  }
-                  popup.oncommand="event.stopPropagation();";
-                  popup.className = "new-tab-popup";
-                  popup.setAttribute("position", "after_end");
-                  parent.appendChild(popup);
-
-                  addClickAndHoldListenersOnElement(parent);
-                  parent.setAttribute("type", "menu");
-                }
-              } else {
-                for (let parent of [newTab, newTab2]) {
-                  if (!parent)
-                    continue;
-                  removeClickAndHoldListenersOnElement(parent);
-                  parent.removeAttribute("type");
-                  parent.firstChild.remove();
-                }
-              }
-
-              break;
-          }
-        ]]></body>
-      </method>
-
       <property name="_isCustomizing" readonly="true">
         <getter>
           let root = document.documentElement;
           return root.getAttribute("customizing") == "true" ||
                  root.getAttribute("customize-exiting") == "true";
         </getter>
       </property>
 
@@ -6735,64 +6675,55 @@
       <handler event="popupshowing">
       <![CDATA[
         if (event.target.getAttribute('id') == "alltabs_containersMenuTab") {
           createUserContextMenu(event);
           return;
         }
 
         let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
-
-        if (event.target.getAttribute('anonid') == "newtab-popup" ||
-            event.target.id == "newtab-popup") {
-          createUserContextMenu(event);
-        } else {
-          document.getElementById("alltabs-popup-separator-1").hidden = !containersEnabled;
-          let containersTab = document.getElementById("alltabs_containersTab");
-
-          containersTab.hidden = !containersEnabled;
-          if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-            containersTab.setAttribute("disabled", "true");
-          }
-
-          document.getElementById("alltabs_undoCloseTab").disabled =
-            SessionStore.getClosedTabCount(window) == 0;
-
-          var tabcontainer = gBrowser.tabContainer;
-
-          // Listen for changes in the tab bar.
-          tabcontainer.addEventListener("TabAttrModified", this, false);
-          tabcontainer.addEventListener("TabClose", this, false);
-          tabcontainer.mTabstrip.addEventListener("scroll", this, false);
-
-          let tabs = gBrowser.visibleTabs;
-          for (var i = 0; i < tabs.length; i++) {
-            if (!tabs[i].pinned)
-              this._createTabMenuItem(tabs[i]);
-          }
-          this._updateTabsVisibilityStatus();
+        document.getElementById("alltabs-popup-separator-1").hidden = !containersEnabled;
+        let containersTab = document.getElementById("alltabs_containersTab");
+
+        containersTab.hidden = !containersEnabled;
+        if (PrivateBrowsingUtils.isWindowPrivate(window)) {
+          containersTab.setAttribute("disabled", "true");
         }
+
+        document.getElementById("alltabs_undoCloseTab").disabled =
+          SessionStore.getClosedTabCount(window) == 0;
+
+        var tabcontainer = gBrowser.tabContainer;
+
+        // Listen for changes in the tab bar.
+        tabcontainer.addEventListener("TabAttrModified", this, false);
+        tabcontainer.addEventListener("TabClose", this, false);
+        tabcontainer.mTabstrip.addEventListener("scroll", this, false);
+
+        let tabs = gBrowser.visibleTabs;
+        for (var i = 0; i < tabs.length; i++) {
+          if (!tabs[i].pinned)
+            this._createTabMenuItem(tabs[i]);
+        }
+        this._updateTabsVisibilityStatus();
       ]]></handler>
 
       <handler event="popuphidden">
       <![CDATA[
         if (event.target.getAttribute('id') == "alltabs_containersMenuTab") {
           return;
         }
 
         // clear out the menu popup and remove the listeners
         for (let i = this.childNodes.length - 1; i > 0; i--) {
           let menuItem = this.childNodes[i];
           if (menuItem.tab) {
             menuItem.tab.mCorrespondingMenuitem = null;
             this.removeChild(menuItem);
           }
-          if (menuItem.hasAttribute("usercontextid")) {
-            this.removeChild(menuItem);
-          }
         }
         var tabcontainer = gBrowser.tabContainer;
         tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
         tabcontainer.removeEventListener("TabAttrModified", this, false);
         tabcontainer.removeEventListener("TabClose", this, false);
       ]]></handler>
 
       <handler event="DOMMenuItemActive">
--- a/browser/base/content/test/tabPrompts/browser_multiplePrompts.js
+++ b/browser/base/content/test/tabPrompts/browser_multiplePrompts.js
@@ -51,16 +51,22 @@ add_task(function*() {
       if (i !== promptsCount) {
         is(prompt.hidden, true, "This prompt should be hidden.");
         i++;
         continue;
       }
 
       is(prompt.hidden, false, "The last prompt should not be hidden.");
       prompt.onButtonClick(0);
+
+      // The click is handled async; wait for an event loop turn for that to
+      // happen.
+      yield new Promise(function(resolve) {
+        Services.tm.mainThread.dispatch(resolve, Ci.nsIThread.DISPATCH_NORMAL);
+      });
     }
   }
 
   let prompts = tab.linkedBrowser.parentNode.querySelectorAll("tabmodalprompt");
   is(prompts.length, 0, "Prompts should all be dismissed.");
 
   yield BrowserTestUtils.removeTab(tab);
 });
--- a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
+++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
@@ -37,16 +37,20 @@ add_task(function*() {
   let row = ourPrompt.querySelector("row");
   ok(row, "Should have found the row with our checkbox");
   let checkbox = row.querySelector("checkbox[label*='example.com']");
   ok(checkbox, "The checkbox should be there");
   ok(!checkbox.checked, "Checkbox shouldn't be checked");
   // tick box and accept dialog
   checkbox.checked = true;
   ourPrompt.onButtonClick(0);
+  // Wait for that click to actually be handled completely.
+  yield new Promise(function(resolve) {
+    Services.tm.mainThread.dispatch(resolve, Ci.nsIThread.DISPATCH_NORMAL);
+  });
   // check permission is set
   let ps = Services.perms;
   is(ps.ALLOW_ACTION, ps.testPermission(makeURI(pageWithAlert), "focus-tab-by-prompt"),
      "Tab switching should now be allowed");
 
   let openedTabSelectedPromise = BrowserTestUtils.waitForAttribute("selected", openedTab, "true");
   // switch to other tab again
   yield BrowserTestUtils.switchTab(gBrowser, firstTab);
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -8,17 +8,16 @@ support-files =
   serviceworker.html
   worker.js
 
 [browser_aboutURLs.js]
 skip-if = (debug && (os == "win" || os == "linux")) # intermittent negative leak bug 1271182
 [browser_eme.js]
 [browser_favicon.js]
 [browser_forgetaboutsite.js]
-[browser_newtabButton.js]
 [browser_usercontext.js]
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
 tags = openwindow
 [browser_serviceworkers.js]
deleted file mode 100644
--- a/browser/components/contextualidentity/test/browser/browser_newtabButton.js
+++ /dev/null
@@ -1,34 +0,0 @@
-"use strict";
-
-// Testing that when the user opens the add tab menu and clicks menu items
-// the correct context id is opened
-
-add_task(function* test() {
-  yield SpecialPowers.pushPrefEnv({"set": [
-      ["privacy.userContext.enabled", true]
-  ]});
-
-  let newTab = document.getElementById('tabbrowser-tabs');
-  let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
-  ok(newTabButton, "New tab button exists");
-  ok(!newTabButton.hidden, "New tab button is visible");
-  let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
-
-  for (let i = 1; i <= 4; i++) {
-    let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
-    EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
-
-    yield popupShownPromise;
-    let contextIdItem = popup.querySelector(`menuitem[usercontextid="${i}"]`);
-
-    ok(contextIdItem, `User context id ${i} exists`);
-
-    let waitForTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
-    EventUtils.synthesizeMouseAtCenter(contextIdItem, {});
-
-    let tab = yield waitForTabPromise;
-
-    is(tab.getAttribute('usercontextid'), i, `New tab has UCI equal ${i}`);
-    yield BrowserTestUtils.removeTab(tab);
-  }
-});
--- a/browser/components/preferences/in-content/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content/tests/browser_subdialogs.js
@@ -54,28 +54,29 @@ function* open_subdialog_and_test_generi
 function* close_subdialog_and_test_generic_end_state(browser, closingFn, closingButton, acceptCount, options) {
   let dialogclosingPromise = ContentTask.spawn(browser, {closingButton, acceptCount}, function*(expectations) {
     let win = content.window;
     let subdialog = win.gSubDialog;
     let frame = subdialog._frame;
     info("waiting for dialogclosing");
     let closingEvent =
       yield ContentTaskUtils.waitForEvent(frame.contentWindow, "dialogclosing");
+    let closingButton = closingEvent.detail.button;
     let actualAcceptCount = frame.contentWindow.arguments &&
                             frame.contentWindow.arguments[0].acceptCount;
 
     info("waiting for about:blank load");
     yield ContentTaskUtils.waitForEvent(frame, "load");
 
     Assert.notEqual(win.getComputedStyle(subdialog._overlay, "").visibility, "visible",
       "overlay is not visible");
     Assert.equal(frame.getAttribute("style"), "", "inline styles should be cleared");
     Assert.equal(frame.contentWindow.location.href.toString(), "about:blank",
       "sub-dialog should be unloaded");
-    Assert.equal(closingEvent.detail.button, expectations.closingButton,
+    Assert.equal(closingButton, expectations.closingButton,
       "closing event should indicate button was '" + expectations.closingButton + "'");
     Assert.equal(actualAcceptCount, expectations.acceptCount,
       "should be 1 if accepted, 0 if canceled, undefined if closed w/out button");
   });
 
   if (options && options.runClosingFnOutsideOfContentTask) {
     yield closingFn();
   } else {
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -18,18 +18,16 @@ support-files =
 [browser_addEngine.js]
 [browser_amazon.js]
 [browser_amazon_behavior.js]
 [browser_bing.js]
 [browser_bing_behavior.js]
 [browser_contextmenu.js]
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" # bug 967013
-[browser_eBay.js]
-[browser_eBay_behavior.js]
 [browser_google.js]
 [browser_google_codes.js]
 [browser_google_behavior.js]
 [browser_healthreport.js]
 [browser_hiddenOneOffs_cleanup.js]
 [browser_hiddenOneOffs_diacritics.js]
 [browser_oneOffHeader.js]
 [browser_private_search_perwindowpb.js]
--- a/browser/components/search/test/browser_abouthome_behavior.js
+++ b/browser/components/search/test/browser_abouthome_behavior.js
@@ -70,23 +70,16 @@ function test() {
     {
       name: "Search with Yahoo from about:home",
       searchURL: replaceUrl("https://search.yahoo.com/search?p=foo&ei=UTF-8&fr=moz35"),
       run: function () {
         verify_about_home_search("Yahoo");
       }
     },
     {
-      name: "Search with eBay from about:home",
-      searchURL: replaceUrl("http://rover.ebay.com/rover/1/711-47294-18009-3/4?mfe=search&mpre=http://www.ebay.com/sch/i.html?_nkw=foo"),
-      run: function () {
-        verify_about_home_search("eBay");
-      }
-    },
-    {
       name: "Search with Google from about:home",
       searchURL: replaceUrl("https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8"),
       run: function () {
         verify_about_home_search("Google");
       }
     },
     {
       name: "Search with Amazon.com from about:home",
deleted file mode 100644
--- a/browser/components/search/test/browser_eBay.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Test eBay search plugin URLs
- */
-
-"use strict";
-
-const BROWSER_SEARCH_PREF = "browser.search.";
-
-function test() {
-  let engine = Services.search.getEngineByName("eBay");
-  ok(engine, "eBay");
-
-  let base = "http://rover.ebay.com/rover/1/711-47294-18009-3/4?mfe=search&mpre=http://www.ebay.com/sch/i.html?_nkw=foo";
-  let url;
-
-  // Test search URLs (including purposes).
-  url = engine.getSubmission("foo").uri.spec;
-  is(url, base, "Check search URL for 'foo'");
-
-  // Check search suggestion URL.
-  url = engine.getSubmission("foo", "application/x-suggestions+json").uri.spec;
-  is(url, "http://autosug.ebay.com/autosug?sId=0&kwd=foo&fmt=osr", "Check search suggestion URL for 'foo'");
-
-  // Check all other engine properties.
-  const EXPECTED_ENGINE = {
-    name: "eBay",
-    alias: null,
-    description: "eBay - Online auctions",
-    searchForm: "http://search.ebay.com/",
-    hidden: false,
-    wrappedJSObject: {
-      queryCharset: "ISO-8859-1",
-      "_iconURL": "data:image/x-icon;base64,AAABAAIAEBAAAAAAAAB6AQAAJgAAACAgAAAAAAAAQgMAAKABAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAFBSURBVDjLtZPdK0MBGIf3J5Babhx3rinFBWuipaUskX9DYvkopqgV90q5UJpyp0OKrUWM2VrRsS9D0zZKHGaOnW1nj4vtypVtPPe/533r9746QAAOAJXfo5Yzgg44pHrcugon/6Sgo0b+XuAOZ2iZiVQmyPoDpIwmUkYTzqM7GsdDdC7F6Lbf8pzOkfWOouzqeZem2b+2AqAV8zjD8yVBqqcf2b7C66yNiMGMfixIQSvi8Mp0LEbR5ADq1QSKWM+Gx0RC9nOZ2GLzwlIWdPWiuNzk4w/EpThNkyEAXKEP2ud8KGId2sspilhPMrmNwzfCuqePr/xbSfC5I/I0MMSj2YJ3z49gDdO2cEOrLUowJpE9G0QRG1ClKbR0EIdvmOPYcnUtnN+vsnZiQC1k/qnGagQ1n3LNzySUJZVskitnmr8BlQG7T2hvgxsAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAMJSURBVFjD7ZddSFNhGMeHXXQTZFFCWfR1pRhUECQlBdWVToo+6KYu1KigtDASG5qUfZgFZvahEDosECPDktKZS1FL+1DRnEvdUptjug91X2dnZzv/3vO6OZbWnR4v9sADL+fs7P97/s/znu2VAJD4UkpSSdKG+QubTyPBr+sXz8XCR64fIAHihVTis0SsUAoAVhEBrBKIHCGAEMB/ARi3F5LkbpS2WMRzYEEBXC2tsD6T03R9agsCGLNyqPw6CXmrBT06JvhbPHZwmkdwtR0B138PPKOHgzXD5jLAy3tmibo4K9weZwDAazJj/FQKRnfugfHMeRiTz0K3Ixam1HQKcPC+Fisu9NK1P08Uj4DleHgMdXC+WQ7nu3UEOhFMfTQcVUvQ1H4IN2sj8H2k7K+2TqCc3GseyA8AmDOzMBq7D9bS8sAr6nEJdNt3UbHVF1XQGtmZew8bTPT6tWoD3KpsUvlR8NxUoEICMvl6KQo+xqCwcRs4T8Ax5c8bFExjbAgAjO7aS8VsLypgq3g5nWStjztAhWRVhqAqeB6IuKTClkw1eNYEbrCQQBwD8yGGOsAooogLYejQPKBi7UPF9DkH+ezd+o141ZkUPAOC+L9SAMivNc7q46YMNSLTe4n1kaQF4XD3ZIDTPgU3XEYciKcAHrsGJS1xKFBGgyVzouiT4VbdGhjt/cEA5isyKsaz7jl3we7bg7Rqf6j0LoSldON4wWcqJDgQNGTN++l13vELA+MK6kKd6iryFOvxtidt9i5gO7owdjKJQliflNAU1pas6xQgnAzg1ux+lJEdILixNr0Pq9JUUA8NwVG9DM73G0jlcnh+V4BpjIWzJmIGQIjnXw5TiDuKSEwxurm3ITc8DNO51BnrLbIcsrW0dNA6RxgUKU1UdGVqLy5X6qGzTLvlnewiBZyGs3Yz6X8UeaYI3olvZDhzwLumZ+eHvooCCC0Q5VUsb4unwycM4YIDqA01tPqmgbzQr2EIYPECiPm33LYoDiZSsY9moh9O/Znoa4d9HkXtPg2pX/cPKCoRQ+ocZa4AAAAASUVORK5CYII=",
-      _urls : [
-        {
-          type: "application/x-suggestions+json",
-          method: "GET",
-          template: "http://autosug.ebay.com/autosug",
-          params: [
-            {
-              name: "sId",
-              value: "0",
-              purpose: undefined,
-            },
-            {
-              name: "kwd",
-              value: "{searchTerms}",
-              purpose: undefined,
-            },
-            {
-              name: "fmt",
-              value: "osr",
-              purpose: undefined,
-            },
-          ],
-        },
-        {
-          type: "text/html",
-          method: "GET",
-          template: "http://rover.ebay.com/rover/1/711-47294-18009-3/4",
-          params: [
-            {
-              name: "mfe",
-              value: "search",
-              purpose: undefined,
-            },
-            {
-              name: "mpre",
-              value: "http://www.ebay.com/sch/i.html?_nkw={searchTerms}",
-              purpose: undefined,
-            },
-          ],
-          mozparams: {},
-        },
-      ],
-    },
-  };
-
-  isSubObjectOf(EXPECTED_ENGINE, engine, "eBay");
-}
deleted file mode 100644
--- a/browser/components/search/test/browser_eBay_behavior.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Test eBay search plugin URLs
- */
-
-"use strict";
-
-const BROWSER_SEARCH_PREF = "browser.search.";
-
-
-function test() {
-  let engine = Services.search.getEngineByName("eBay");
-  ok(engine, "eBay is installed");
-
-  let previouslySelectedEngine = Services.search.currentEngine;
-  Services.search.currentEngine = engine;
-  engine.alias = 'e';
-
-  let base = "http://rover.ebay.com/rover/1/711-47294-18009-3/4?mfe=search&mpre=http://www.ebay.com/sch/i.html?_nkw=foo";
-  let url;
-
-  // Test search URLs (including purposes).
-  url = engine.getSubmission("foo").uri.spec;
-  is(url, base, "Check search URL for 'foo'");
-
-  waitForExplicitFinish();
-
-  var gCurrTest;
-  var gTests = [
-    {
-      name: "context menu search",
-      searchURL: base,
-      run: function () {
-        // Simulate a contextmenu search
-        // FIXME: This is a bit "low-level"...
-        BrowserSearch.loadSearch("foo", false, "contextmenu");
-      }
-    },
-    {
-      name: "keyword search",
-      searchURL: base,
-      run: function () {
-        gURLBar.value = "? foo";
-        gURLBar.focus();
-        EventUtils.synthesizeKey("VK_RETURN", {});
-      }
-    },
-    {
-      name: "keyword search",
-      searchURL: base,
-      run: function () {
-        gURLBar.value = "e foo";
-        gURLBar.focus();
-        EventUtils.synthesizeKey("VK_RETURN", {});
-      }
-    },
-    {
-      name: "search bar search",
-      searchURL: base,
-      run: function () {
-        let sb = BrowserSearch.searchBar;
-        sb.focus();
-        sb.value = "foo";
-        registerCleanupFunction(function () {
-          sb.value = "";
-        });
-        EventUtils.synthesizeKey("VK_RETURN", {});
-      }
-    },
-    {
-      name: "new tab search",
-      searchURL: base,
-      run: function () {
-        function doSearch(doc) {
-          // Re-add the listener, and perform a search
-          gBrowser.addProgressListener(listener);
-          doc.getElementById("newtab-search-text").value = "foo";
-          doc.getElementById("newtab-search-submit").click();
-        }
-
-        // load about:newtab, but remove the listener first so it doesn't
-        // get in the way
-        gBrowser.removeProgressListener(listener);
-        gBrowser.loadURI("about:newtab");
-        info("Waiting for about:newtab load");
-        tab.linkedBrowser.addEventListener("load", function load(event) {
-          if (event.originalTarget != tab.linkedBrowser.contentDocument ||
-              event.target.location.href == "about:blank") {
-            info("skipping spurious load event");
-            return;
-          }
-          tab.linkedBrowser.removeEventListener("load", load, true);
-
-          // Observe page setup
-          let win = gBrowser.contentWindow;
-          if (win.gSearch.currentEngineName ==
-              Services.search.currentEngine.name) {
-            doSearch(win.document);
-          }
-          else {
-            info("Waiting for newtab search init");
-            win.addEventListener("ContentSearchService", function done(event) {
-              info("Got newtab search event " + event.detail.type);
-              if (event.detail.type == "State") {
-                win.removeEventListener("ContentSearchService", done);
-                // Let gSearch respond to the event before continuing.
-                executeSoon(() => doSearch(win.document));
-              }
-            });
-          }
-        }, true);
-      }
-    }
-  ];
-
-  function nextTest() {
-    if (gTests.length) {
-      gCurrTest = gTests.shift();
-      info("Running : " + gCurrTest.name);
-      executeSoon(gCurrTest.run);
-    } else {
-      finish();
-    }
-  }
-
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-
-  let listener = {
-    onStateChange: function onStateChange(webProgress, req, flags, status) {
-      info("onStateChange");
-      // Only care about top-level document starts
-      let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
-                     Ci.nsIWebProgressListener.STATE_START;
-      if (!(flags & docStart) || !webProgress.isTopLevel)
-        return;
-
-      if (req.originalURI.spec == "about:blank")
-        return;
-
-      info("received document start");
-
-      ok(req instanceof Ci.nsIChannel, "req is a channel");
-      is(req.originalURI.spec, gCurrTest.searchURL, "search URL was loaded");
-      info("Actual URI: " + req.URI.spec);
-
-      req.cancel(Components.results.NS_ERROR_FAILURE);
-
-      executeSoon(nextTest);
-    }
-  }
-
-  registerCleanupFunction(function () {
-    engine.alias = undefined;
-    gBrowser.removeProgressListener(listener);
-    gBrowser.removeTab(tab);
-    Services.search.currentEngine = previouslySelectedEngine;
-  });
-
-  tab.linkedBrowser.addEventListener("load", function load() {
-    tab.linkedBrowser.removeEventListener("load", load, true);
-    gBrowser.addProgressListener(listener);
-    nextTest();
-  }, true);
-}
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -738,8 +738,10 @@ pendingCrashReports.ignoreAll = Ignore
 decoder.noCodecs.button = Learn how
 decoder.noCodecs.accesskey = L
 decoder.noCodecs.message = To play video, you may need to install Microsoft’s Media Feature Pack.
 decoder.noCodecsVista.message = To play video, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noCodecsXP.message = To play video, you may need to enable Adobe’s Primetime Content Decryption Module.
 decoder.noCodecsLinux.message = To play video, you may need to install the required video codecs.
 decoder.noHWAcceleration.message = To improve video quality, you may need to install Microsoft’s Media Feature Pack.
 decoder.noHWAccelerationVista.message = To improve video quality, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
+
+permissions.remove.tooltip = Clear this permission and ask again
deleted file mode 100644
--- a/browser/locales/en-US/searchplugins/eBay.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<!-- 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/. -->
-
-<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
-<ShortName>eBay</ShortName>
-<Description>eBay - Online auctions</Description>
-<InputEncoding>ISO-8859-1</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAAAAAB6AQAAJgAAACAgAAAAAAAAQgMAAKABAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAFBSURBVDjLtZPdK0MBGIf3J5Babhx3rinFBWuipaUskX9DYvkopqgV90q5UJpyp0OKrUWM2VrRsS9D0zZKHGaOnW1nj4vtypVtPPe/533r9746QAAOAJXfo5Yzgg44pHrcugon/6Sgo0b+XuAOZ2iZiVQmyPoDpIwmUkYTzqM7GsdDdC7F6Lbf8pzOkfWOouzqeZem2b+2AqAV8zjD8yVBqqcf2b7C66yNiMGMfixIQSvi8Mp0LEbR5ADq1QSKWM+Gx0RC9nOZ2GLzwlIWdPWiuNzk4w/EpThNkyEAXKEP2ud8KGId2sspilhPMrmNwzfCuqePr/xbSfC5I/I0MMSj2YJ3z49gDdO2cEOrLUowJpE9G0QRG1ClKbR0EIdvmOPYcnUtnN+vsnZiQC1k/qnGagQ1n3LNzySUJZVskitnmr8BlQG7T2hvgxsAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAMJSURBVFjD7ZddSFNhGMeHXXQTZFFCWfR1pRhUECQlBdWVToo+6KYu1KigtDASG5qUfZgFZvahEDosECPDktKZS1FL+1DRnEvdUptjug91X2dnZzv/3vO6OZbWnR4v9sADL+fs7P97/s/znu2VAJD4UkpSSdKG+QubTyPBr+sXz8XCR64fIAHihVTis0SsUAoAVhEBrBKIHCGAEMB/ARi3F5LkbpS2WMRzYEEBXC2tsD6T03R9agsCGLNyqPw6CXmrBT06JvhbPHZwmkdwtR0B138PPKOHgzXD5jLAy3tmibo4K9weZwDAazJj/FQKRnfugfHMeRiTz0K3Ixam1HQKcPC+Fisu9NK1P08Uj4DleHgMdXC+WQ7nu3UEOhFMfTQcVUvQ1H4IN2sj8H2k7K+2TqCc3GseyA8AmDOzMBq7D9bS8sAr6nEJdNt3UbHVF1XQGtmZew8bTPT6tWoD3KpsUvlR8NxUoEICMvl6KQo+xqCwcRs4T8Ax5c8bFExjbAgAjO7aS8VsLypgq3g5nWStjztAhWRVhqAqeB6IuKTClkw1eNYEbrCQQBwD8yGGOsAooogLYejQPKBi7UPF9DkH+ezd+o141ZkUPAOC+L9SAMivNc7q46YMNSLTe4n1kaQF4XD3ZIDTPgU3XEYciKcAHrsGJS1xKFBGgyVzouiT4VbdGhjt/cEA5isyKsaz7jl3we7bg7Rqf6j0LoSldON4wWcqJDgQNGTN++l13vELA+MK6kKd6iryFOvxtidt9i5gO7owdjKJQliflNAU1pas6xQgnAzg1ux+lJEdILixNr0Pq9JUUA8NwVG9DM73G0jlcnh+V4BpjIWzJmIGQIjnXw5TiDuKSEwxurm3ITc8DNO51BnrLbIcsrW0dNA6RxgUKU1UdGVqLy5X6qGzTLvlnewiBZyGs3Yz6X8UeaYI3olvZDhzwLumZ+eHvooCCC0Q5VUsb4unwycM4YIDqA01tPqmgbzQr2EIYPECiPm33LYoDiZSsY9moh9O/Znoa4d9HkXtPg2pX/cPKCoRQ+ocZa4AAAAASUVORK5CYII=</Image>
-<Url type="application/x-suggestions+json" method="GET" template="http://autosug.ebay.com/autosug">
-  <Param name="sId" value="0" />
-  <Param name="kwd" value="{searchTerms}" />
-  <Param name="fmt" value="osr" />
-</Url>
-<Url type="text/html" method="GET" template="http://rover.ebay.com/rover/1/711-47294-18009-3/4" resultdomain="ebay.com">
-  <Param name="mfe"  value="search" />
-  <Param name="mpre" value="http://www.ebay.com/sch/i.html?_nkw={searchTerms}" />
-</Url>
-<SearchForm>http://search.ebay.com/</SearchForm>
-</SearchPlugin>
--- a/browser/locales/en-US/searchplugins/list.txt
+++ b/browser/locales/en-US/searchplugins/list.txt
@@ -1,8 +1,7 @@
 amazondotcom
 bing
-eBay
 google
 twitter
 wikipedia
 yahoo
 yahoo-en-CA:hidden
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -391,17 +391,19 @@ this.ContentSearch = {
     }
   },
 
   _onMessage: Task.async(function* (msg) {
     let methodName = "_onMessage" + msg.data.type;
     if (methodName in this) {
       yield this._initService();
       yield this[methodName](msg, msg.data.data);
-      msg.target.removeEventListener("SwapDocShells", msg, true);
+      if (!Cu.isDeadWrapper(msg.target)) {
+        msg.target.removeEventListener("SwapDocShells", msg, true);
+      }
     }
   }),
 
   _onMessageGetState: function (msg, data) {
     return this.currentStateObj().then(state => {
       this._reply(msg, "State", state);
     });
   },
@@ -484,17 +486,17 @@ this.ContentSearch = {
       this._suggestionMap.set(browser, data);
     }
     return data;
   },
 
   _reply: function (msg, type, data) {
     // We reply asyncly to messages, and by the time we reply the browser we're
     // responding to may have been destroyed.  messageManager is null then.
-    if (msg.target.messageManager) {
+    if (!Cu.isDeadWrapper(msg.target) && msg.target.messageManager) {
       msg.target.messageManager.sendAsyncMessage(...this._msgArgs(type, data));
     }
   },
 
   _broadcast: function (type, data) {
     Cc["@mozilla.org/globalmessagemanager;1"].
       getService(Ci.nsIMessageListenerManager).
       broadcastAsyncMessage(...this._msgArgs(type, data));
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -250,16 +250,24 @@ interface nsIScriptSecurityManager : nsI
 
     /**
      * Get the codebase principal for the channel's URI.
      * aChannel must not be null.
      */
     nsIPrincipal getChannelURIPrincipal(in nsIChannel aChannel);
 
     /**
+     * Get the principal for a sandbox object.
+     *
+     * This function is currently only used in tests.
+     */
+    [implicit_jscontext]
+    nsIPrincipal getSandboxPrincipal(in jsval aSandbox);
+
+    /**
      * Check whether a given principal is a system principal.  This allows us
      * to avoid handing back the system principal to script while allowing
      * script to check whether a given principal is system.
      */
     boolean isSystemPrincipal(in nsIPrincipal aPrincipal);
 %{C++
     bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
       bool isSystem = false;
--- a/caps/nsPrincipal.cpp
+++ b/caps/nsPrincipal.cpp
@@ -669,17 +669,24 @@ struct OriginComparator
     NS_ENSURE_SUCCESS(rv, false);
     nsAutoCString originB;
     rv = b->GetOrigin(originB);
     NS_ENSURE_SUCCESS(rv, false);
     return a == b;
   }
 };
 
-nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
+nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
+                                         const PrincipalOriginAttributes& aOriginAttributes)
+  : nsExpandedPrincipal(aWhiteList)
+{
+  mOriginAttributes = aOriginAttributes;
+}
+
+nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList)
 {
   // We force the principals to be sorted by origin so that nsExpandedPrincipal
   // origins can have a canonical form.
   OriginComparator c;
   for (size_t i = 0; i < aWhiteList.Length(); ++i) {
     mPrincipals.InsertElementSorted(aWhiteList[i], c);
   }
 }
--- a/caps/nsPrincipal.h
+++ b/caps/nsPrincipal.h
@@ -62,17 +62,19 @@ protected:
 
   bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override;
   bool MayLoadInternal(nsIURI* aURI) override;
 };
 
 class nsExpandedPrincipal : public nsIExpandedPrincipal, public mozilla::BasePrincipal
 {
 public:
-  explicit nsExpandedPrincipal(nsTArray< nsCOMPtr<nsIPrincipal> > &aWhiteList);
+  nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
+                      const mozilla::PrincipalOriginAttributes& aOriginAttributes);
+  explicit nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList);
 
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
   NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -62,16 +62,17 @@
 #include <stdint.h>
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsILoadInfo.h"
 #include "nsXPCOMStrings.h"
+#include "xpcprivate.h"
 
 // This should be probably defined on some other place... but I couldn't find it
 #define WEBAPPS_PERM_NAME "webapps-manage"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
@@ -251,18 +252,20 @@ nsScriptSecurityManager::AppStatusForPri
     // browser frame, so non-desktop should be able to assume that
     // inIsolatedMozBrowser is true for all mozbrowser frames.  Additionally,
     // apps are no longer used on desktop, so appId is always NO_APP_ID.  We use
     // a release assertion in nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so
     // that platforms with apps can assume inIsolatedMozBrowser is true for all
     // mozbrowser frames.
     bool inIsolatedMozBrowser = aPrin->GetIsInIsolatedMozBrowserElement();
 
-    NS_WARN_IF_FALSE(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
-                     "Asking for app status on a principal with an unknown app id");
+    NS_WARNING_ASSERTION(
+      appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+      "Asking for app status on a principal with an unknown app id");
+
     // Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
     // and they are not inside a mozbrowser.
     if (appId == nsIScriptSecurityManager::NO_APP_ID ||
         appId == nsIScriptSecurityManager::UNKNOWN_APP_ID ||
         inIsolatedMozBrowser)
     {
         return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
     }
@@ -468,16 +471,28 @@ nsScriptSecurityManager::GetChannelURIPr
     rv = MaybeSetAddonIdFromURI(attrs, uri);
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
     prin.forget(aPrincipal);
     return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
+nsScriptSecurityManager::GetSandboxPrincipal(JS::HandleValue aSandboxArg,
+                                             JSContext* aCx,
+                                             nsIPrincipal** aPrincipal)
+{
+  if (!aSandboxArg.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  JS::RootedObject sandbox(aCx, &aSandboxArg.toObject());
+  return xpc::GetSandboxPrincipal(aCx, sandbox, aPrincipal);
+}
+
+NS_IMETHODIMP
 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
                                            bool* aIsSystem)
 {
     *aIsSystem = (aPrincipal == mSystemPrincipal);
     return NS_OK;
 }
 
 /////////////////////////////
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -134,19 +134,18 @@ nsChromeProtocolHandler::NewChannel2(nsI
             mozilla::services::GetChromeRegistryService();
         NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
     }
 
     nsCOMPtr<nsIURI> resolvedURI;
     rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
     if (NS_FAILED(rv)) {
 #ifdef DEBUG
-        nsAutoCString spec;
-        aURI->GetSpec(spec);
-        printf("Couldn't convert chrome URL: %s\n", spec.get());
+        printf("Couldn't convert chrome URL: %s\n",
+               aURI->GetSpecOrDefault().get());
 #endif
         return rv;
     }
 
     rv = NS_NewChannelInternal(getter_AddRefs(result),
                                resolvedURI,
                                aLoadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -448,17 +448,18 @@ nsChromeRegistryChrome::SendRegisteredCh
     ContentParent::GetAll(parents);
     if (!parents.Length())
       return;
 
     for (uint32_t i = 0; i < parents.Length(); i++) {
       DebugOnly<bool> success =
         parents[i]->SendRegisterChrome(packages, resources, overrides,
                                        mSelectedLocale, true);
-      NS_WARN_IF_FALSE(success, "couldn't reset a child's registered chrome");
+      NS_WARNING_ASSERTION(success,
+                           "couldn't reset a child's registered chrome");
     }
   }
 }
 
 /* static */ void
 nsChromeRegistryChrome::ChromePackageFromPackageEntry(const nsACString& aPackageName,
                                                       PackageEntry* aPackage,
                                                       ChromePackage* aChromePackage,
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -43,16 +43,17 @@ const ErrorDocs = {
   JSMSG_OVER_RECURSED: "Too_much_recursion",
   JSMSG_BRACKET_AFTER_LIST: "Missing_bracket_after_list",
   JSMSG_PAREN_AFTER_ARGS: "Missing_parenthesis_after_argument_list",
   JSMSG_MORE_ARGS_NEEDED: "More_arguments_needed",
   JSMSG_BAD_LEFTSIDE_OF_ASS: "Invalid_assignment_left-hand_side",
   JSMSG_UNTERMINATED_STRING: "Unterminated_string_literal",
   JSMSG_NOT_CONSTRUCTOR: "Not_a_constructor",
   JSMSG_CURLY_AFTER_LIST: "Missing_curly_after_property_list",
+  JSMSG_DEPRECATED_FOR_EACH: "For-each-in_loops_are_deprecated",
 };
 
 const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Mixed_content";
 const TRACKING_PROTECTION_LEARN_MORE = "https://developer.mozilla.org/Firefox/Privacy/Tracking_Protection";
 const INSECURE_PASSWORDS_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Insecure_passwords";
 const PUBLIC_KEY_PINS_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Public_Key_Pinning";
 const STRICT_TRANSPORT_SECURITY_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/HTTP_strict_transport_security";
 const WEAK_SIGNATURE_ALGORITHM_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Weak_Signature_Algorithm";
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1872,21 +1872,18 @@ nsDocShell::SetCurrentURI(nsIURI* aURI)
   return NS_OK;
 }
 
 bool
 nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
                           bool aFireOnLocationChange, uint32_t aLocationFlags)
 {
   if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (aURI) {
-      aURI->GetSpec(spec);
-    }
-    PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
+    PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n",
+                this, aURI ? aURI->GetSpecOrDefault().get() : "");
   }
 
   // We don't want to send a location change when we're displaying an error
   // page, and we don't want to change our idea of "current URI" either
   if (mLoadType == LOAD_ERROR_PAGE) {
     return false;
   }
 
@@ -5244,29 +5241,27 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
                           const char* aErrorPage,
                           const char16_t* aErrorType,
                           const char16_t* aDescription,
                           const char* aCSSClass,
                           nsIChannel* aFailedChannel)
 {
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
     nsAutoCString chanName;
     if (aFailedChannel) {
       aFailedChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
            ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
-            spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
+            aURI->GetSpecOrDefault().get(), NS_ConvertUTF16toUTF8(aURL).get(),
+            chanName.get()));
   }
 #endif
   mFailedChannel = aFailedChannel;
   mFailedURI = aURI;
   mFailedLoadType = mLoadType;
 
   if (mLSHE) {
     // Abandon mLSHE's BFCache entry and create a new one.  This way, if
@@ -6331,19 +6326,19 @@ NS_IMETHODIMP
 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
 {
 #ifdef DEBUG
   // if the channel is non-null
   if (aMixedContentChannel) {
     // Get the root docshell.
     nsCOMPtr<nsIDocShellTreeItem> root;
     GetSameTypeRootTreeItem(getter_AddRefs(root));
-    NS_WARN_IF_FALSE(root.get() == static_cast<nsIDocShellTreeItem*>(this),
-                     "Setting mMixedContentChannel on a docshell that is not "
-                     "the root docshell");
+    NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this),
+                         "Setting mMixedContentChannel on a docshell that is "
+                         "not the root docshell");
   }
 #endif
   mMixedContentChannel = aMixedContentChannel;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel)
@@ -9713,21 +9708,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                          nsIURI* aBaseURI,
                          nsIDocShell** aDocShell,
                          nsIRequest** aRequest)
 {
   nsresult rv = NS_OK;
   mOriginalUriString.Truncate();
 
   if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (aURI) {
-      aURI->GetSpec(spec);
-    }
-    PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
+    PR_LogPrint("DOCSHELL %p InternalLoad %s\n",
+                this, aURI ? aURI->GetSpecOrDefault().get() : "");
   }
   // Initialize aDocShell/aRequest
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
     *aRequest = nullptr;
   }
@@ -11428,29 +11420,26 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsICh
                      uint32_t aLoadType, bool aFireOnLocationChange,
                      bool aAddToGlobalHistory, bool aCloneSHChildren)
 {
   NS_PRECONDITION(aURI, "uri is null");
   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) {
       aChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
-           ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
-            chanName.get(), aLoadType));
+            ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
+             this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
   }
 #endif
 
   bool equalUri = false;
 
   // Get the post data and the HTTP response code from the channel.
   uint32_t responseStatus = 0;
   nsCOMPtr<nsIInputStream> inputStream;
@@ -12074,29 +12063,26 @@ nsDocShell::AddToSessionHistory(nsIURI* 
                                 bool aCloneChildren,
                                 nsISHEntry** aNewEntry)
 {
   NS_PRECONDITION(aURI, "uri is null");
   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) {
       aChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
-           ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
-            this, spec.get(), chanName.get()));
+            ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
+             this, aURI->GetSpecOrDefault().get(), chanName.get()));
   }
 #endif
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsISHEntry> entry;
   bool shouldPersist;
 
   shouldPersist = ShouldAddToSessionHistory(aURI);
@@ -12882,17 +12868,17 @@ nsDocShell::ExtractLastVisit(nsIChannel*
     // There is no last visit for this channel, so this must be the first
     // link.  Link the visit to the referrer of this request, if any.
     // Treat referrer as null if there is an error getting it.
     (void)NS_GetReferrerFromChannel(aChannel, aURI);
   } else {
     rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
                                     aChannelRedirectFlags);
 
-    NS_WARN_IF_FALSE(
+    NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "Could not fetch previous flags, URI will be treated like referrer");
   }
 }
 
 void
 nsDocShell::SaveLastVisit(nsIChannel* aChannel,
                           nsIURI* aURI,
@@ -14236,18 +14222,17 @@ nsDocShell::SetOriginAttributes(const Do
   // attributes.
   if (mContentViewer) {
     nsIDocument* doc = mContentViewer->GetDocument();
     if (doc) {
       nsIURI* uri = doc->GetDocumentURI();
       if (!uri) {
         return NS_ERROR_FAILURE;
       }
-      nsAutoCString uriSpec;
-      uri->GetSpec(uriSpec);
+      nsCString uriSpec = uri->GetSpecOrDefault();
       MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
       if (!uriSpec.EqualsLiteral("about:blank")) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   AssertOriginAttributesMatchPrivateBrowsing();
@@ -14466,18 +14451,17 @@ nsDocShell::ShouldPrepareForIntercept(ns
   nsresult result;
   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
     do_GetService(THIRDPARTYUTIL_CONTRACTID, &result);
   NS_ENSURE_SUCCESS(result, result);
 
   if (mCurrentURI &&
       nsContentUtils::CookiesBehavior() == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
     nsAutoCString uriSpec;
-    mCurrentURI->GetSpec(uriSpec);
-    if (!(uriSpec.EqualsLiteral("about:blank"))) {
+    if (!(mCurrentURI->GetSpecOrDefault().EqualsLiteral("about:blank"))) {
       // Reject the interception of third-party iframes if the cookie behaviour
       // is set to reject all third-party cookies (1). In case that this pref
       // is not set or can't be read, we default to allow all cookies (0) as
       // this is the default value in all.js.
       bool isThirdPartyURI = true;
       result = thirdPartyUtil->IsThirdPartyURI(mCurrentURI, aURI,
                                                &isThirdPartyURI);
       if (NS_FAILED(result)) {
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -69,17 +69,17 @@ static LazyLogModule gSHistoryLog("nsSHi
 //  nsIURI *uri = [...];
 //  LOG_SPEC(("The URI is %s.", _spec), uri);
 //
 #define LOG_SPEC(format, uri)                              \
   PR_BEGIN_MACRO                                           \
     if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) {     \
       nsAutoCString _specStr(NS_LITERAL_CSTRING("(null)"));\
       if (uri) {                                           \
-        uri->GetSpec(_specStr);                            \
+        _specStr = uri->GetSpecOrDefault();                \
       }                                                    \
       const char* _spec = _specStr.get();                  \
       LOG(format);                                         \
     }                                                      \
   PR_END_MACRO
 
 // This macro makes it easy to log a message including an SHEntry's URI.
 // For example:
--- a/dom/base/CustomElementsRegistry.cpp
+++ b/dom/base/CustomElementsRegistry.cpp
@@ -1,26 +1,164 @@
 /* -*- 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/. */
 
 #include "mozilla/dom/CustomElementsRegistry.h"
+
 #include "mozilla/dom/CustomElementsRegistryBinding.h"
+#include "mozilla/dom/HTMLElementBinding.h"
 #include "mozilla/dom/WebComponentsBinding.h"
+#include "nsIParserService.h"
+#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
+void
+CustomElementCallback::Call()
+{
+  ErrorResult rv;
+  switch (mType) {
+    case nsIDocument::eCreated:
+    {
+      // For the duration of this callback invocation, the element is being created
+      // flag must be set to true.
+      mOwnerData->mElementIsBeingCreated = true;
+
+      // The callback hasn't actually been invoked yet, but we need to flip
+      // this now in order to enqueue the attached callback. This is a spec
+      // bug (w3c bug 27437).
+      mOwnerData->mCreatedCallbackInvoked = true;
+
+      // If ELEMENT is in a document and this document has a browsing context,
+      // enqueue attached callback for ELEMENT.
+      nsIDocument* document = mThisObject->GetComposedDoc();
+      if (document && document->GetDocShell()) {
+        nsContentUtils::EnqueueLifecycleCallback(
+          document, nsIDocument::eAttached, mThisObject);
+      }
+
+      static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
+      mOwnerData->mElementIsBeingCreated = false;
+      break;
+    }
+    case nsIDocument::eAttached:
+      static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
+      break;
+    case nsIDocument::eDetached:
+      static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
+      break;
+    case nsIDocument::eAttributeChanged:
+      static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
+        mArgs.name, mArgs.oldValue, mArgs.newValue, rv);
+      break;
+  }
+}
+
+void
+CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const
+{
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
+  aCb.NoteXPCOMChild(mThisObject);
+
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
+  aCb.NoteXPCOMChild(mCallback);
+}
+
+CustomElementCallback::CustomElementCallback(Element* aThisObject,
+                                             nsIDocument::ElementCallbackType aCallbackType,
+                                             mozilla::dom::CallbackFunction* aCallback,
+                                             CustomElementData* aOwnerData)
+  : mThisObject(aThisObject),
+    mCallback(aCallback),
+    mType(aCallbackType),
+    mOwnerData(aOwnerData)
+{
+}
+
+CustomElementData::CustomElementData(nsIAtom* aType)
+  : mType(aType),
+    mCurrentCallback(-1),
+    mElementIsBeingCreated(false),
+    mCreatedCallbackInvoked(true),
+    mAssociatedMicroTask(-1)
+{
+}
+
+void
+CustomElementData::RunCallbackQueue()
+{
+  // Note: It's possible to re-enter this method.
+  while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
+    mCallbackQueue[mCurrentCallback]->Call();
+  }
+
+  mCallbackQueue.Clear();
+  mCurrentCallback = -1;
+}
 
 // Only needed for refcounted objects.
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CustomElementsRegistry, mWindow)
+NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementsRegistry)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementsRegistry)
+  tmp->mCustomDefinitions.Clear();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementsRegistry)
+  for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
+    nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
+
+    if (callbacks->mAttributeChangedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
+      cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
+    }
+
+    if (callbacks->mCreatedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mCreatedCallback");
+      cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
+    }
+
+    if (callbacks->mAttachedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mAttachedCallback");
+      cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
+    }
+
+    if (callbacks->mDetachedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mDetachedCallback");
+      cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
+    }
+  }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementsRegistry)
+  for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
+    aCallbacks.Trace(&iter.UserData()->mConstructor,
+                     "mCustomDefinitions constructor",
+                     aClosure);
+    aCallbacks.Trace(&iter.UserData()->mPrototype,
+                     "mCustomDefinitions prototype",
+                     aClosure);
+  }
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CustomElementsRegistry)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CustomElementsRegistry)
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CustomElementsRegistry)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /* static */ bool
 CustomElementsRegistry::IsCustomElementsEnabled(JSContext* aCx, JSObject* aObject)
 {
@@ -38,48 +176,624 @@ CustomElementsRegistry::Create(nsPIDOMWi
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
   if (!aWindow->GetDocShell()) {
     return nullptr;
   }
 
+  if (!Preferences::GetBool("dom.webcomponents.customelements.enabled") &&
+      !Preferences::GetBool("dom.webcomponents.enabled")) {
+    return nullptr;
+  }
+
   RefPtr<CustomElementsRegistry> customElementsRegistry =
     new CustomElementsRegistry(aWindow);
   return customElementsRegistry.forget();
 }
 
+/* static */ void
+CustomElementsRegistry::ProcessTopElementQueue()
+{
+  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+
+  nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack;
+  uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
+
+  for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
+    // Callback queue may have already been processed in an earlier
+    // element queue or in an element queue that was popped
+    // off more recently.
+    if (stack[i]->mAssociatedMicroTask != -1) {
+      stack[i]->RunCallbackQueue();
+      stack[i]->mAssociatedMicroTask = -1;
+    }
+  }
+
+  // If this was actually the base element queue, don't bother trying to pop
+  // the first "queue" marker (sentinel).
+  if (firstQueue != 0) {
+    stack.SetLength(firstQueue);
+  } else {
+    // Don't pop sentinel for base element queue.
+    stack.SetLength(1);
+  }
+}
+
+/* static */ void
+CustomElementsRegistry::XPCOMShutdown()
+{
+  sProcessingStack.reset();
+}
+
+/* static */ Maybe<nsTArray<RefPtr<CustomElementData>>>
+CustomElementsRegistry::sProcessingStack;
+
 CustomElementsRegistry::CustomElementsRegistry(nsPIDOMWindowInner* aWindow)
  : mWindow(aWindow)
+ , mIsCustomDefinitionRunning(false)
 {
+  mozilla::HoldJSObjects(this);
+
+  if (!sProcessingStack) {
+    sProcessingStack.emplace();
+    // Add the base queue sentinel to the processing stack.
+    sProcessingStack->AppendElement((CustomElementData*) nullptr);
+  }
 }
 
 CustomElementsRegistry::~CustomElementsRegistry()
 {
+  mozilla::DropJSObjects(this);
+}
+
+CustomElementDefinition*
+CustomElementsRegistry::LookupCustomElementDefinition(const nsAString& aLocalName,
+                                                      const nsAString* aIs) const
+{
+  nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName);
+  nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
+
+  CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom);
+  if (data && data->mLocalName == localNameAtom) {
+    return data;
+  }
+
+  return nullptr;
+}
+
+void
+CustomElementsRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
+{
+  mozilla::dom::NodeInfo* info = aElement->NodeInfo();
+
+  // Candidate may be a custom element through extension,
+  // in which case the custom element type name will not
+  // match the element tag name. e.g. <button is="x-button">.
+  nsCOMPtr<nsIAtom> typeName = aTypeName;
+  if (!typeName) {
+    typeName = info->NameAtom();
+  }
+
+  if (mCustomDefinitions.Get(typeName)) {
+    return;
+  }
+
+  nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
+  nsWeakPtr* elem = unresolved->AppendElement();
+  *elem = do_GetWeakReference(aElement);
+  aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
+
+  return;
+}
+
+void
+CustomElementsRegistry::SetupCustomElement(Element* aElement,
+                                           const nsAString* aTypeExtension)
+{
+  nsCOMPtr<nsIAtom> tagAtom = aElement->NodeInfo()->NameAtom();
+  nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ?
+    NS_Atomize(*aTypeExtension) : tagAtom;
+
+  if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
+    // Custom element setup in the parser happens after the "is"
+    // attribute is added.
+    aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
+  }
+
+  CustomElementDefinition* data = LookupCustomElementDefinition(
+    aElement->NodeInfo()->LocalName(), aTypeExtension);
+
+  if (!data) {
+    // The type extension doesn't exist in the registry,
+    // thus we don't need to enqueue callback or adjust
+    // the "is" attribute, but it is possibly an upgrade candidate.
+    RegisterUnresolvedElement(aElement, typeAtom);
+    return;
+  }
+
+  if (data->mLocalName != tagAtom) {
+    // The element doesn't match the local name for the
+    // definition, thus the element isn't a custom element
+    // and we don't need to do anything more.
+    return;
+  }
+
+  // Enqueuing the created callback will set the CustomElementData on the
+  // element, causing prototype swizzling to occur in Element::WrapObject.
+  EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data);
+}
+
+void
+CustomElementsRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
+                                                 Element* aCustomElement,
+                                                 LifecycleCallbackArgs* aArgs,
+                                                 CustomElementDefinition* aDefinition)
+{
+  CustomElementData* elementData = aCustomElement->GetCustomElementData();
+
+  // Let DEFINITION be ELEMENT's definition
+  CustomElementDefinition* definition = aDefinition;
+  if (!definition) {
+    mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
+
+    // Make sure we get the correct definition in case the element
+    // is a extended custom element e.g. <button is="x-button">.
+    nsCOMPtr<nsIAtom> typeAtom = elementData ?
+      elementData->mType.get() : info->NameAtom();
+
+    definition = mCustomDefinitions.Get(typeAtom);
+    if (!definition || definition->mLocalName != info->NameAtom()) {
+      // Trying to enqueue a callback for an element that is not
+      // a custom element. We are done, nothing to do.
+      return;
+    }
+  }
+
+  if (!elementData) {
+    // Create the custom element data the first time
+    // that we try to enqueue a callback.
+    elementData = new CustomElementData(definition->mType);
+    // aCustomElement takes ownership of elementData
+    aCustomElement->SetCustomElementData(elementData);
+    MOZ_ASSERT(aType == nsIDocument::eCreated,
+               "First callback should be the created callback");
+  }
+
+  // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
+  CallbackFunction* func = nullptr;
+  switch (aType) {
+    case nsIDocument::eCreated:
+      if (definition->mCallbacks->mCreatedCallback.WasPassed()) {
+        func = definition->mCallbacks->mCreatedCallback.Value();
+      }
+      break;
+
+    case nsIDocument::eAttached:
+      if (definition->mCallbacks->mAttachedCallback.WasPassed()) {
+        func = definition->mCallbacks->mAttachedCallback.Value();
+      }
+      break;
+
+    case nsIDocument::eDetached:
+      if (definition->mCallbacks->mDetachedCallback.WasPassed()) {
+        func = definition->mCallbacks->mDetachedCallback.Value();
+      }
+      break;
+
+    case nsIDocument::eAttributeChanged:
+      if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
+        func = definition->mCallbacks->mAttributeChangedCallback.Value();
+      }
+      break;
+  }
+
+  // If there is no such callback, stop.
+  if (!func) {
+    return;
+  }
+
+  if (aType == nsIDocument::eCreated) {
+    elementData->mCreatedCallbackInvoked = false;
+  } else if (!elementData->mCreatedCallbackInvoked) {
+    // Callbacks other than created callback must not be enqueued
+    // until after the created callback has been invoked.
+    return;
+  }
+
+  // Add CALLBACK to ELEMENT's callback queue.
+  CustomElementCallback* callback = new CustomElementCallback(aCustomElement,
+                                                              aType,
+                                                              func,
+                                                              elementData);
+  // Ownership of callback is taken by mCallbackQueue.
+  elementData->mCallbackQueue.AppendElement(callback);
+  if (aArgs) {
+    callback->SetArgs(*aArgs);
+  }
+
+  if (!elementData->mElementIsBeingCreated) {
+    CustomElementData* lastData =
+      sProcessingStack->SafeLastElement(nullptr);
+
+    // A new element queue needs to be pushed if the queue at the
+    // top of the stack is associated with another microtask level.
+    bool shouldPushElementQueue =
+      (!lastData || lastData->mAssociatedMicroTask <
+         static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
+
+    // Push a new element queue onto the processing stack when appropriate
+    // (when we enter a new microtask).
+    if (shouldPushElementQueue) {
+      // Push a sentinel value on the processing stack to mark the
+      // boundary between the element queues.
+      sProcessingStack->AppendElement((CustomElementData*) nullptr);
+    }
+
+    sProcessingStack->AppendElement(elementData);
+    elementData->mAssociatedMicroTask =
+      static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
+
+    // Add a script runner to pop and process the element queue at
+    // the top of the processing stack.
+    if (shouldPushElementQueue) {
+      // Lifecycle callbacks enqueued by user agent implementation
+      // should be invoked prior to returning control back to script.
+      // Create a script runner to process the top of the processing
+      // stack as soon as it is safe to run script.
+      nsCOMPtr<nsIRunnable> runnable =
+        NS_NewRunnableFunction(&CustomElementsRegistry::ProcessTopElementQueue);
+      nsContentUtils::AddScriptRunner(runnable);
+    }
+  }
+}
+
+void
+CustomElementsRegistry::GetCustomPrototype(nsIAtom* aAtom,
+                                           JS::MutableHandle<JSObject*> aPrototype)
+{
+  mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom);
+  if (definition) {
+    aPrototype.set(definition->mPrototype);
+  } else {
+    aPrototype.set(nullptr);
+  }
+}
+
+void
+CustomElementsRegistry::UpgradeCandidates(JSContext* aCx,
+                                          nsIAtom* aKey,
+                                          CustomElementDefinition* aDefinition)
+{
+  nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
+  mCandidatesMap.RemoveAndForget(aKey, candidates);
+  if (candidates) {
+    for (size_t i = 0; i < candidates->Length(); ++i) {
+      nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
+      if (!elem) {
+        continue;
+      }
+
+      elem->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
+
+      // Make sure that the element name matches the name in the definition.
+      // (e.g. a definition for x-button extending button should match
+      // <button is="x-button"> but not <x-button>.
+      if (elem->NodeInfo()->NameAtom() != aDefinition->mLocalName) {
+        //Skip over this element because definition does not apply.
+        continue;
+      }
+
+      MOZ_ASSERT(elem->IsHTMLElement(aDefinition->mLocalName));
+      nsWrapperCache* cache;
+      CallQueryInterface(elem, &cache);
+      MOZ_ASSERT(cache, "Element doesn't support wrapper cache?");
+
+      // We want to set the custom prototype in the caller's comparment.
+      // In the case that element is in a different compartment,
+      // this will set the prototype on the element's wrapper and
+      // thus only visible in the wrapper's compartment.
+      JS::RootedObject wrapper(aCx);
+      JS::Rooted<JSObject*> prototype(aCx, aDefinition->mPrototype);
+      if ((wrapper = cache->GetWrapper()) && JS_WrapObject(aCx, &wrapper)) {
+        if (!JS_SetPrototype(aCx, wrapper, prototype)) {
+          continue;
+        }
+      }
+
+      nsContentUtils::EnqueueLifecycleCallback(
+        elem->OwnerDoc(), nsIDocument::eCreated, elem, nullptr, aDefinition);
+    }
+  }
 }
 
 JSObject*
 CustomElementsRegistry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CustomElementsRegistryBinding::Wrap(aCx, this, aGivenProto);
 }
 
 nsISupports* CustomElementsRegistry::GetParentObject() const
 {
   return mWindow;
 }
 
-void CustomElementsRegistry::Define(const nsAString& aName,
-                                    Function& aFunctionConstructor,
-                                    const ElementDefinitionOptions& aOptions,
-                                    ErrorResult& aRv)
+static const char* kLifeCycleCallbackNames[] = {
+  "connectedCallback",
+  "disconnectedCallback",
+  "adoptedCallback",
+  "attributeChangedCallback",
+  // The life cycle callbacks from v0 spec.
+  "createdCallback",
+  "attachedCallback",
+  "detachedCallback"
+};
+
+static void
+CheckLifeCycleCallbacks(JSContext* aCx,
+                        JS::Handle<JSObject*> aConstructor,
+                        ErrorResult& aRv)
+{
+  for (size_t i = 0; i < ArrayLength(kLifeCycleCallbackNames); ++i) {
+    const char* callbackName = kLifeCycleCallbackNames[i];
+    JS::Rooted<JS::Value> callbackValue(aCx);
+    if (!JS_GetProperty(aCx, aConstructor, callbackName, &callbackValue)) {
+      aRv.StealExceptionFromJSContext(aCx);
+      return;
+    }
+    if (!callbackValue.isUndefined()) {
+      if (!callbackValue.isObject()) {
+        aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_ConvertASCIItoUTF16(callbackName));
+        return;
+      }
+      JS::Rooted<JSObject*> callback(aCx, &callbackValue.toObject());
+      if (!JS::IsCallable(callback)) {
+        aRv.ThrowTypeError<MSG_NOT_CALLABLE>(NS_ConvertASCIItoUTF16(callbackName));
+        return;
+      }
+    }
+  }
+}
+
+// https://html.spec.whatwg.org/multipage/scripting.html#element-definition
+void
+CustomElementsRegistry::Define(const nsAString& aName,
+                               Function& aFunctionConstructor,
+                               const ElementDefinitionOptions& aOptions,
+                               ErrorResult& aRv)
 {
-  // TODO: This function will be implemented in bug 1275835
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  aRv.MightThrowJSException();
+
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  JSContext *cx = jsapi.cx();
+  JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.Callable());
+
+  /**
+   * 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
+   *    these steps.
+   */
+  // For now, all wrappers are constructable if they are callable. So we need to
+  // unwrap constructor to check it is really constructable.
+  JS::Rooted<JSObject*> constructorUnwrapped(cx, js::CheckedUnwrap(constructor));
+  if (!constructorUnwrapped) {
+    // If the caller's compartment does not have permission to access the
+    // unwrapped constructor then throw.
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  if (!JS::IsConstructor(constructorUnwrapped)) {
+    aRv.ThrowTypeError<MSG_NOT_CONSTRUCTOR>(NS_LITERAL_STRING("Argument 2 of CustomElementsRegistry.define"));
+    return;
+  }
+
+  /**
+   * 2. If name is not a valid custom element name, then throw a "SyntaxError"
+   *    DOMException and abort these steps.
+   */
+  nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
+  if (!nsContentUtils::IsCustomElementName(nameAtom)) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  /**
+   * 3. If this CustomElementsRegistry contains an entry with name name, then
+   *    throw a "NotSupportedError" DOMException and abort these steps.
+   */
+  if (mCustomDefinitions.Get(nameAtom)) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  /**
+   * 4. If this CustomElementsRegistry contains an entry with constructor constructor,
+   *    then throw a "NotSupportedError" DOMException and abort these steps.
+   */
+  // TODO: Step 3 of HTMLConstructor also needs a way to look up definition by
+  // using constructor. So I plans to figure out a solution to support both of
+  // them in bug 1274159.
+
+  /**
+   * 5. Let localName be name.
+   * 6. Let extends be the value of the extends member of options, or null if
+   *    no such member exists.
+   * 7. If extends is not null, then:
+   *    1. If extends is a valid custom element name, then throw a
+   *       "NotSupportedError" DOMException.
+   *    2. If the element interface for extends and the HTML namespace is
+   *       HTMLUnknownElement (e.g., if extends does not indicate an element
+   *       definition in this specification), then throw a "NotSupportedError"
+   *       DOMException.
+   *    3. Set localName to extends.
+   */
+  nsAutoString localName(aName);
+  if (aOptions.mExtends.WasPassed()) {
+    nsCOMPtr<nsIAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
+    if (nsContentUtils::IsCustomElementName(extendsAtom)) {
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return;
+    }
+
+    nsIParserService* ps = nsContentUtils::GetParserService();
+    if (!ps) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+
+    // bgsound and multicol are unknown html element.
+    int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
+    if (tag == eHTMLTag_userdefined ||
+        tag == eHTMLTag_bgsound ||
+        tag == eHTMLTag_multicol) {
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return;
+    }
+
+    localName.Assign(aOptions.mExtends.Value());
+  }
+
+  /**
+   * 8. If this CustomElementRegistry's element definition is running flag is set,
+   *    then throw a "NotSupportedError" DOMException and abort these steps.
+   */
+  if (mIsCustomDefinitionRunning) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  JS::Rooted<JSObject*> constructorPrototype(cx);
+  nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
+  { // Set mIsCustomDefinitionRunning.
+    /**
+     * 9. Set this CustomElementRegistry's element definition is running flag.
+     */
+    AutoSetRunningFlag as(this);
+
+    { // Enter constructor's compartment.
+      /**
+       * 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
+       */
+      JSAutoCompartment ac(cx, constructor);
+      JS::Rooted<JS::Value> prototypev(cx);
+      // The .prototype on the constructor passed from document.registerElement
+      // is the "expando" of a wrapper. So we should get it from wrapper instead
+      // instead of underlying object.
+      if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
+        aRv.StealExceptionFromJSContext(cx);
+        return;
+      }
+
+      /**
+       * 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
+       */
+      if (!prototypev.isObject()) {
+        aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
+        return;
+      }
+
+      constructorPrototype = &prototypev.toObject();
+    } // Leave constructor's compartment.
+
+    JS::Rooted<JSObject*> constructorProtoUnwrapped(cx, js::CheckedUnwrap(constructorPrototype));
+    if (!constructorProtoUnwrapped) {
+      // If the caller's compartment does not have permission to access the
+      // unwrapped prototype then throw.
+      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+      return;
+    }
+
+    { // Enter constructorProtoUnwrapped's compartment
+      JSAutoCompartment ac(cx, constructorProtoUnwrapped);
+
+      /**
+       * 10.3. Let lifecycleCallbacks be a map with the four keys
+       *       "connectedCallback", "disconnectedCallback", "adoptedCallback", and
+       *       "attributeChangedCallback", each of which belongs to an entry whose
+       *       value is null.
+       * 10.4. For each of the four keys callbackName in lifecycleCallbacks:
+       *       1. Let callbackValue be Get(prototype, callbackName). Rethrow any
+       *          exceptions.
+       *       2. If callbackValue is not undefined, then set the value of the
+       *          entry in lifecycleCallbacks with key callbackName to the result
+       *          of converting callbackValue to the Web IDL Function callback type.
+       *          Rethrow any exceptions from the conversion.
+       */
+      // Will do the same checking for the life cycle callbacks from v0 spec.
+      CheckLifeCycleCallbacks(cx, constructorProtoUnwrapped, aRv);
+      if (aRv.Failed()) {
+        return;
+      }
+
+      /**
+       * 10.5. Let observedAttributes be an empty sequence<DOMString>.
+       * 10.6. If the value of the entry in lifecycleCallbacks with key
+       *       "attributeChangedCallback" is not null, then:
+       *       1. Let observedAttributesIterable be Get(constructor,
+       *          "observedAttributes"). Rethrow any exceptions.
+       *       2. If observedAttributesIterable is not undefined, then set
+       *          observedAttributes to the result of converting
+       *          observedAttributesIterable to a sequence<DOMString>. Rethrow
+       *          any exceptions from the conversion.
+       */
+      // TODO: Bug 1293921 - Implement connected/disconnected/adopted/attributeChanged lifecycle callbacks for custom elements
+
+      // Note: We call the init from the constructorProtoUnwrapped's compartment
+      //       here.
+      JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped));
+      if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return;
+      }
+    } // Leave constructorProtoUnwrapped's compartment.
+  } // Unset mIsCustomDefinitionRunning
+
+  /**
+   * 11. Let definition be a new custom element definition with name name,
+   *     local name localName, constructor constructor, prototype prototype,
+   *     observed attributes observedAttributes, and lifecycle callbacks
+   *     lifecycleCallbacks.
+   */
+  // Associate the definition with the custom element.
+  nsCOMPtr<nsIAtom> localNameAtom(NS_Atomize(localName));
+  LifecycleCallbacks* callbacks = callbacksHolder.forget();
+  CustomElementDefinition* definition =
+    new CustomElementDefinition(nameAtom,
+                                localNameAtom,
+                                constructor,
+                                constructorPrototype,
+                                callbacks,
+                                0 /* TODO dependent on HTML imports. Bug 877072 */);
+
+  /**
+   * 12. Add definition to this CustomElementsRegistry.
+   */
+  mCustomDefinitions.Put(nameAtom, definition);
+
+  /**
+   * 13. 14. 15. Upgrade candidates
+   */
+  // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm
+  UpgradeCandidates(cx, nameAtom, definition);
+
+  /**
+   * 16. If this CustomElementsRegistry's when-defined promise map contains an
+   *     entry with key name:
+   *     1. Let promise be the value of that entry.
+   *     2. Resolve promise with undefined.
+   *     3. Delete the entry with key name from this CustomElementsRegistry's
+   *        when-defined promise map.
+   */
+  // TODO: Bug 1275839 - Implement CustomElementsRegistry whenDefined function
 }
 
 void
 CustomElementsRegistry::Get(JSContext* aCx, const nsAString& aName,
                             JS::MutableHandle<JS::Value> aRetVal,
                             ErrorResult& aRv)
 {
   // TODO: This function will be implemented in bug 1275838
@@ -89,25 +803,25 @@ CustomElementsRegistry::Get(JSContext* a
 already_AddRefed<Promise>
 CustomElementsRegistry::WhenDefined(const nsAString& name, ErrorResult& aRv)
 {
   // TODO: This function will be implemented in bug 1275839
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   return nullptr;
 }
 
-CustomElementDefinition::CustomElementDefinition(JSObject* aPrototype,
-                                                 nsIAtom* aType,
+CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
                                                  nsIAtom* aLocalName,
+                                                 JSObject* aConstructor,
+                                                 JSObject* aPrototype,
                                                  LifecycleCallbacks* aCallbacks,
-                                                 uint32_t aNamespaceID,
                                                  uint32_t aDocOrder)
-  : mPrototype(aPrototype),
-    mType(aType),
+  : mType(aType),
     mLocalName(aLocalName),
+    mConstructor(aConstructor),
+    mPrototype(aPrototype),
     mCallbacks(aCallbacks),
-    mNamespaceID(aNamespaceID),
     mDocOrder(aDocOrder)
 {
 }
 
 } // namespace dom
 } // namespace mozilla
\ No newline at end of file
--- a/dom/base/CustomElementsRegistry.h
+++ b/dom/base/CustomElementsRegistry.h
@@ -10,116 +10,239 @@
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "mozilla/dom/FunctionBinding.h"
 
+class nsDocument;
+
 namespace mozilla {
 namespace dom {
 
+struct CustomElementData;
 struct ElementDefinitionOptions;
 struct LifecycleCallbacks;
+class CallbackFunction;
 class Function;
 class Promise;
 
-class CustomElementHashKey : public PLDHashEntryHdr
+struct LifecycleCallbackArgs
+{
+  nsString name;
+  nsString oldValue;
+  nsString newValue;
+};
+
+class CustomElementCallback
 {
 public:
-  typedef CustomElementHashKey *KeyType;
-  typedef const CustomElementHashKey *KeyTypePointer;
-
-  CustomElementHashKey(int32_t aNamespaceID, nsIAtom *aAtom)
-    : mNamespaceID(aNamespaceID),
-      mAtom(aAtom)
-  {}
-  explicit CustomElementHashKey(const CustomElementHashKey* aKey)
-    : mNamespaceID(aKey->mNamespaceID),
-      mAtom(aKey->mAtom)
-  {}
-  ~CustomElementHashKey()
-  {}
-
-  KeyType GetKey() const { return const_cast<KeyType>(this); }
-  bool KeyEquals(const KeyTypePointer aKey) const
+  CustomElementCallback(Element* aThisObject,
+                        nsIDocument::ElementCallbackType aCallbackType,
+                        CallbackFunction* aCallback,
+                        CustomElementData* aOwnerData);
+  void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
+  void Call();
+  void SetArgs(LifecycleCallbackArgs& aArgs)
   {
-    MOZ_ASSERT(mNamespaceID != kNameSpaceID_Unknown,
-               "This equals method is not transitive, nor symmetric. "
-               "A key with a namespace of kNamespaceID_Unknown should "
-               "not be stored in a hashtable.");
-    return (kNameSpaceID_Unknown == aKey->mNamespaceID ||
-            mNamespaceID == aKey->mNamespaceID) &&
-           aKey->mAtom == mAtom;
+    MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
+               "Arguments are only used by attribute changed callback.");
+    mArgs = aArgs;
   }
 
-  static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
-  static PLDHashNumber HashKey(const KeyTypePointer aKey)
-  {
-    return aKey->mAtom->hash();
-  }
-  enum { ALLOW_MEMMOVE = true };
+private:
+  // The this value to use for invocation of the callback.
+  RefPtr<Element> mThisObject;
+  RefPtr<CallbackFunction> mCallback;
+  // The type of callback (eCreated, eAttached, etc.)
+  nsIDocument::ElementCallbackType mType;
+  // Arguments to be passed to the callback,
+  // used by the attribute changed callback.
+  LifecycleCallbackArgs mArgs;
+  // CustomElementData that contains this callback in the
+  // callback queue.
+  CustomElementData* mOwnerData;
+};
+
+// Each custom element has an associated callback queue and an element is
+// being created flag.
+struct CustomElementData
+{
+  NS_INLINE_DECL_REFCOUNTING(CustomElementData)
+
+  explicit CustomElementData(nsIAtom* aType);
+  // Objects in this array are transient and empty after each microtask
+  // checkpoint.
+  nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
+  // Custom element type, for <button is="x-button"> or <x-button>
+  // this would be x-button.
+  nsCOMPtr<nsIAtom> mType;
+  // The callback that is next to be processed upon calling RunCallbackQueue.
+  int32_t mCurrentCallback;
+  // Element is being created flag as described in the custom elements spec.
+  bool mElementIsBeingCreated;
+  // Flag to determine if the created callback has been invoked, thus it
+  // determines if other callbacks can be enqueued.
+  bool mCreatedCallbackInvoked;
+  // The microtask level associated with the callbacks in the callback queue,
+  // it is used to determine if a new queue needs to be pushed onto the
+  // processing stack.
+  int32_t mAssociatedMicroTask;
+
+  // Empties the callback queue.
+  void RunCallbackQueue();
 
 private:
-  int32_t mNamespaceID;
-  nsCOMPtr<nsIAtom> mAtom;
+  virtual ~CustomElementData() {}
 };
 
 // The required information for a custom element as defined in:
-// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
+// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
 struct CustomElementDefinition
 {
-  CustomElementDefinition(JSObject* aPrototype,
-                          nsIAtom* aType,
+  CustomElementDefinition(nsIAtom* aType,
                           nsIAtom* aLocalName,
+                          JSObject* aConstructor,
+                          JSObject* aPrototype,
                           mozilla::dom::LifecycleCallbacks* aCallbacks,
-                          uint32_t aNamespaceID,
                           uint32_t aDocOrder);
 
-  // The prototype to use for new custom elements of this type.
-  JS::Heap<JSObject *> mPrototype;
-
   // The type (name) for this custom element.
   nsCOMPtr<nsIAtom> mType;
 
   // The localname to (e.g. <button is=type> -- this would be button).
   nsCOMPtr<nsIAtom> mLocalName;
 
+  // The custom element constructor.
+  JS::Heap<JSObject *> mConstructor;
+
+  // The prototype to use for new custom elements of this type.
+  JS::Heap<JSObject *> mPrototype;
+
   // The lifecycle callbacks to call for this custom element.
   nsAutoPtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
 
   // Whether we're currently calling the created callback for a custom element
   // of this type.
   bool mElementIsBeingCreated;
 
-  // Element namespace.
-  int32_t mNamespaceID;
+  // A construction stack.
+  // TODO: Bug 1287348 - Implement construction stack for upgrading an element
 
   // The document custom element order.
   uint32_t mDocOrder;
 };
 
 class CustomElementsRegistry final : public nsISupports,
                                      public nsWrapperCache
 {
+  // Allow nsDocument to access mCustomDefinitions and mCandidatesMap.
+  friend class ::nsDocument;
+
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CustomElementsRegistry)
 
 public:
   static bool IsCustomElementsEnabled(JSContext* aCx, JSObject* aObject);
   static already_AddRefed<CustomElementsRegistry> Create(nsPIDOMWindowInner* aWindow);
-  already_AddRefed<nsIDocument> GetOwnerDocument() const;
+  static void ProcessTopElementQueue();
+
+  static void XPCOMShutdown();
+
+  /**
+   * Looking up a custom element definition.
+   * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
+   */
+  CustomElementDefinition* LookupCustomElementDefinition(
+    const nsAString& aLocalName, const nsAString* aIs = nullptr) const;
+
+  /**
+   * Enqueue created callback or register upgrade candidate for
+   * newly created custom elements, possibly extending an existing type.
+   * ex. <x-button>, <button is="x-button> (type extension)
+   */
+  void SetupCustomElement(Element* aElement, const nsAString* aTypeExtension);
+
+  void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
+                                Element* aCustomElement,
+                                LifecycleCallbackArgs* aArgs,
+                                CustomElementDefinition* aDefinition);
+
+  void GetCustomPrototype(nsIAtom* aAtom,
+                          JS::MutableHandle<JSObject*> aPrototype);
 
 private:
   explicit CustomElementsRegistry(nsPIDOMWindowInner* aWindow);
   ~CustomElementsRegistry();
+
+  /**
+   * Registers an unresolved custom element that is a candidate for
+   * upgrade when the definition is registered via registerElement.
+   * |aTypeName| is the name of the custom element type, if it is not
+   * provided, then element name is used. |aTypeName| should be provided
+   * when registering a custom element that extends an existing
+   * element. e.g. <button is="x-button">.
+   */
+  void RegisterUnresolvedElement(Element* aElement,
+                                 nsIAtom* aTypeName = nullptr);
+
+  void UpgradeCandidates(JSContext* aCx,
+                         nsIAtom* aKey,
+                         CustomElementDefinition* aDefinition);
+
+  typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition>
+    DefinitionMap;
+  typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
+    CandidateMap;
+
+  // Hashtable for custom element definitions in web components.
+  // Custom prototypes are stored in the compartment where
+  // registerElement was called.
+  DefinitionMap mCustomDefinitions;
+
+  // The "upgrade candidates map" from the web components spec. Maps from a
+  // namespace id and local name to a list of elements to upgrade if that
+  // element is registered as a custom element.
+  CandidateMap mCandidatesMap;
+
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 
+  // Array representing the processing stack in the custom elements
+  // specification. The processing stack is conceptually a stack of
+  // element queues. Each queue is represented by a sequence of
+  // CustomElementData in this array, separated by nullptr that
+  // represent the boundaries of the items in the stack. The first
+  // queue in the stack is the base element queue.
+  static mozilla::Maybe<nsTArray<RefPtr<CustomElementData>>> sProcessingStack;
+
+  // It is used to prevent reentrant invocations of element definition.
+  bool mIsCustomDefinitionRunning;
+
+private:
+  class MOZ_RAII AutoSetRunningFlag final {
+    public:
+      explicit AutoSetRunningFlag(CustomElementsRegistry* aRegistry)
+        : mRegistry(aRegistry)
+      {
+        MOZ_ASSERT(!mRegistry->mIsCustomDefinitionRunning,
+                   "IsCustomDefinitionRunning flag should be initially false");
+        mRegistry->mIsCustomDefinitionRunning = true;
+      }
+
+      ~AutoSetRunningFlag() {
+        mRegistry->mIsCustomDefinitionRunning = false;
+      }
+
+    private:
+      CustomElementsRegistry* mRegistry;
+  };
+
 public:
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Define(const nsAString& aName, Function& aFunctionConstructor,
               const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
 
--- a/dom/base/DOMImplementation.cpp
+++ b/dom/base/DOMImplementation.cpp
@@ -128,17 +128,16 @@ DOMImplementation::CreateDocument(const 
 
   // When DOMImplementation's createDocument method is invoked with
   // namespace set to HTML Namespace use the registry of the associated
   // document to the new instance.
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
 
   if (aNamespaceURI.EqualsLiteral("http://www.w3.org/1999/xhtml")) {
     doc->SetContentType(NS_LITERAL_STRING("application/xhtml+xml"));
-    doc->UseRegistryFromDocument(mOwner);
   } else if (aNamespaceURI.EqualsLiteral("http://www.w3.org/2000/svg")) {
     doc->SetContentType(NS_LITERAL_STRING("image/svg+xml"));
   } else {
     doc->SetContentType(NS_LITERAL_STRING("application/xml"));
   }
 
   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
 
@@ -230,20 +229,16 @@ DOMImplementation::CreateHTMLDocument(co
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<Element> body = doc->CreateElem(NS_LITERAL_STRING("body"), nullptr,
                                            kNameSpaceID_XHTML);
   rv = root->AppendChildTo(body, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // When the createHTMLDocument method is invoked,
-  // use the registry of the associated document to the new instance.
-  doc->UseRegistryFromDocument(mOwner);
-
   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
 
   doc.forget(aDocument);
   document.forget(aDOMDocument);
   return NS_OK;
 }
 
 already_AddRefed<nsIDocument>
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -465,18 +465,18 @@ Element::WrapObject(JSContext *aCx, JS::
   JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
   JS::Rooted<JSObject*> customProto(aCx);
 
   if (!givenProto) {
     // Custom element prototype swizzling.
     CustomElementData* data = GetCustomElementData();
     if (data) {
       // If this is a registered custom element then fix the prototype.
-      nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
-      document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &customProto);
+      nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
+                                         data->mType, &customProto);
       if (customProto &&
           NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
         // Just go ahead and create with the right proto up front.  Set
         // customProto to null to flag that we don't need to do any post-facto
         // proto fixups here.
         givenProto = customProto;
         customProto = nullptr;
       }
@@ -951,17 +951,17 @@ Element::GetClientAreaRect()
   nsIFrame* styledFrame;
   nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
 
   if (sf) {
     return sf->GetScrollPortRect();
   }
 
   if (styledFrame &&
-      (styledFrame->StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
+      (styledFrame->StyleDisplay()->mDisplay != StyleDisplay::Inline ||
        styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
     // Special case code to make client area work even when there isn't
     // a scroll view, see bug 180552, bug 227567.
     return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
   }
 
   // SVG nodes reach here and just return 0
   return nsRect(0, 0, 0, 0);
@@ -1603,17 +1603,18 @@ Element::BindToTree(nsIDocument* aDocume
   }
 
   nsIDocument* composedDoc = GetComposedDoc();
   if (composedDoc) {
     // Attached callback must be enqueued whenever custom element is inserted into a
     // document and this document has a browsing context.
     if (GetCustomElementData() && composedDoc->GetDocShell()) {
       // Enqueue an attached callback for the custom element.
-      composedDoc->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
+      nsContentUtils::EnqueueLifecycleCallback(
+        composedDoc, nsIDocument::eAttached, this);
     }
   }
 
   // Propagate scoped style sheet tracking bit.
   if (mParent->IsContent()) {
     nsIContent* parent;
     ShadowRoot* shadowRootParent = ShadowRoot::FromNode(mParent);
     if (shadowRootParent) {
@@ -1884,17 +1885,18 @@ Element::UnbindFromTree(bool aDeep, bool
     }
 
     document->ClearBoxObjectFor(this);
 
     // Detached must be enqueued whenever custom element is removed from
     // the document and this document has a browsing context.
     if (GetCustomElementData() && document->GetDocShell()) {
       // Enqueue a detached callback for the custom element.
-      document->EnqueueLifecycleCallback(nsIDocument::eDetached, this);
+      nsContentUtils::EnqueueLifecycleCallback(
+        document, nsIDocument::eDetached, this);
     }
   }
 
   // Unset this since that's what the old code effectively did.
   UnsetFlags(NODE_FORCE_XBL_BINDINGS);
   bool clearBindingParent = true;
 
 #ifdef MOZ_XUL
@@ -2490,17 +2492,18 @@ Element::SetAttrAndNotify(int32_t aNames
     nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
     LifecycleCallbackArgs args = {
       nsDependentAtomString(aName),
       aModType == nsIDOMMutationEvent::ADDITION ?
         NullString() : nsDependentAtomString(oldValueAtom),
       nsDependentAtomString(newValueAtom)
     };
 
-    ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
+    nsContentUtils::EnqueueLifecycleCallback(
+      ownerDoc, nsIDocument::eAttributeChanged, this, &args);
   }
 
   if (aCallAfterSetAttr) {
     rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
       OnSetDirAttr(this, &valueForAfterSetAttr,
@@ -2744,17 +2747,18 @@ Element::UnsetAttr(int32_t aNameSpaceID,
   if (ownerDoc && GetCustomElementData()) {
     nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
     LifecycleCallbackArgs args = {
       nsDependentAtomString(aName),
       nsDependentAtomString(oldValueAtom),
       NullString()
     };
 
-    ownerDoc->EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, this, &args);
+    nsContentUtils::EnqueueLifecycleCallback(
+      ownerDoc, nsIDocument::eAttributeChanged, this, &args);
   }
 
   if (aNotify) {
     // We can always pass oldValue here since there is no new value which could
     // have corrupted it.
     nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
                                   nsIDOMMutationEvent::REMOVAL, &oldValue);
   }
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -131,16 +131,17 @@ class EventChainPostVisitor;
 class EventChainPreVisitor;
 class EventChainVisitor;
 class EventListenerManager;
 class EventStateManager;
 
 namespace dom {
 
 class Animation;
+class CustomElementsRegistry;
 class Link;
 class UndoManager;
 class DOMRect;
 class DOMRectList;
 class DestinationInsertionPointList;
 class Grid;
 
 // IID for the dom::Element interface
@@ -419,17 +420,19 @@ protected:
   }
 
 private:
   // Need to allow the ESM, nsGlobalWindow, and the focus manager to
   // set our state
   friend class mozilla::EventStateManager;
   friend class ::nsGlobalWindow;
   friend class ::nsFocusManager;
-  friend class ::nsDocument;
+
+  // Allow CusomtElementRegistry to call AddStates.
+  friend class CustomElementsRegistry;
 
   // Also need to allow Link to call UpdateLinkState.
   friend class Link;
 
   void NotifyStateChange(EventStates aStates);
 
   void NotifyStyleStateChange(EventStates aStates);
 
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -730,17 +730,18 @@ protected:
     if (mFile && mIsTemporary) {
       NS_WARNING("In temporary ~BlobImplFile");
       // Ignore errors if any, not much we can do. Clean-up will be done by
       // https://mxr.mozilla.org/mozilla-central/source/xpcom/io/nsAnonymousTemporaryFile.cpp?rev=6c1c7e45c902#127
 #ifdef DEBUG
       nsresult rv =
 #endif
       mFile->Remove(false);
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to remove temporary DOMFile.");
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "Failed to remove temporary DOMFile.");
     }
   }
 
 private:
   // Create slice
   BlobImplFile(const BlobImplFile* aOther, uint64_t aStart,
                uint64_t aLength, const nsAString& aContentType)
     : BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
--- a/dom/base/SameProcessMessageQueue.cpp
+++ b/dom/base/SameProcessMessageQueue.cpp
@@ -16,17 +16,18 @@ SameProcessMessageQueue::SameProcessMess
 {
 }
 
 SameProcessMessageQueue::~SameProcessMessageQueue()
 {
   // This code should run during shutdown, and we should already have pumped the
   // event loop. So we should only see messages here if someone is sending
   // messages pretty late in shutdown.
-  NS_WARN_IF_FALSE(mQueue.IsEmpty(), "Shouldn't send messages during shutdown");
+  NS_WARNING_ASSERTION(mQueue.IsEmpty(),
+                       "Shouldn't send messages during shutdown");
   sSingleton = nullptr;
 }
 
 void
 SameProcessMessageQueue::Push(Runnable* aRunnable)
 {
   mQueue.AppendElement(aRunnable);
   NS_DispatchToCurrentThread(aRunnable);
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1729,19 +1729,19 @@ nsAttrValue::LoadImage(nsIDocument* aDoc
     ToString(val);
     NS_ASSERTION(!val.IsEmpty(),
                  "How did we end up with an empty string for eURL");
   }
 #endif
 
   MiscContainer* cont = GetMiscContainer();
   mozilla::css::URLValue* url = cont->mValue.mURL;
-  mozilla::css::ImageValue* image = 
-    new css::ImageValue(url->GetURI(), url->mString, url->mReferrer,
-                        url->mOriginPrincipal, aDocument);
+  mozilla::css::ImageValue* image =
+    new css::ImageValue(url->GetURI(), url->mString, url->mBaseURI,
+                        url->mReferrer, url->mOriginPrincipal, aDocument);
 
   NS_ADDREF(image);
   cont->mValue.mImage = image;
   NS_RELEASE(url);
   cont->mType = eImage;
 }
 
 bool
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -198,39 +198,35 @@ nsContentPolicy::CheckPolicy(CPMethod   
 
     // everyone returned failure, or no policies: sanitize result
     *decision = nsIContentPolicy::ACCEPT;
     return NS_OK;
 }
 
 //uses the parameters from ShouldXYZ to produce and log a message
 //logType must be a literal string constant
-#define LOG_CHECK(logType)                                                    \
-  PR_BEGIN_MACRO                                                              \
-    /* skip all this nonsense if the call failed or logging is disabled */    \
-    if (NS_SUCCEEDED(rv) && MOZ_LOG_TEST(gConPolLog, LogLevel::Debug)) {          \
-      const char *resultName;                                                 \
-      if (decision) {                                                         \
-        resultName = NS_CP_ResponseName(*decision);                           \
-      } else {                                                                \
-        resultName = "(null ptr)";                                            \
-      }                                                                       \
-      nsAutoCString spec("None");                                             \
-      if (contentLocation) {                                                  \
-          contentLocation->GetSpec(spec);                                     \
-      }                                                                       \
-      nsAutoCString refSpec("None");                                          \
-      if (requestingLocation) {                                               \
-          requestingLocation->GetSpec(refSpec);                               \
-      }                                                                       \
-      MOZ_LOG(gConPolLog, LogLevel::Debug,                                        \
-             ("Content Policy: " logType ": <%s> <Ref:%s> result=%s",         \
-              spec.get(), refSpec.get(), resultName)                          \
-             );                                                               \
-    }                                                                         \
+#define LOG_CHECK(logType)                                                     \
+  PR_BEGIN_MACRO                                                               \
+    /* skip all this nonsense if the call failed or logging is disabled */     \
+    if (NS_SUCCEEDED(rv) && MOZ_LOG_TEST(gConPolLog, LogLevel::Debug)) {       \
+      const char *resultName;                                                  \
+      if (decision) {                                                          \
+        resultName = NS_CP_ResponseName(*decision);                            \
+      } else {                                                                 \
+        resultName = "(null ptr)";                                             \
+      }                                                                        \
+      MOZ_LOG(gConPolLog, LogLevel::Debug,                                     \
+             ("Content Policy: " logType ": <%s> <Ref:%s> result=%s",          \
+              contentLocation ? contentLocation->GetSpecOrDefault().get()      \
+                              : "None",                                        \
+              requestingLocation ? requestingLocation->GetSpecOrDefault().get()\
+                                 : "None",                                     \
+              resultName)                                                      \
+             );                                                                \
+    }                                                                          \
   PR_END_MACRO
 
 NS_IMETHODIMP
 nsContentPolicy::ShouldLoad(uint32_t          contentType,
                             nsIURI           *contentLocation,
                             nsIURI           *requestingLocation,
                             nsISupports      *requestingContext,
                             const nsACString &mimeType,
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/AutoTimelineMarker.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/CustomElementsRegistry.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
 #include "mozilla/dom/HTMLShadowElement.h"
 #include "mozilla/dom/ipc/BlobChild.h"
@@ -5152,19 +5153,17 @@ nsContentUtils::GetMostRecentNonPBWindow
 /* static */
 void
 nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument)
 {
   nsAutoString msg;
   if (aDocument) {
     nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
     if (uri) {
-      nsCString spec;
-      uri->GetSpec(spec);
-      msg.Append(NS_ConvertUTF8toUTF16(spec));
+      msg.Append(NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault()));
       msg.AppendLiteral(" : ");
     }
   }
   msg.AppendLiteral("Unable to run script because scripts are blocked internally.");
 
   LogSimpleConsoleError(msg, "DOM");
 }
 
@@ -9428,8 +9427,128 @@ nsContentUtils::HttpsStateIsModern(nsIDo
     csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
     if (isTrustworthyOrigin) {
       return true;
     }
   }
 
   return false;
 }
+
+/* static */ CustomElementDefinition*
+nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
+                                              const nsAString& aLocalName,
+                                              uint32_t aNameSpaceID,
+                                              const nsAString* aIs)
+{
+  MOZ_ASSERT(aDoc);
+
+  // To support imported document.
+  nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
+
+  if (aNameSpaceID != kNameSpaceID_XHTML ||
+      !doc->GetDocShell()) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
+  if (!window) {
+    return nullptr;
+  }
+
+  RefPtr<CustomElementsRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return nullptr;
+  }
+
+  return registry->LookupCustomElementDefinition(aLocalName, aIs);
+}
+
+/* static */ void
+nsContentUtils::SetupCustomElement(Element* aElement,
+                                   const nsAString* aTypeExtension)
+{
+  MOZ_ASSERT(aElement);
+
+  nsCOMPtr<nsIDocument> doc = aElement->OwnerDoc();
+
+  if (!doc) {
+    return;
+  }
+
+  // To support imported document.
+  doc = doc->MasterDocument();
+
+  if (aElement->GetNameSpaceID() != kNameSpaceID_XHTML ||
+      !doc->GetDocShell()) {
+    return;
+  }
+
+  nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
+  if (!window) {
+    return;
+  }
+
+  RefPtr<CustomElementsRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return;
+  }
+
+  return registry->SetupCustomElement(aElement, aTypeExtension);
+}
+
+/* static */ void
+nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
+                                         nsIDocument::ElementCallbackType aType,
+                                         Element* aCustomElement,
+                                         LifecycleCallbackArgs* aArgs,
+                                         CustomElementDefinition* aDefinition)
+{
+  MOZ_ASSERT(aDoc);
+
+  // To support imported document.
+  nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
+
+  if (!doc->GetDocShell()) {
+    return;
+  }
+
+  nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
+  if (!window) {
+    return;
+  }
+
+  RefPtr<CustomElementsRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return;
+  }
+
+  registry->EnqueueLifecycleCallback(aType, aCustomElement, aArgs, aDefinition);
+}
+
+/* static */ void
+nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
+                                   int32_t aNamespaceID,
+                                   nsIAtom* aAtom,
+                                   JS::MutableHandle<JSObject*> aPrototype)
+{
+  MOZ_ASSERT(aDoc);
+
+  // To support imported document.
+  nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
+
+  if (aNamespaceID != kNameSpaceID_XHTML ||
+      !doc->GetDocShell()) {
+    return;
+  }
+
+  nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
+  if (!window) {
+    return;
+  }
+
+  RefPtr<CustomElementsRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return;
+  }
+
+  return registry->GetCustomPrototype(aAtom, aPrototype);
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -29,16 +29,17 @@
 #include "Units.h"
 #include "mozilla/dom/AutocompleteInfoBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "mozilla/Logging.h"
 #include "mozilla/NotNull.h"
 #include "nsIContentPolicy.h"
+#include "nsIDocument.h"
 #include "nsPIDOMWindow.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
 class imgICache;
@@ -50,17 +51,16 @@ class imgRequestProxy;
 class nsAutoScriptBlockerSuppressNodeRemoved;
 class nsHtml5StringParser;
 class nsIChannel;
 class nsIConsoleService;
 class nsIContent;
 class nsIContentPolicy;
 class nsIContentSecurityPolicy;
 class nsIDocShellTreeItem;
-class nsIDocument;
 class nsIDocumentLoaderFactory;
 class nsIDOMDocument;
 class nsIDOMDocumentFragment;
 class nsIDOMEvent;
 class nsIDOMHTMLInputElement;
 class nsIDOMKeyEvent;
 class nsIDOMNode;
 class nsIDragSession;
@@ -114,21 +114,23 @@ template<class K, class V> class nsDataH
 template<class K, class V> class nsRefPtrHashtable;
 template<class T> class nsReadingIterator;
 
 namespace mozilla {
 class ErrorResult;
 class EventListenerManager;
 
 namespace dom {
+struct CustomElementDefinition;
 class DocumentFragment;
 class Element;
 class EventTarget;
 class IPCDataTransfer;
 class IPCDataTransferItem;
+struct LifecycleCallbackArgs;
 class NodeInfo;
 class nsIContentChild;
 class nsIContentParent;
 class TabChild;
 class Selection;
 class TabParent;
 } // namespace dom
 
@@ -2671,16 +2673,40 @@ public:
   /**
    * Returns true if the "HTTPS state" of the document should be "modern". See:
    *
    * https://html.spec.whatwg.org/#concept-document-https-state
    * https://fetch.spec.whatwg.org/#concept-response-https-state
    */
   static bool HttpsStateIsModern(nsIDocument* aDocument);
 
+  /**
+   * Looking up a custom element definition.
+   * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
+   */
+  static mozilla::dom::CustomElementDefinition*
+    LookupCustomElementDefinition(nsIDocument* aDoc,
+                                  const nsAString& aLocalName,
+                                  uint32_t aNameSpaceID,
+                                  const nsAString* aIs = nullptr);
+
+  static void SetupCustomElement(Element* aElement,
+                                 const nsAString* aTypeExtension = nullptr);
+
+  static void EnqueueLifecycleCallback(nsIDocument* aDoc,
+                                       nsIDocument::ElementCallbackType aType,
+                                       Element* aCustomElement,
+                                       mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
+                                       mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
+
+  static void GetCustomPrototype(nsIDocument* aDoc,
+                                 int32_t aNamespaceID,
+                                 nsIAtom* aAtom,
+                                 JS::MutableHandle<JSObject*> prototype);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -706,18 +706,18 @@ nsDOMMutationObserver::Observe(nsINode& 
   r->SetNativeAnonymousChildList(nativeAnonymousChildList);
   r->SetAttributeFilter(Move(filters));
   r->SetAllAttributes(allAttrs);
   r->SetAnimations(animations);
   r->RemoveClones();
 
 #ifdef DEBUG
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
-    NS_WARN_IF_FALSE(mReceivers[i]->Target(),
-                     "All the receivers should have a target!");
+    NS_WARNING_ASSERTION(mReceivers[i]->Target(),
+                         "All the receivers should have a target!");
   }
 #endif
 }
 
 void
 nsDOMMutationObserver::Disconnect()
 {
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -213,16 +213,18 @@
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/NodeFilterBinding.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/UndoManager.h"
 #include "mozilla/dom/WebComponentsBinding.h"
+#include "mozilla/dom/CustomElementsRegistryBinding.h"
+#include "mozilla/dom/CustomElementsRegistry.h"
 #include "nsFrame.h"
 #include "nsDOMCaretPosition.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsViewportInfo.h"
 #include "mozilla/StaticPtr.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIEditor.h"
@@ -363,166 +365,16 @@ nsIdentifierMapEntry::RemoveContentChang
     return;
   ChangeCallback cc = { aCallback, aData, aForImage };
   mChangeCallbacks->RemoveEntry(cc);
   if (mChangeCallbacks->Count() == 0) {
     mChangeCallbacks = nullptr;
   }
 }
 
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(Registry)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry)
-  for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
-    aCallbacks.Trace(&iter.UserData()->mPrototype,
-                     "mCustomDefinitions prototype",
-                     aClosure);
-  }
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
-  for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
-    nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
-
-    if (callbacks->mAttributeChangedCallback.WasPassed()) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-        "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
-      cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
-    }
-
-    if (callbacks->mCreatedCallback.WasPassed()) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-        "mCustomDefinitions->mCallbacks->mCreatedCallback");
-      cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
-    }
-
-    if (callbacks->mAttachedCallback.WasPassed()) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-        "mCustomDefinitions->mCallbacks->mAttachedCallback");
-      cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
-    }
-
-    if (callbacks->mDetachedCallback.WasPassed()) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-        "mCustomDefinitions->mCallbacks->mDetachedCallback");
-      cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
-    }
-  }
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry)
-  tmp->mCustomDefinitions.Clear();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Registry)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(Registry)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(Registry)
-
-Registry::Registry()
-{
-  mozilla::HoldJSObjects(this);
-}
-
-Registry::~Registry()
-{
-  mozilla::DropJSObjects(this);
-}
-
-void
-CustomElementCallback::Call()
-{
-  ErrorResult rv;
-  switch (mType) {
-    case nsIDocument::eCreated:
-    {
-      // For the duration of this callback invocation, the element is being created
-      // flag must be set to true.
-      mOwnerData->mElementIsBeingCreated = true;
-
-      // The callback hasn't actually been invoked yet, but we need to flip
-      // this now in order to enqueue the attached callback. This is a spec
-      // bug (w3c bug 27437).
-      mOwnerData->mCreatedCallbackInvoked = true;
-
-      // If ELEMENT is in a document and this document has a browsing context,
-      // enqueue attached callback for ELEMENT.
-      nsIDocument* document = mThisObject->GetComposedDoc();
-      if (document && document->GetDocShell()) {
-        document->EnqueueLifecycleCallback(nsIDocument::eAttached, mThisObject);
-      }
-
-      static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
-      mOwnerData->mElementIsBeingCreated = false;
-      break;
-    }
-    case nsIDocument::eAttached:
-      static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
-      break;
-    case nsIDocument::eDetached:
-      static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
-      break;
-    case nsIDocument::eAttributeChanged:
-      static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
-        mArgs.name, mArgs.oldValue, mArgs.newValue, rv);
-      break;
-  }
-}
-
-void
-CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const
-{
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
-  aCb.NoteXPCOMChild(mThisObject);
-
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
-  aCb.NoteXPCOMChild(mCallback);
-}
-
-CustomElementCallback::CustomElementCallback(Element* aThisObject,
-                                             nsIDocument::ElementCallbackType aCallbackType,
-                                             mozilla::dom::CallbackFunction* aCallback,
-                                             CustomElementData* aOwnerData)
-  : mThisObject(aThisObject),
-    mCallback(aCallback),
-    mType(aCallbackType),
-    mOwnerData(aOwnerData)
-{
-}
-
-CustomElementData::CustomElementData(nsIAtom* aType)
-  : mType(aType),
-    mCurrentCallback(-1),
-    mElementIsBeingCreated(false),
-    mCreatedCallbackInvoked(true),
-    mAssociatedMicroTask(-1)
-{
-}
-
-void
-CustomElementData::RunCallbackQueue()
-{
-  // Note: It's possible to re-enter this method.
-  while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
-    mCallbackQueue[mCurrentCallback]->Call();
-  }
-
-  mCallbackQueue.Clear();
-  mCurrentCallback = -1;
-}
-
-} // namespace dom
-} // namespace mozilla
-
 void
 nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
                                           Element* aNewElement,
                                           bool aImageOnly)
 {
   if (!mChangeCallbacks)
     return;
 
@@ -1489,22 +1341,16 @@ nsDocument::nsDocument(const char* aCont
            ("DOCUMENT %p created", this));
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
 
   // void state used to differentiate an empty source from an unselected source
   mPreloadPictureFoundSource.SetIsVoid(true);
 
-  if (!sProcessingStack) {
-    sProcessingStack.emplace();
-    // Add the base queue sentinel to the processing stack.
-    sProcessingStack->AppendElement((CustomElementData*) nullptr);
-  }
-
   mEverInForeground = false;
 }
 
 void
 nsDocument::ClearAllBoxObjects()
 {
   if (mBoxObjectTable) {
     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
@@ -1612,18 +1458,16 @@ nsDocument::~nsDocument()
     }
   }
 
   ReportUseCounters();
 
   mInDestructor = true;
   mInUnlinkOrDeletion = true;
 
-  mRegistry = nullptr;
-
   mozilla::DropJSObjects(this);
 
   // Clear mObservers to keep it in sync with the mutationobserver list
   mObservers.Clear();
 
   if (mStyleSheetSetList) {
     mStyleSheetSetList->Disconnect();
   }
@@ -1787,17 +1631,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     if (tmp->IsLoadedAsData()) {
       loadedAsData.AssignLiteral("data");
     } else {
       loadedAsData.AssignLiteral("normal");
     }
     uint32_t nsid = tmp->GetDefaultNamespaceID();
     nsAutoCString uri;
     if (tmp->mDocumentURI)
-      tmp->mDocumentURI->GetSpec(uri);
+      uri = tmp->mDocumentURI->GetSpecOrDefault();
     if (nsid < ArrayLength(kNSURIs)) {
       SprintfLiteral(name, "nsDocument %s %s %s",
                      loadedAsData.get(), kNSURIs[nsid], uri.get());
     }
     else {
       SprintfLiteral(name, "nsDocument %s %s",
                      loadedAsData.get(), uri.get());
     }
@@ -1885,17 +1729,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks)
@@ -1970,17 +1813,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
 
   tmp->mParentDocument = nullptr;
 
@@ -2182,19 +2024,18 @@ nsDocument::Reset(nsIChannel* aChannel, 
 
 void
 nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                        nsIPrincipal* aPrincipal)
 {
   NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
 
   if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-    PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
+    PR_LogPrint("DOCUMENT %p ResetToURI %s", this,
+                aURI->GetSpecOrDefault().get());
   }
 
   mSecurityInfo = nullptr;
 
   mDocumentLoadGroup = nullptr;
 
   // Delete references to sub-documents and kill the subdocument map,
   // if any. It holds strong references
@@ -2221,23 +2062,16 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
       mChildren.RemoveChildAt(i);
       nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
       content->UnbindFromTree();
     }
     mCachedRootElement = nullptr;
   }
   mInUnlinkOrDeletion = oldVal;
 
-  if (!mMasterDocument) {
-    // "When creating an import, use the registry of the master document."
-    // Note: at this point the mMasterDocument is already set for imports
-    // (and only for imports)
-    mRegistry = nullptr;
-  }
-
   // Reset our stylesheets
   ResetStylesheetsToURI(aURI);
 
   // Release the listener manager
   if (mListenerManager) {
     mListenerManager->Disconnect();
     mListenerManager = nullptr;
   }
@@ -2523,20 +2357,18 @@ nsDocument::StartDocumentLoad(const char
                               nsILoadGroup* aLoadGroup,
                               nsISupports* aContainer,
                               nsIStreamListener **aDocListener,
                               bool aReset, nsIContentSink* aSink)
 {
   if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
     nsCOMPtr<nsIURI> uri;
     aChannel->GetURI(getter_AddRefs(uri));
-    nsAutoCString spec;
-    if (uri)
-      uri->GetSpec(spec);
-    PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get());
+    PR_LogPrint("DOCUMENT %p StartDocumentLoad %s",
+                this, uri ? uri->GetSpecOrDefault().get() : "");
   }
 
   MOZ_ASSERT(NodePrincipal()->GetAppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID,
              "Document should never have UNKNOWN_APP_ID");
 
   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
              "Bad readyState");
   SetReadyStateInternal(READYSTATE_LOADING);
@@ -4730,20 +4562,16 @@ nsDocument::SetScriptGlobalObject(nsIScr
 #endif
         bool allowDNSPrefetch;
         docShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
         mAllowDNSPrefetch = allowDNSPrefetch;
       }
     }
 
     MaybeRescheduleAnimationFrameNotifications();
-    if (Preferences::GetBool("dom.webcomponents.enabled") ||
-        Preferences::GetBool("dom.webcomponents.customelements.enabled")) {
-      mRegistry = new Registry();
-    }
   }
 
   // Remember the pointer to our window (or lack there of), to avoid
   // having to QI every time it's asked for.
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mScriptGlobalObject);
   mWindow = window;
 
   // Now that we know what our window is, we can flush the CSP errors to the
@@ -5559,36 +5387,39 @@ bool IsLowercaseASCII(const nsAString& a
     char16_t c = aValue[i];
     if (!(0x0061 <= (c) && ((c) <= 0x007a))) {
       return false;
     }
   }
   return true;
 }
 
-CustomElementDefinition*
-nsDocument::LookupCustomElementDefinition(const nsAString& aLocalName,
-                                          uint32_t aNameSpaceID,
-                                          const nsAString* aIs)
-{
-  if (!mRegistry || aNameSpaceID != kNameSpaceID_XHTML) {
+already_AddRefed<mozilla::dom::CustomElementsRegistry>
+nsDocument::GetCustomElementsRegistry()
+{
+  nsAutoString contentType;
+  GetContentType(contentType);
+  if (!IsHTMLDocument() &&
+      !contentType.EqualsLiteral("application/xhtml+xml")) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName);
-  nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
-
-  CustomElementDefinition* data;
-  CustomElementHashKey key(aNameSpaceID, typeAtom);
-  if (mRegistry->mCustomDefinitions.Get(&key, &data) &&
-      data->mLocalName == localNameAtom) {
-    return data;
-  }
-
-  return nullptr;
+  nsCOMPtr<nsPIDOMWindowInner> window(
+    do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
+                                          : GetScopeObject()));
+  if (!window) {
+    return nullptr;
+  }
+
+  RefPtr<CustomElementsRegistry> registry = window->CustomElements();
+  if (!registry) {
+    return nullptr;
+  }
+
+  return registry.forget();
 }
 
 already_AddRefed<Element>
 nsDocument::CreateElement(const nsAString& aTagName,
                           const ElementCreationOptions& aOptions,
                           ErrorResult& rv)
 {
   rv = nsContentUtils::CheckQName(aTagName, false);
@@ -5610,58 +5441,16 @@ nsDocument::CreateElement(const nsAStrin
   }
 
   RefPtr<Element> elem = CreateElem(
     needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
 
   return elem.forget();
 }
 
-void
-nsDocument::SetupCustomElement(Element* aElement,
-                               uint32_t aNamespaceID,
-                               const nsAString* aTypeExtension)
-{
-  if (!mRegistry || aNamespaceID != kNameSpaceID_XHTML) {
-    return;
-  }
-
-  nsCOMPtr<nsIAtom> tagAtom = aElement->NodeInfo()->NameAtom();
-  nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ?
-    NS_Atomize(*aTypeExtension) : tagAtom;
-
-  if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
-    // Custom element setup in the parser happens after the "is"
-    // attribute is added.
-    aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
-  }
-
-  CustomElementDefinition* data = LookupCustomElementDefinition(
-    aElement->NodeInfo()->LocalName(), aNamespaceID, aTypeExtension);
-
-  if (!data) {
-    // The type extension doesn't exist in the registry,
-    // thus we don't need to enqueue callback or adjust
-    // the "is" attribute, but it is possibly an upgrade candidate.
-    RegisterUnresolvedElement(aElement, typeAtom);
-    return;
-  }
-
-  if (data->mLocalName != tagAtom) {
-    // The element doesn't match the local name for the
-    // definition, thus the element isn't a custom element
-    // and we don't need to do anything more.
-    return;
-  }
-
-  // Enqueuing the created callback will set the CustomElementData on the
-  // element, causing prototype swizzling to occur in Element::WrapObject.
-  EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data);
-}
-
 NS_IMETHODIMP
 nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
                             const nsAString& aQualifiedName,
                             nsIDOMElement** aReturn)
 {
   *aReturn = nullptr;
   ElementCreationOptions options;
   ErrorResult rv;
@@ -5911,35 +5700,38 @@ nsDocument::CustomElementConstructor(JSC
   // Function name is the type of the custom element.
   JSString* jsFunName =
     JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
   nsAutoJSString elemName;
   if (!elemName.init(aCx, jsFunName)) {
     return true;
   }
 
+  RefPtr<mozilla::dom::CustomElementsRegistry> registry = window->CustomElements();
+  if (!registry) {
+    return true;
+  }
+
   nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
-  CustomElementHashKey key(kNameSpaceID_Unknown, typeAtom);
-  CustomElementDefinition* definition;
-  if (!document->mRegistry ||
-      !document->mRegistry->mCustomDefinitions.Get(&key, &definition)) {
+  CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom);
+  if (!definition) {
     return true;
   }
 
   nsDependentAtomString localName(definition->mLocalName);
 
   nsCOMPtr<Element> element =
-    document->CreateElem(localName, nullptr, definition->mNamespaceID);
+    document->CreateElem(localName, nullptr, kNameSpaceID_XHTML);
   NS_ENSURE_TRUE(element, true);
 
   if (definition->mLocalName != typeAtom) {
     // This element is a custom element by extension, thus we need to
     // do some special setup. For non-extended custom elements, this happens
     // when the element is created.
-    document->SetupCustomElement(element, definition->mNamespaceID, &elemName);
+    nsContentUtils::SetupCustomElement(element, &elemName);
   }
 
   nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
   NS_ENSURE_SUCCESS(rv, true);
 
   return true;
 }
 
@@ -5970,447 +5762,92 @@ nsDocument::IsWebComponentsEnabled(JSCon
     NS_ENSURE_SUCCESS(rv, false);
 
     return perm == nsIPermissionManager::ALLOW_ACTION;
   }
 
   return false;
 }
 
-nsresult
-nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
-{
-  if (!mRegistry) {
-    return NS_OK;
-  }
-
-  mozilla::dom::NodeInfo* info = aElement->NodeInfo();
-
-  // Candidate may be a custom element through extension,
-  // in which case the custom element type name will not
-  // match the element tag name. e.g. <button is="x-button">.
-  nsCOMPtr<nsIAtom> typeName = aTypeName;
-  if (!typeName) {
-    typeName = info->NameAtom();
-  }
-
-  CustomElementHashKey key(info->NamespaceID(), typeName);
-  if (mRegistry->mCustomDefinitions.Get(&key)) {
-    return NS_OK;
-  }
-
-  nsTArray<nsWeakPtr>* unresolved;
-  mRegistry->mCandidatesMap.Get(&key, &unresolved);
-  if (!unresolved) {
-    unresolved = new nsTArray<nsWeakPtr>();
-    // Ownership of unresolved is taken by mCandidatesMap.
-    mRegistry->mCandidatesMap.Put(&key, unresolved);
-  }
-
-  nsWeakPtr* elem = unresolved->AppendElement();
-  *elem = do_GetWeakReference(aElement);
-  aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
-
-  return NS_OK;
-}
-
-void
-nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
-                                     Element* aCustomElement,
-                                     LifecycleCallbackArgs* aArgs,
-                                     CustomElementDefinition* aDefinition)
-{
-  if (!mRegistry) {
-    // The element might not belong to a document that
-    // has a browsing context, and thus no registry.
-    return;
-  }
-
-  CustomElementData* elementData = aCustomElement->GetCustomElementData();
-
-  // Let DEFINITION be ELEMENT's definition
-  CustomElementDefinition* definition = aDefinition;
-  if (!definition) {
-    mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
-
-    // Make sure we get the correct definition in case the element
-    // is a extended custom element e.g. <button is="x-button">.
-    nsCOMPtr<nsIAtom> typeAtom = elementData ?
-      elementData->mType.get() : info->NameAtom();
-
-    CustomElementHashKey key(info->NamespaceID(), typeAtom);
-    if (!mRegistry->mCustomDefinitions.Get(&key, &definition) ||
-        definition->mLocalName != info->NameAtom()) {
-      // Trying to enqueue a callback for an element that is not
-      // a custom element. We are done, nothing to do.
-      return;
-    }
-  }
-
-  if (!elementData) {
-    // Create the custom element data the first time
-    // that we try to enqueue a callback.
-    elementData = new CustomElementData(definition->mType);
-    // aCustomElement takes ownership of elementData
-    aCustomElement->SetCustomElementData(elementData);
-    MOZ_ASSERT(aType == nsIDocument::eCreated,
-               "First callback should be the created callback");
-  }
-
-  // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
-  CallbackFunction* func = nullptr;
-  switch (aType) {
-    case nsIDocument::eCreated:
-      if (definition->mCallbacks->mCreatedCallback.WasPassed()) {
-        func = definition->mCallbacks->mCreatedCallback.Value();
-      }
-      break;
-
-    case nsIDocument::eAttached:
-      if (definition->mCallbacks->mAttachedCallback.WasPassed()) {
-        func = definition->mCallbacks->mAttachedCallback.Value();
-      }
-      break;
-
-    case nsIDocument::eDetached:
-      if (definition->mCallbacks->mDetachedCallback.WasPassed()) {
-        func = definition->mCallbacks->mDetachedCallback.Value();
-      }
-      break;
-
-    case nsIDocument::eAttributeChanged:
-      if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
-        func = definition->mCallbacks->mAttributeChangedCallback.Value();
-      }
-      break;
-  }
-
-  // If there is no such callback, stop.
-  if (!func) {
-    return;
-  }
-
-  if (aType == nsIDocument::eCreated) {
-    elementData->mCreatedCallbackInvoked = false;
-  } else if (!elementData->mCreatedCallbackInvoked) {
-    // Callbacks other than created callback must not be enqueued
-    // until after the created callback has been invoked.
-    return;
-  }
-
-  // Add CALLBACK to ELEMENT's callback queue.
-  CustomElementCallback* callback = new CustomElementCallback(aCustomElement,
-                                                              aType,
-                                                              func,
-                                                              elementData);
-  // Ownership of callback is taken by mCallbackQueue.
-  elementData->mCallbackQueue.AppendElement(callback);
-  if (aArgs) {
-    callback->SetArgs(*aArgs);
-  }
-
-  if (!elementData->mElementIsBeingCreated) {
-    CustomElementData* lastData =
-      sProcessingStack->SafeLastElement(nullptr);
-
-    // A new element queue needs to be pushed if the queue at the
-    // top of the stack is associated with another microtask level.
-    bool shouldPushElementQueue =
-      (!lastData || lastData->mAssociatedMicroTask <
-         static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
-
-    // Push a new element queue onto the processing stack when appropriate
-    // (when we enter a new microtask).
-    if (shouldPushElementQueue) {
-      // Push a sentinel value on the processing stack to mark the
-      // boundary between the element queues.
-      sProcessingStack->AppendElement((CustomElementData*) nullptr);
-    }
-
-    sProcessingStack->AppendElement(elementData);
-    elementData->mAssociatedMicroTask =
-      static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
-
-    // Add a script runner to pop and process the element queue at
-    // the top of the processing stack.
-    if (shouldPushElementQueue) {
-      // Lifecycle callbacks enqueued by user agent implementation
-      // should be invoked prior to returning control back to script.
-      // Create a script runner to process the top of the processing
-      // stack as soon as it is safe to run script.
-      nsCOMPtr<nsIRunnable> runnable =
-        NS_NewRunnableFunction(&nsDocument::ProcessTopElementQueue);
-      nsContentUtils::AddScriptRunner(runnable);
-    }
-  }
-}
-
-// static
-void
-nsDocument::ProcessTopElementQueue()
-{
-  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
-
-  nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack;
-  uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
-
-  for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
-    // Callback queue may have already been processed in an earlier
-    // element queue or in an element queue that was popped
-    // off more recently.
-    if (stack[i]->mAssociatedMicroTask != -1) {
-      stack[i]->RunCallbackQueue();
-      stack[i]->mAssociatedMicroTask = -1;
-    }
-  }
-
-  // If this was actually the base element queue, don't bother trying to pop
-  // the first "queue" marker (sentinel).
-  if (firstQueue != 0) {
-    stack.SetLength(firstQueue);
-  } else {
-    // Don't pop sentinel for base element queue.
-    stack.SetLength(1);
-  }
-}
-
-bool
-nsDocument::RegisterEnabled()
-{
-  static bool sPrefValue =
-    Preferences::GetBool("dom.webcomponents.enabled", false);
-  return sPrefValue;
-}
-
-// static
-Maybe<nsTArray<RefPtr<mozilla::dom::CustomElementData>>>
-nsDocument::sProcessingStack;
-
 void
 nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
                             const ElementRegistrationOptions& aOptions,
                             JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& rv)
 {
-  if (!mRegistry) {
+  RefPtr<CustomElementsRegistry> registry(GetCustomElementsRegistry());
+  if (!registry) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
-  Registry::DefinitionMap& definitions = mRegistry->mCustomDefinitions;
-
   // Unconditionally convert TYPE to lowercase.
   nsAutoString lcType;
   nsContentUtils::ASCIIToLower(aType, lcType);
 
-  // Only convert NAME to lowercase in HTML documents. Note that NAME is
-  // options.extends.
-  nsAutoString lcName;
-  if (IsHTMLDocument()) {
-    nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName);
-  } else {
-    lcName.Assign(aOptions.mExtends);
-  }
-
-  nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(lcType));
-  if (!nsContentUtils::IsCustomElementName(typeAtom)) {
-    rv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-    return;
-  }
-
-  // If there already exists a definition with the same TYPE, set ERROR to
-  // DuplicateDefinition and stop.
-  // Note that we need to find existing custom elements from either namespace.
-  CustomElementHashKey duplicateFinder(kNameSpaceID_Unknown, typeAtom);
-  if (definitions.Get(&duplicateFinder)) {
-    rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return;
-  }
-
   nsIGlobalObject* sgo = GetScopeObject();
   if (!sgo) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
-  nsCOMPtr<nsIAtom> nameAtom;
-  int32_t namespaceID = kNameSpaceID_XHTML;
   JS::Rooted<JSObject*> protoObject(aCx);
-  {
+
+  if (!aOptions.mPrototype) {
     JS::Rooted<JSObject*> htmlProto(aCx);
-    {
-      JSAutoCompartment ac(aCx, global);
-
-      htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
-      if (!htmlProto) {
-        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;
-      }
-
-      protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
-      if (!protoObject) {
-        rv.Throw(NS_ERROR_UNEXPECTED);
-        return;
-      }
-    } else {
-      protoObject = aOptions.mPrototype;
-
-      // Get the unwrapped prototype to do some checks.
-      JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
-      if (!protoObjectUnwrapped) {
-        // If the caller's compartment does not have permission to access the
-        // unwrapped prototype then throw.
-        rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-        return;
-      }
-
-      // If PROTOTYPE is already an interface prototype object for any interface
-      // object or PROTOTYPE has a non-configurable property named constructor,
-      // throw a NotSupportedError and stop.
-      const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
-      if (IsDOMIfaceAndProtoClass(clasp)) {
-        rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-        return;
-      }
-
-      JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
-      JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
-      // This check may go through a wrapper, but as we checked above
-      // it should be transparent or an xray. This should be fine for now,
-      // until the spec is sorted out.
-      if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
-        rv.Throw(NS_ERROR_UNEXPECTED);
-        return;
-      }
-
-      if (!desc.configurable()) {
-        rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-        return;
-      }
-
-      JS::Rooted<JSObject*> protoProto(aCx, protoObject);
-
-      if (!JS_WrapObject(aCx, &htmlProto)) {
-        rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-        return;
-      }
-
-      while (protoProto) {
-        if (protoProto == htmlProto) {
-          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.
-      nameAtom = NS_Atomize(lcName);
-      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 {
-      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;
-  }
-
-  // Note: We call the init from the caller compartment here
-  nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
-  JS::RootedValue rootedv(aCx, JS::ObjectValue(*wrappedProto));
-  if (!JS_WrapValue(aCx, &rootedv) || !callbacksHolder->Init(aCx, rootedv)) {
-    rv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  // Associate the definition with the custom element.
-  CustomElementHashKey key(namespaceID, typeAtom);
-  LifecycleCallbacks* callbacks = callbacksHolder.forget();
-  CustomElementDefinition* definition =
-    new CustomElementDefinition(wrappedProto,
-                                typeAtom,
-                                nameAtom,
-                                callbacks,
-                                namespaceID,
-                                0 /* TODO dependent on HTML imports. Bug 877072 */);
-  definitions.Put(&key, definition);
-
-  // Do element upgrade.
-  nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
-  mRegistry->mCandidatesMap.RemoveAndForget(&key, candidates);
-  if (candidates) {
-    for (size_t i = 0; i < candidates->Length(); ++i) {
-      nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
-      if (!elem) {
-        continue;
-      }
-
-      elem->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
-
-      // Make sure that the element name matches the name in the definition.
-      // (e.g. a definition for x-button extending button should match
-      // <button is="x-button"> but not <x-button>.
-      if (elem->NodeInfo()->NameAtom() != nameAtom) {
-        //Skip over this element because definition does not apply.
-        continue;
-      }
-
-      MOZ_ASSERT(elem->IsHTMLElement(nameAtom));
-      nsWrapperCache* cache;
-      CallQueryInterface(elem, &cache);
-      MOZ_ASSERT(cache, "Element doesn't support wrapper cache?");
-
-      // We want to set the custom prototype in the caller's comparment.
-      // In the case that element is in a different compartment,
-      // this will set the prototype on the element's wrapper and
-      // thus only visible in the wrapper's compartment.
-      JS::RootedObject wrapper(aCx);
-      if ((wrapper = cache->GetWrapper()) && JS_WrapObject(aCx, &wrapper)) {
-        if (!JS_SetPrototype(aCx, wrapper, wrappedProto)) {
-          continue;
-        }
-      }
-
-      EnqueueLifecycleCallback(nsIDocument::eCreated, elem, nullptr, definition);
+    htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
+    if (!htmlProto) {
+      rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
+
+    protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
+    if (!protoObject) {
+      rv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+  } else {
+    protoObject = aOptions.mPrototype;
+
+    // Get the unwrapped prototype to do some checks.
+    JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
+    if (!protoObjectUnwrapped) {
+      // If the caller's compartment does not have permission to access the
+      // unwrapped prototype then throw.
+      rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+      return;
+    }
+
+    // If PROTOTYPE is already an interface prototype object for any interface
+    // object or PROTOTYPE has a non-configurable property named constructor,
+    // throw a NotSupportedError and stop.
+    const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
+    if (IsDOMIfaceAndProtoClass(clasp)) {
+      rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return;
+    }
+
+    JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
+    JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
+    // This check may go through a wrapper, but as we checked above
+    // it should be transparent or an xray. This should be fine for now,
+    // until the spec is sorted out.
+    if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
+      rv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+
+    if (!desc.configurable()) {
+      rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return;
     }
   }
 
   JS::Rooted<JSFunction*> constructor(aCx);
-
   {
     // Go into the document's global compartment when creating the constructor
     // function because we want to get the correct document (where the
     // definition is registered) when it is called.
     JSAutoCompartment ac(aCx, global);
 
     // Create constructor to return. Store the name of the custom element as the
     // name of the function.
@@ -6430,27 +5867,34 @@ nsDocument::RegisterElement(JSContext* a
     return;
   }
 
   if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
+  ElementDefinitionOptions options;
+  if (!aOptions.mExtends.IsVoid()) {
+    // Only convert NAME to lowercase in HTML documents.
+    nsAutoString lcName;
+    IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
+                     : lcName.Assign(aOptions.mExtends);
+
+    options.mExtends.Construct(lcName);
+  }
+
+  RootedCallback<OwningNonNull<binding_detail::FastFunction>> functionConstructor(aCx);
+  functionConstructor = new binding_detail::FastFunction(aCx, wrappedConstructor, sgo);
+
+  registry->Define(lcType, functionConstructor, options, rv);
+
   aRetval.set(wrappedConstructor);
 }
 
-void
-nsDocument::UseRegistryFromDocument(nsIDocument* aDocument)
-{
-  nsDocument* doc = static_cast<nsDocument*>(aDocument);
-  MOZ_ASSERT(!mRegistry, "There should be no existing registry.");
-  mRegistry = doc->mRegistry;
-}
-
 NS_IMETHODIMP
 nsDocument::GetElementsByTagName(const nsAString& aTagname,
                                  nsIDOMNodeList** aReturn)
 {
   RefPtr<nsContentList> list = GetElementsByTagName(aTagname);
   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
 
   // transfer ref to aReturn
@@ -8985,18 +8429,16 @@ nsDocument::Destroy()
   mInUnlinkOrDeletion = oldVal;
 
   mLayoutHistoryState = nullptr;
 
   // Shut down our external resource map.  We might not need this for
   // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
   // tearing down all those frame trees right now is the right thing to do.
   mExternalResourceMap.Shutdown();
-
-  mRegistry = nullptr;
 }
 
 void
 nsDocument::RemovedFromDocShell()
 {
   if (mRemovedFromDocShell)
     return;
 
@@ -10339,17 +9781,18 @@ nsIDocument::CreateStaticClone(nsIDocShe
       for (int32_t i = 0; i < sheetsCount; ++i) {
         StyleSheetHandle::RefPtr sheet = GetStyleSheetAt(i);
         if (sheet) {
           if (sheet->IsApplicable()) {
             // XXXheycam Need to make ServoStyleSheet cloning work.
             if (sheet->IsGecko()) {
               RefPtr<CSSStyleSheet> clonedSheet =
                 sheet->AsGecko()->Clone(nullptr, nullptr, clonedDoc, nullptr);
-              NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!");
+              NS_WARNING_ASSERTION(clonedSheet,
+                                   "Cloning a stylesheet didn't work!");
               if (clonedSheet) {
                 clonedDoc->AddStyleSheet(clonedSheet);
               }
             } else {
               NS_ERROR("stylo: ServoStyleSheet doesn't support cloning");
             }
           }
         }
@@ -10358,17 +9801,18 @@ nsIDocument::CreateStaticClone(nsIDocShe
       // Iterate backwards to maintain order
       for (StyleSheetHandle sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
         if (sheet) {
           if (sheet->IsApplicable()) {
             // XXXheycam Need to make ServoStyleSheet cloning work.
             if (sheet->IsGecko()) {
               RefPtr<CSSStyleSheet> clonedSheet =
                 sheet->AsGecko()->Clone(nullptr, nullptr, clonedDoc, nullptr);
-              NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!");
+              NS_WARNING_ASSERTION(clonedSheet,
+                                   "Cloning a stylesheet didn't work!");
               if (clonedSheet) {
                 clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
               }
             } else {
               NS_ERROR("stylo: ServoStyleSheet doesn't support cloning");
             }
           }
         }
@@ -12414,18 +11858,20 @@ nsDocument::SetPointerLock(Element* aEle
     NS_WARNING("SetPointerLock(): Unable to get PresContext");
     return false;
   }
 
   nsCOMPtr<nsIWidget> widget;
   nsIFrame* rootFrame = shell->GetRootFrame();
   if (!NS_WARN_IF(!rootFrame)) {
     widget = rootFrame->GetNearestWidget();
-    NS_WARN_IF_FALSE(widget, "SetPointerLock(): Unable to find widget "
-                     "in shell->GetRootFrame()->GetNearestWidget();");
+    NS_WARNING_ASSERTION(
+      widget,
+      "SetPointerLock(): Unable to find widget in "
+      "shell->GetRootFrame()->GetNearestWidget();");
     if (aElement && !widget) {
       return false;
     }
   }
 
   // Hide the cursor and set pointer lock for future mouse events
   RefPtr<EventStateManager> esm = presContext->EventStateManager();
   esm->SetCursor(aCursorStyle, nullptr, false,
@@ -12572,22 +12018,16 @@ nsDocument::OnAppThemeChanged()
     }
     bool willNotify;
     bool isAlternate;
     link->UpdateStyleSheet(nullptr, &willNotify, &isAlternate, true);
   }
 }
 
 void
-nsDocument::XPCOMShutdown()
-{
-  sProcessingStack.reset();
-}
-
-void
 nsDocument::UpdateVisibilityState()
 {
   dom::VisibilityState oldState = mVisibilityState;
   mVisibilityState = GetVisibilityState();
   if (oldState != mVisibilityState) {
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("visibilitychange"),
                                          /* bubbles = */ true,
@@ -13050,18 +12490,17 @@ nsDocument::ReportUseCounters()
       (IsContentDocument() || IsResourceDoc())) {
     nsCOMPtr<nsIURI> uri;
     NodePrincipal()->GetURI(getter_AddRefs(uri));
     if (!uri || MightBeAboutOrChromeScheme(uri)) {
       return;
     }
 
     if (sDebugUseCounters) {
-      nsCString spec;
-      uri->GetSpec(spec);
+      nsCString spec = uri->GetSpecOrDefault();
 
       // URIs can be rather long for data documents, so truncate them to
       // some reasonable length.
       spec.Truncate(std::min(128U, spec.Length()));
       printf("-- Use counters for %s --\n", spec.get());
     }
 
     // We keep separate counts for individual documents and top-level
@@ -13462,14 +12901,15 @@ nsDocument::CheckCustomElementName(const
   if (!aOptions.mIs.WasPassed() ||
       !Preferences::GetBool("dom.webcomponents.enabled")) {
       return nullptr;
   }
 
   nsString* is = const_cast<nsString*>(&(aOptions.mIs.Value()));
 
   // Throw NotFoundError if 'is' is not-null and definition is null
-  if (!LookupCustomElementDefinition(aLocalName, aNamespaceID, is)) {
+  if (!nsContentUtils::LookupCustomElementDefinition(this, aLocalName,
+                                                     aNamespaceID, is)) {
       rv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
   }
 
   return is;
 }
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -258,117 +258,16 @@ private:
   nsTArray<Element*> mIdContentList;
   RefPtr<nsBaseContentList> mNameContentList;
   nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
   RefPtr<Element> mImageElement;
 };
 
 namespace mozilla {
 namespace dom {
-struct LifecycleCallbackArgs
-{
-  nsString name;
-  nsString oldValue;
-  nsString newValue;
-};
-
-struct CustomElementData;
-
-class CustomElementCallback
-{
-public:
-  CustomElementCallback(Element* aThisObject,
-                        nsIDocument::ElementCallbackType aCallbackType,
-                        mozilla::dom::CallbackFunction* aCallback,
-                        CustomElementData* aOwnerData);
-  void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
-  void Call();
-  void SetArgs(LifecycleCallbackArgs& aArgs)
-  {
-    MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
-               "Arguments are only used by attribute changed callback.");
-    mArgs = aArgs;
-  }
-
-private:
-  // The this value to use for invocation of the callback.
-  RefPtr<mozilla::dom::Element> mThisObject;
-  RefPtr<mozilla::dom::CallbackFunction> mCallback;
-  // The type of callback (eCreated, eAttached, etc.)
-  nsIDocument::ElementCallbackType mType;
-  // Arguments to be passed to the callback,
-  // used by the attribute changed callback.
-  LifecycleCallbackArgs mArgs;
-  // CustomElementData that contains this callback in the
-  // callback queue.
-  CustomElementData* mOwnerData;
-};
-
-// Each custom element has an associated callback queue and an element is
-// being created flag.
-struct CustomElementData
-{
-  NS_INLINE_DECL_REFCOUNTING(CustomElementData)
-
-  explicit CustomElementData(nsIAtom* aType);
-  // Objects in this array are transient and empty after each microtask
-  // checkpoint.
-  nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
-  // Custom element type, for <button is="x-button"> or <x-button>
-  // this would be x-button.
-  nsCOMPtr<nsIAtom> mType;
-  // The callback that is next to be processed upon calling RunCallbackQueue.
-  int32_t mCurrentCallback;
-  // Element is being created flag as described in the custom elements spec.
-  bool mElementIsBeingCreated;
-  // Flag to determine if the created callback has been invoked, thus it
-  // determines if other callbacks can be enqueued.
-  bool mCreatedCallbackInvoked;
-  // The microtask level associated with the callbacks in the callback queue,
-  // it is used to determine if a new queue needs to be pushed onto the
-  // processing stack.
-  int32_t mAssociatedMicroTask;
-
-  // Empties the callback queue.
-  void RunCallbackQueue();
-
-private:
-  virtual ~CustomElementData() {}
-};
-
-class Registry : public nsISupports
-{
-public:
-  friend class ::nsDocument;
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Registry)
-
-  Registry();
-
-protected:
-  virtual ~Registry();
-
-  typedef nsClassHashtable<mozilla::dom::CustomElementHashKey,
-                           mozilla::dom::CustomElementDefinition>
-    DefinitionMap;
-  typedef nsClassHashtable<mozilla::dom::CustomElementHashKey,
-                           nsTArray<nsWeakPtr>>
-    CandidateMap;
-
-  // Hashtable for custom element definitions in web components.
-  // Custom prototypes are stored in the compartment where
-  // registerElement was called.
-  DefinitionMap mCustomDefinitions;
-
-  // The "upgrade candidates map" from the web components spec. Maps from a
-  // namespace id and local name to a list of elements to upgrade if that
-  // element is registered as a custom element.
-  CandidateMap mCandidatesMap;
-};
 
 } // namespace dom
 } // namespace mozilla
 
 class nsDocHeaderData
 {
 public:
   nsDocHeaderData(nsIAtom* aField, const nsAString& aData)
@@ -1213,46 +1112,16 @@ public:
   // to notify window when the page was first visited.
   void MaybeActiveMediaComponents();
 
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
-  virtual void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
-                                        Element* aCustomElement,
-                                        mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
-                                        mozilla::dom::CustomElementDefinition* aDefinition = nullptr) override;
-
-  static void ProcessTopElementQueue();
-
-  void GetCustomPrototype(int32_t aNamespaceID,
-                          nsIAtom* aAtom,
-                          JS::MutableHandle<JSObject*> prototype)
-  {
-    if (!mRegistry) {
-      prototype.set(nullptr);
-      return;
-    }
-
-    mozilla::dom::CustomElementHashKey key(aNamespaceID, aAtom);
-    mozilla::dom::CustomElementDefinition* definition;
-    if (mRegistry->mCustomDefinitions.Get(&key, &definition)) {
-      prototype.set(definition->mPrototype);
-    } else {
-      prototype.set(nullptr);
-    }
-  }
-
-  static bool RegisterEnabled();
-
-  virtual nsresult RegisterUnresolvedElement(mozilla::dom::Element* aElement,
-                                             nsIAtom* aTypeName = nullptr) override;
-
   // WebIDL bits
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) override;
   virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
                     JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) override;
@@ -1263,29 +1132,27 @@ public:
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) override;
   virtual already_AddRefed<Element> CreateElement(const nsAString& aTagName,
                                                   const mozilla::dom::ElementCreationOptions& aOptions,
                                                   ErrorResult& rv) override;
   virtual already_AddRefed<Element> CreateElementNS(const nsAString& aNamespaceURI,
                                                     const nsAString& aQualifiedName,
                                                     const mozilla::dom::ElementCreationOptions& aOptions,
                                                     mozilla::ErrorResult& rv) override;
-  virtual void UseRegistryFromDocument(nsIDocument* aDocument) override;
 
   virtual nsIDocument* MasterDocument() override
   {
     return mMasterDocument ? mMasterDocument.get()
                            : this;
   }
 
   virtual void SetMasterDocument(nsIDocument* master) override
   {
     MOZ_ASSERT(master);
     mMasterDocument = master;
-    UseRegistryFromDocument(mMasterDocument);
   }
 
   virtual bool IsMasterDocument() override
   {
     return !mMasterDocument;
   }
 
   virtual mozilla::dom::ImportManager* ImportManager() override
@@ -1392,18 +1259,16 @@ protected:
   Element* GetTitleElement();
 
 public:
   // Get our title
   virtual void GetTitle(nsString& aTitle) override;
   // Set our title
   virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv) override;
 
-  static void XPCOMShutdown();
-
   bool mIsTopLevelContentDocument: 1;
   bool mIsContentDocument: 1;
 
   bool IsTopLevelContentDocument();
   void SetIsTopLevelContentDocument(bool aIsTopLevelContentDocument);
 
   bool IsContentDocument() const;
   void SetIsContentDocument(bool aIsContentDocument);
@@ -1498,60 +1363,38 @@ protected:
   // pop one off this stack, restoring the previous full-screen state
   nsTArray<nsWeakPtr> mFullScreenStack;
 
   // The root of the doc tree in which this document is in. This is only
   // non-null when this document is in fullscreen mode.
   nsWeakPtr mFullscreenRoot;
 
 private:
-  // Array representing the processing stack in the custom elements
-  // specification. The processing stack is conceptually a stack of
-  // element queues. Each queue is represented by a sequence of
-  // CustomElementData in this array, separated by nullptr that
-  // represent the boundaries of the items in the stack. The first
-  // queue in the stack is the base element queue.
-  static mozilla::Maybe<nsTArray<RefPtr<mozilla::dom::CustomElementData>>> sProcessingStack;
-
   static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
 
   /**
-   * Looking up a custom element definition.
-   * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
-   */
-  mozilla::dom::CustomElementDefinition* LookupCustomElementDefinition(
-    const nsAString& aLocalName, uint32_t aNameSpaceID, const nsAString* aIs);
-
-  /**
    * Check if the passed custom element name, aOptions.mIs, is a registered
    * custom element type or not, then return the custom element name for future
    * usage.
    *
    * If there is no existing custom element definition for this name, throw a
    * NotFoundError.
    */
   nsString* CheckCustomElementName(
     const mozilla::dom::ElementCreationOptions& aOptions,
     const nsAString& aLocalName,
     uint32_t aNamespaceID,
     ErrorResult& rv);
 
 public:
-  // Enqueue created callback or register upgrade candidate for
-  // newly created custom elements, possibly extending an existing type.
-  // ex. <x-button>, <button is="x-button> (type extension)
-  virtual void SetupCustomElement(Element* aElement,
-                                  uint32_t aNamespaceID,
-                                  const nsAString* aTypeExtension) override;
+  virtual already_AddRefed<mozilla::dom::CustomElementsRegistry>
+    GetCustomElementsRegistry() override;
 
   static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
 
-  // The "registry" from the web components spec.
-  RefPtr<mozilla::dom::Registry> mRegistry;
-
   RefPtr<mozilla::EventListenerManager> mListenerManager;
   RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   RefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
   /* mIdentifierMap works as follows for IDs:
    * 1) Attribute changes affect the table immediately (removing and adding
    *    entries as needed).
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -507,19 +507,19 @@ nsFocusManager::MoveFocus(mozIDOMWindowP
 {
   *aElement = nullptr;
 
   LOGFOCUS(("<<MoveFocus begin Type: %d Flags: %x>>", aType, aFlags));
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug) && mFocusedWindow) {
     nsIDocument* doc = mFocusedWindow->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      nsAutoCString spec;
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS((" Focused Window: %p %s", mFocusedWindow.get(), spec.get()));
+      LOGFOCUS((" Focused Window: %p %s",
+                mFocusedWindow.get(),
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
   }
 
   LOGCONTENT("  Current Focus: %s", mFocusedContent.get());
 
   // use FLAG_BYMOVEFOCUS when switching focus with MoveFocus unless one of
   // the other focus methods is already set, or we're just moving to the root
   // or caret position.
@@ -659,27 +659,26 @@ nsFocusManager::MoveCaretToFocus(mozIDOM
 NS_IMETHODIMP
 nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Raised [Currently: %p %p]", aWindow, mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Raised Window: %p %s", aWindow, spec.get()));
+      LOGFOCUS(("  Raised Window: %p %s", aWindow,
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %p %s", mActiveWindow.get(), spec.get()));
+        LOGFOCUS(("  Active Window: %p %s", mActiveWindow.get(),
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (mActiveWindow == window) {
     // The window is already active, so there is no need to focus anything,
     // but make sure that the right widget is focused. This is a special case
     // for Windows because when restoring a minimized window, a second
@@ -745,27 +744,26 @@ nsFocusManager::WindowRaised(mozIDOMWind
 NS_IMETHODIMP
 nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Lowered [Currently: %p %p]", aWindow, mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Lowered Window: %s", spec.get()));
+      LOGFOCUS(("  Lowered Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %s", spec.get()));
+        LOGFOCUS(("  Active Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (mActiveWindow != window)
     return NS_OK;
 
   // clear the mouse capture as the active window has changed
@@ -874,28 +872,27 @@ nsFocusManager::ContentRemoved(nsIDocume
 NS_IMETHODIMP
 nsFocusManager::WindowShown(mozIDOMWindowProxy* aWindow, bool aNeedsFocus)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Shown [Currently: %p %p]", window.get(), mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("Shown Window: %s", spec.get()));
+      LOGFOCUS(("Shown Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
 
     if (mFocusedWindow) {
       doc = mFocusedWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS((" Focused Window: %s", spec.get()));
+        LOGFOCUS((" Focused Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (nsIDocShell* docShell = window->GetDocShell()) {
     if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
       bool active = static_cast<TabChild*>(child.get())->ParentIsActive();
       ActivateOrDeactivate(window, active);
@@ -932,33 +929,33 @@ nsFocusManager::WindowHidden(mozIDOMWind
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Hidden [Currently: %p %p]", window.get(), mActiveWindow.get(), mFocusedWindow.get()));
     nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Hide Window: %s", spec.get()));
+      LOGFOCUS(("  Hide Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
 
     if (mFocusedWindow) {
       doc = mFocusedWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Focused Window: %s", spec.get()));
+        LOGFOCUS(("  Focused Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
 
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %s", spec.get()));
+        LOGFOCUS(("  Active Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (!IsSameOrAncestor(window, mFocusedWindow))
     return NS_OK;
 
   // at this point, we know that the window being hidden is either the focused
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2224,18 +2224,18 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
                "MaybeCreateDocShell succeeded, but null mDocShell");
   if (!mDocShell) {
     return NS_ERROR_FAILURE;
   }
 
   // Check that we're still in the docshell tree.
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
-  NS_WARN_IF_FALSE(treeOwner,
-                   "Trying to load a new url to a docshell without owner!");
+  NS_WARNING_ASSERTION(treeOwner,
+                       "Trying to load a new url to a docshell without owner!");
   NS_ENSURE_STATE(treeOwner);
 
   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
     // No need to do recursion-protection here XXXbz why not??  Do we really
     // trust people not to screw up with non-content docshells?
     return NS_OK;
   }
 
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -965,19 +965,19 @@ nsGenericDOMDataNode::GetWholeText(nsASt
 {
   nsIContent* parent = GetParent();
 
   // Handle parent-less nodes
   if (!parent)
     return GetData(aWholeText);
 
   int32_t index = parent->IndexOf(this);
-  NS_WARN_IF_FALSE(index >= 0,
-                   "Trying to use .wholeText with an anonymous"
-                    "text node child of a binding parent?");
+  NS_WARNING_ASSERTION(index >= 0,
+                       "Trying to use .wholeText with an anonymous"
+                       "text node child of a binding parent?");
   NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   int32_t first =
     FirstLogicallyAdjacentTextNode(parent, index);
   int32_t last =
     LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
 
   aWholeText.Truncate();
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1354,17 +1354,17 @@ nsGlobalWindow::~nsGlobalWindow()
   }
 
   --gRefCnt;
 
 #ifdef DEBUG
   if (!PR_GetEnv("MOZ_QUIET")) {
     nsAutoCString url;
     if (mLastOpenedURI) {
-      mLastOpenedURI->GetSpec(url);
+      url = mLastOpenedURI->GetSpecOrDefault();
 
       // Data URLs can be very long, so truncate to avoid flooding the log.
       const uint32_t maxURLLength = 1000;
       if (url.Length() > maxURLLength) {
         url.Truncate(maxURLLength);
       }
     }
 
@@ -1841,17 +1841,17 @@ ImplCycleCollectionTraverse(nsCycleColle
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     nsAutoCString uri;
     if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
-      tmp->mDoc->GetDocumentURI()->GetSpec(uri);
+      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
     }
     SprintfLiteral(name, "nsGlobalWindow # %" PRIu64 " %s %s", tmp->mWindowID,
                    tmp->IsInnerWindow() ? "inner" : "outer", uri.get());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
   }
 
@@ -2988,20 +2988,18 @@ nsGlobalWindow::ClearStatus()
 void
 nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
 {
   NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
   MOZ_ASSERT(aDocument);
 
   if (gDOMLeakPRLog && MOZ_LOG_TEST(gDOMLeakPRLog, LogLevel::Debug)) {
     nsIURI *uri = aDocument->GetDocumentURI();
-    nsAutoCString spec;
-    if (uri)
-      uri->GetSpec(spec);
-    PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
+    PR_LogPrint("DOMWINDOW %p SetNewDocument %s",
+                this, uri ? uri->GetSpecOrDefault().get() : "");
   }
 
   mDoc = aDocument;
   ClearDocumentDependentSlots(aCx);
   mFocusedNode = nullptr;
   mLocalStorage = nullptr;
   mSessionStorage = nullptr;
 
@@ -6531,17 +6529,17 @@ nsGlobalWindow::FinishFullscreenChange(b
     if (!pmService) {
       return;
     }
 
     // XXXkhuey using the inner here, do we need to do something if it changes?
     ErrorResult rv;
     mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
                                        AsOuter()->GetCurrentInnerWindow(), rv);
-    NS_WARN_IF_FALSE(!rv.Failed(), "Failed to lock the wakelock");
+    NS_WARNING_ASSERTION(!rv.Failed(), "Failed to lock the wakelock");
     rv.SuppressException();
   } else if (mWakeLock && !mFullScreen) {
     ErrorResult rv;
     mWakeLock->Unlock(rv);
     mWakeLock = nullptr;
     rv.SuppressException();
   }
 }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2477,44 +2477,23 @@ public:
     eCreated,
     eAttached,
     eDetached,
     eAttributeChanged
   };
 
   nsIDocument* GetTopLevelContentDocument();
 
-  /**
-   * Registers an unresolved custom element that is a candidate for
-   * upgrade when the definition is registered via registerElement.
-   * |aTypeName| is the name of the custom element type, if it is not
-   * provided, then element name is used. |aTypeName| should be provided
-   * when registering a custom element that extends an existing
-   * element. e.g. <button is="x-button">.
-   */
-  virtual nsresult RegisterUnresolvedElement(Element* aElement,
-                                             nsIAtom* aTypeName = nullptr) = 0;
-  virtual void EnqueueLifecycleCallback(ElementCallbackType aType,
-                                        Element* aCustomElement,
-                                        mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
-                                        mozilla::dom::CustomElementDefinition* aDefinition = nullptr) = 0;
-  virtual void SetupCustomElement(Element* aElement,
-                                  uint32_t aNamespaceID,
-                                  const nsAString* aTypeExtension = nullptr) = 0;
   virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
                     JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) = 0;
-
-  /**
-   * In some cases, new document instances must be associated with
-   * an existing web components custom element registry as specified.
-   */
-  virtual void UseRegistryFromDocument(nsIDocument* aDocument) = 0;
+  virtual already_AddRefed<mozilla::dom::CustomElementsRegistry>
+    GetCustomElementsRegistry() = 0;
 
   already_AddRefed<nsContentList>
   GetElementsByTagName(const nsAString& aTagName)
   {
     return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
   }
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -124,18 +124,18 @@ nsInProcessTabChildGlobal::MarkForCC()
 
 nsresult
 nsInProcessTabChildGlobal::Init()
 {
 #ifdef DEBUG
   nsresult rv =
 #endif
   InitTabChildGlobal();
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                   "Couldn't initialize nsInProcessTabChildGlobal");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Couldn't initialize nsInProcessTabChildGlobal");
   mMessageManager = new nsFrameMessageManager(this,
                                               nullptr,
                                               dom::ipc::MM_CHILD);
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsInProcessTabChildGlobal)
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -526,19 +526,17 @@ PrintWinURI(nsGlobalWindow *win)
   }
 
   nsIURI *uri = doc->GetDocumentURI();
   if (!uri) {
     printf("Document doesn't have a URI.\n");
     return;
   }
 
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("%s\n", spec.get());
+  printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
 PrintWinCodebase(nsGlobalWindow *win)
 {
   if (!win) {
     printf("No window passed in.\n");
     return;
@@ -552,19 +550,17 @@ PrintWinCodebase(nsGlobalWindow *win)
 
   nsCOMPtr<nsIURI> uri;
   prin->GetURI(getter_AddRefs(uri));
   if (!uri) {
     printf("No URI, maybe the system principal.\n");
     return;
   }
 
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("%s\n", spec.get());
+  printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
 DumpString(const nsAString &str)
 {
   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
 }
 #endif
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -466,25 +466,24 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
     rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (clone->IsElement()) {
       // The cloned node may be a custom element that may require
       // enqueing created callback and prototype swizzling.
       Element* elem = clone->AsElement();
       if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
-        elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID());
+        nsContentUtils::SetupCustomElement(elem);
       } else {
         // Check if node may be custom element by type extension.
         // ex. <button is="x-button">
         nsAutoString extension;
         if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
             !extension.IsEmpty()) {
-          elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID(),
-                                               &extension);
+          nsContentUtils::SetupCustomElement(elem, &extension);
         }
       }
     }
 
     if (aParent) {
       // If we're cloning we need to insert the cloned children into the cloned
       // parent.
       rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1134,20 +1134,18 @@ nsObjectLoadingContent::OnStartRequest(n
   bool success = IsSuccessfulRequest(aRequest, &status);
 
   if (status == NS_ERROR_BLOCKED_URI) {
     nsCOMPtr<nsIConsoleService> console(
       do_GetService("@mozilla.org/consoleservice;1"));
     if (console) {
       nsCOMPtr<nsIURI> uri;
       chan->GetURI(getter_AddRefs(uri));
-      nsAutoCString spec;
-      uri->GetSpec(spec);
       nsString message = NS_LITERAL_STRING("Blocking ") +
-        NS_ConvertASCIItoUTF16(spec.get()) +
+        NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
         NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
       console->LogStringMessage(message.get());
     }
     Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
     return NS_ERROR_FAILURE;
   } else if (status == NS_ERROR_TRACKING_URI) {
     return NS_ERROR_FAILURE;
   } else {
@@ -1644,22 +1642,18 @@ nsObjectLoadingContent::CheckLoadPolicy(
                                           thisContent,
                                           mContentType,
                                           nullptr, //extra
                                           aContentPolicy,
                                           nsContentUtils::GetContentPolicy(),
                                           nsContentUtils::GetSecurityManager());
   NS_ENSURE_SUCCESS(rv, false);
   if (NS_CP_REJECTED(*aContentPolicy)) {
-    nsAutoCString uri;
-    nsAutoCString baseUri;
-    mURI->GetSpec(uri);
-    mURI->GetSpec(baseUri);
-    LOG(("OBJLC [%p]: Content policy denied load of %s (base %s)",
-         this, uri.get(), baseUri.get()));
+    LOG(("OBJLC [%p]: Content policy denied load of %s",
+         this, mURI->GetSpecOrDefault().get()));
     return false;
   }
 
   return true;
 }
 
 bool
 nsObjectLoadingContent::CheckProcessPolicy(int16_t *aContentPolicy)
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -108,17 +108,17 @@ nsPlainTextSerializer::nsPlainTextSerial
 
   mIgnoredChildNodeLevel = 0;
 }
 
 nsPlainTextSerializer::~nsPlainTextSerializer()
 {
   delete[] mTagStack;
   delete[] mOLStack;
-  NS_WARN_IF_FALSE(mHeadLevel == 0, "Wrong head level!");
+  NS_WARNING_ASSERTION(mHeadLevel == 0, "Wrong head level!");
 }
 
 NS_IMPL_ISUPPORTS(nsPlainTextSerializer,
                   nsIContentSerializer)
 
 
 NS_IMETHODIMP 
 nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -3367,17 +3367,17 @@ enum TreeTraversalState {
 static int8_t
 GetRequiredInnerTextLineBreakCount(nsIFrame* aFrame)
 {
   if (aFrame->GetContent()->IsHTMLElement(nsGkAtoms::p)) {
     return 2;
   }
   const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
   if (styleDisplay->IsBlockOutside(aFrame) ||
-      styleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) {
+      styleDisplay->mDisplay == StyleDisplay::TableCaption) {
     return 1;
   }
   return 0;
 }
 
 static bool
 IsLastCellOfRow(nsIFrame* aFrame)
 {
@@ -3484,27 +3484,29 @@ nsRange::GetInnerTextNoFlush(DOMString& 
     if (currentNode == endNode && currentState == endState) {
       break;
     }
     if (isVisibleAndNotReplaced) {
       if (currentNode->IsHTMLElement(nsGkAtoms::br)) {
         result.Append('\n');
       }
       switch (f->StyleDisplay()->mDisplay) {
-      case NS_STYLE_DISPLAY_TABLE_CELL:
+      case StyleDisplay::TableCell:
         if (!IsLastCellOfRow(f)) {
           result.Append('\t');
         }
         break;
-      case NS_STYLE_DISPLAY_TABLE_ROW:
+      case StyleDisplay::TableRow:
         if (!IsLastRowOfRowGroup(f) ||
             !IsLastNonemptyRowGroupOfTable(f->GetParent())) {
           result.Append('\n');
         }
         break;
+      default:
+        break; // Do nothing
       }
       result.AddRequiredLineBreakCount(GetRequiredInnerTextLineBreakCount(f));
     }
     nsIContent* next = currentNode->GetNextSibling();
     if (next) {
       currentNode = next;
       currentState = AT_NODE;
     } else {
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1913,16 +1913,18 @@ nsScriptLoader::ProcessRequest(nsScriptL
 
   nsCOMPtr<nsIScriptElement> oldParserInsertedScript;
   uint32_t parserCreated = aRequest->mElement->GetParserCreated();
   if (parserCreated) {
     oldParserInsertedScript = mCurrentParserInsertedScript;
     mCurrentParserInsertedScript = aRequest->mElement;
   }
 
+  aRequest->mElement->BeginEvaluating();
+
   FireScriptAvailable(NS_OK, aRequest);
 
   // The window may have gone away by this point, in which case there's no point
   // in trying to run the script.
   nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
   {
     // Try to perform a microtask checkpoint
     nsAutoMicroTask mt;
@@ -1943,31 +1945,31 @@ nsScriptLoader::ProcessRequest(nsScriptL
     runScript = false;
   }
 
   nsresult rv = NS_OK;
   if (runScript) {
     if (doc) {
       doc->BeginEvaluatingExternalScript();
     }
-    aRequest->mElement->BeginEvaluating();
     rv = EvaluateScript(aRequest);
-    aRequest->mElement->EndEvaluating();
     if (doc) {
       doc->EndEvaluatingExternalScript();
     }
 
     nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
                                          scriptElem,
                                          NS_LITERAL_STRING("afterscriptexecute"),
                                          true, false);
   }
 
   FireScriptEvaluated(rv, aRequest);
 
+  aRequest->mElement->EndEvaluating();
+
   if (parserCreated) {
     mCurrentParserInsertedScript = oldParserInsertedScript;
   }
 
   if (aRequest->mOffThreadToken) {
     // The request was parsed off-main-thread, but the result of the off
     // thread parse was not actually needed to process the request
     // (disappearing window, some other error, ...). Finish the
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -165,18 +165,17 @@ static void
 AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
 {
   nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
 
   if (uri) {
     if (aAnonymize && !aWindow->IsChromeWindow()) {
       aStr.AppendPrintf("<anonymized-%llu>", aWindow->WindowID());
     } else {
-      nsCString spec;
-      uri->GetSpec(spec);
+      nsCString spec = uri->GetSpecOrDefault();
 
       // A hack: replace forward slashes with '\\' so they aren't
       // treated as path separators.  Users of the reporters
       // (such as about:memory) have to undo this change.
       spec.ReplaceChar('/', '\\');
 
       aStr += spec;
     }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4474,19 +4474,16 @@ def getJSToNativeConversionInfo(type, de
 
     def incrementNestingLevel():
         if nestingLevel is "":
             return 1
         return nestingLevel + 1
 
     assert not (isEnforceRange and isClamp)  # These are mutually exclusive
 
-    if type.isArray():
-        raise TypeError("Can't handle array arguments yet")
-
     if type.isSequence():
         assert not isEnforceRange and not isClamp
 
         if failureCode is None:
             notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
                            "%s" % (firstCap(sourceDescription), exceptionCode))
         else:
             notSequence = failureCode
@@ -4749,26 +4746,26 @@ def getJSToNativeConversionInfo(type, de
                     CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
                               (unionArgumentObj, name)))
                 names.append(name)
             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
                                         pre="done = ", post=";\n\n", reindent=True)
         else:
             interfaceObject = None
 
-        arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
-        if len(arrayObjectMemberTypes) > 0:
-            assert len(arrayObjectMemberTypes) == 1
-            name = getUnionMemberName(arrayObjectMemberTypes[0])
-            arrayObject = CGGeneric(
+        sequenceObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
+        if len(sequenceObjectMemberTypes) > 0:
+            assert len(sequenceObjectMemberTypes) == 1
+            name = getUnionMemberName(sequenceObjectMemberTypes[0])
+            sequenceObject = CGGeneric(
                 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
-            arrayObject = None
+            sequenceObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
             memberType = dateObjectMemberTypes[0]
             name = getUnionMemberName(memberType)
             dateObject = CGGeneric("%s.SetTo%s(cx, ${val});\n"
                                    "done = true;\n" % (unionArgumentObj, name))
@@ -4820,26 +4817,26 @@ def getJSToNativeConversionInfo(type, de
             object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
                                "%s"
                                "}\n"
                                "done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
             names.append(objectMemberTypes[0].name)
         else:
             object = None
 
-        hasObjectTypes = interfaceObject or arrayObject or dateObject or callbackObject or object or mozMapObject
+        hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject
         if hasObjectTypes:
             # "object" is not distinguishable from other types
-            assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
-            if arrayObject or dateObject or callbackObject:
-                # An object can be both an array object and a callback or
+            assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject)
+            if sequenceObject or dateObject or callbackObject:
+                # An object can be both an sequence object and a callback or
                 # dictionary, but we shouldn't have both in the union's members
                 # because they are not distinguishable.
-                assert not (arrayObject and callbackObject)
-                templateBody = CGElseChain([arrayObject, dateObject, callbackObject])
+                assert not (sequenceObject and callbackObject)
+                templateBody = CGElseChain([sequenceObject, dateObject, callbackObject])
             else:
                 templateBody = None
             if interfaceObject:
                 assert not object
                 if templateBody:
                     templateBody = CGIfWrapper(templateBody, "!done")
                 templateBody = CGList([interfaceObject, templateBody])
             else:
@@ -6235,19 +6232,16 @@ def getWrapTemplateForType(type, descrip
             """,
             wrapCall=wrapCall,
             failureCode=failureCode,
             successCode=successCode)
 
     if type is None or type.isVoid():
         return (setUndefined(), True)
 
-    if type.isArray():
-        raise TypeError("Can't handle array return values yet")
-
     if (type.isSequence() or type.isMozMap()) and type.nullable():
         # These are both wrapped in Nullable<>
         recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
                                                         "%s.Value()" % result, successCode,
                                                         returnsNewObject, exceptionCode,
                                                         typedArraysAreStructs)
         code = fill(
             """
@@ -6647,17 +6641,17 @@ def typeNeedsScopeObject(type, retVal=Fa
                              lambda t: leafTypeNeedsScopeObject(t, retVal))
 
 
 def typeMatchesLambda(type, func):
     if type is None:
         return False
     if type.nullable():
         return typeMatchesLambda(type.inner, func)
-    if type.isSequence() or type.isMozMap() or type.isArray():
+    if type.isSequence() or type.isMozMap():
         return typeMatchesLambda(type.inner, func)
     if type.isUnion():
         return any(typeMatchesLambda(t, func) for t in
                    type.unroll().flatMemberTypes)
     if type.isDictionary():
         return dictionaryMatchesLambda(type.inner, func)
     return func(type)
 
@@ -7833,33 +7827,32 @@ class CGMethodCall(CGThing):
             # And all the overloads that take callbacks
             objectSigs.extend(s for s in possibleSignatures
                               if distinguishingType(s).isCallback())
 
             # And all the overloads that take sequences
             objectSigs.extend(s for s in possibleSignatures
                               if distinguishingType(s).isSequence())
 
-            # Now append all the overloads that take an array or dictionary or
-            # callback interface or MozMap.  There should be only one of these!
+            # Now append all the overloads that take a dictionary or callback
+            # interface or MozMap.  There should be only one of these!
             genericObjectSigs = [
                 s for s in possibleSignatures
-                if (distinguishingType(s).isArray() or
-                    distinguishingType(s).isDictionary() or
+                if (distinguishingType(s).isDictionary() or
                     distinguishingType(s).isMozMap() or
                     distinguishingType(s).isCallbackInterface())]
             assert len(genericObjectSigs) <= 1
             objectSigs.extend(genericObjectSigs)
 
             # There might be more than one thing in objectSigs; we need to check
             # which ones we unwrap to.
             if len(objectSigs) > 0:
                 # Here it's enough to guard on our argument being an object. The
                 # code for unwrapping non-callback interfaces, typed arrays,
-                # sequences, arrays, and Dates will just bail out and move on to
+                # sequences, and Dates will just bail out and move on to
                 # the next overload if the object fails to unwrap correctly,
                 # while "object" accepts any object anyway.  We could even not
                 # do the isObject() check up front here, but in cases where we
                 # have multiple object overloads it makes sense to do it only
                 # once instead of for each overload.  That will also allow the
                 # unwrapping test to skip having to do codegen for the
                 # null-or-undefined case, which we already handled above.
                 caseBody.append(CGGeneric("if (%s.isObject()) {\n" %
@@ -9081,19 +9074,16 @@ class CGMemberJITInfo(CGThing):
     @staticmethod
     def getJSReturnTypeTag(t):
         if t.nullable():
             # Sometimes it might return null, sometimes not
             return "JSVAL_TYPE_UNKNOWN"
         if t.isVoid():
             # No return, every time
             return "JSVAL_TYPE_UNDEFINED"
-        if t.isArray():
-            # No idea yet
-            assert False
         if t.isSequence():
             return "JSVAL_TYPE_OBJECT"
         if t.isMozMap():
             return "JSVAL_TYPE_OBJECT"
         if t.isGeckoInterface():
             return "JSVAL_TYPE_OBJECT"
         if t.isString():
             return "JSVAL_TYPE_STRING"
@@ -9159,19 +9149,16 @@ class CGMemberJITInfo(CGThing):
         return "JSVAL_TYPE_UNKNOWN"
 
     @staticmethod
     def getJSArgType(t):
         assert not t.isVoid()
         if t.nullable():
             # Sometimes it might return null, sometimes not
             return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner)
-        if t.isArray():
-            # No idea yet
-            assert False
         if t.isSequence():
             return "JSJitInfo::Object"
         if t.isGeckoInterface():
             return "JSJitInfo::Object"
         if t.isString():
             return "JSJitInfo::String"
         if t.isEnum():
             return "JSJitInfo::String"
@@ -9350,19 +9337,16 @@ class CGEnum(CGThing):
 def getUnionAccessorSignatureType(type, descriptorProvider):
     """
     Returns the types that are used in the getter and setter signatures for
     union types
     """
     # Flat member types have already unwrapped nullables.
     assert not type.nullable()
 
-    if type.isArray():
-        raise TypeError("Can't handle array arguments yet")
-
     if type.isSequence() or type.isMozMap():
         if type.isSequence():
             wrapperType = "Sequence"
         else:
             wrapperType = "MozMap"
         # We don't use the returned template here, so it's OK to just pass no
         # sourceDescription.
         elementInfo = getJSToNativeConversionInfo(type.inner,
@@ -13412,17 +13396,17 @@ class CGBindingRoot(CGThing):
         # Do codegen for all the dictionaries.  We have to be a bit careful
         # here, because we have to generate these in order from least derived
         # to most derived so that class inheritance works out.  We also have to
         # generate members before the dictionary that contains them.
 
         def getDependenciesFromType(type):
             if type.isDictionary():
                 return set([type.unroll().inner])
-            if type.isSequence() or type.isArray():
+            if type.isSequence():
                 return getDependenciesFromType(type.unroll())
             if type.isUnion():
                 return set([type.unroll()])
             return set()
 
         def getDependencies(unionTypeOrDictionary):
             if isinstance(unionTypeOrDictionary, IDLDictionary):
                 deps = set()
@@ -13791,19 +13775,16 @@ class CGNativeMember(ClassMethod):
         """
         The main work of getArgType.  Returns a string type decl, whether this
         is a const ref, as well as whether the type should be wrapped in
         Nullable as needed.
 
         isMember can be false or one of the strings "Sequence", "Variadic",
                  "MozMap"
         """
-        if type.isArray():
-            raise TypeError("Can't handle array arguments yet")
-
         if type.isSequence():
             nullable = type.nullable()
             if nullable:
                 type = type.inner
             elementType = type.inner
             argType = self.getArgType(elementType, False, "Sequence")[0]
             decl = CGTemplatedType("Sequence", argType)
             return decl.define(), True, True
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -21,16 +21,17 @@
  * {X} where X  is an integer representing the argument number that will
  * be replaced with a string value when the error is reported.
  */
 
 MSG_DEF(MSG_INVALID_ENUM_VALUE, 3, JSEXN_TYPEERR, "{0} '{1}' is not a valid value for enumeration {2}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, JSEXN_TYPEERR, "Not enough arguments to {0}.")
 MSG_DEF(MSG_NOT_OBJECT, 1, JSEXN_TYPEERR, "{0} is not an object.")
 MSG_DEF(MSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable.")
+MSG_DEF(MSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "{0} does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "'{0}' called on an object that does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, JSEXN_TYPEERR, "Permission to call '{0}' denied.")
 MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, JSEXN_TYPEERR, "\"this\" object does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 2, JSEXN_TYPEERR, "{0} could not be converted to any of: {1}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Illegal constructor.")
 MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.")
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -139,19 +139,16 @@ FINAL_LIBRARY = 'xul'
 SPHINX_TREES['webidl'] = 'docs'
 SPHINX_PYTHON_PACKAGE_DIRS += ['mozwebidlcodegen']
 
 if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
     # This is needed for Window.webidl
     DEFINES['HAVE_SIDEBAR'] = True
 
 
-if CONFIG['MOZ_SIMPLEPUSH']:
-    DEFINES['MOZ_SIMPLEPUSH'] = True
-
 PYTHON_UNIT_TESTS += [
     'mozwebidlcodegen/test/test_mozwebidlcodegen.py',
 ]
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
 
 if CONFIG['COMPILE_ENVIRONMENT']:
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1851,17 +1851,16 @@ class IDLDictionary(IDLObjectWithScope):
                     A list of locations that leads from the type that was passed in
                     the memberType argument, to the dictionary being validated,
                     if the boolean value in the first element is True.
 
                     None, if the boolean value in the first element is False.
             """
 
             if (memberType.nullable() or
-                memberType.isArray() or
                 memberType.isSequence() or
                 memberType.isMozMap()):
                 return typeContainsDictionary(memberType.inner, dictionary)
 
             if memberType.isDictionary():
                 if memberType.inner == dictionary:
                     return (True, [memberType.location])
 
@@ -1974,18 +1973,17 @@ class IDLType(IDLObject):
         'void',
         # Funny stuff
         'interface',
         'dictionary',
         'enum',
         'callback',
         'union',
         'sequence',
-        'mozmap',
-        'array'
+        'mozmap'
         )
 
     def __init__(self, location, name):
         IDLObject.__init__(self, location)
         self.name = name
         self.builtin = False
 
     def __eq__(self, other):
@@ -2028,19 +2026,16 @@ class IDLType(IDLObject):
         return self.name == "Void"
 
     def isSequence(self):
         return False
 
     def isMozMap(self):
         return False
 
-    def isArray(self):
-        return False
-
     def isArrayBuffer(self):
         return False
 
     def isArrayBufferView(self):
         return False
 
     def isSharedArrayBuffer(self):
         return False
@@ -2256,19 +2251,16 @@ class IDLNullableType(IDLParameterizedTy
         return False
 
     def isSequence(self):
         return self.inner.isSequence()
 
     def isMozMap(self):
         return self.inner.isMozMap()
 
-    def isArray(self):
-        return self.inner.isArray()
-
     def isArrayBuffer(self):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
 
     def isSharedArrayBuffer(self):
         return self.inner.isSharedArrayBuffer()
@@ -2361,19 +2353,16 @@ class IDLSequenceType(IDLParameterizedTy
         return False
 
     def isVoid(self):
         return False
 
     def isSequence(self):
         return True
 
-    def isArray(self):
-        return False
-
     def isDictionary(self):
         return False
 
     def isInterface(self):
         return False
 
     def isEnum(self):
         return False
@@ -2568,116 +2557,16 @@ class IDLUnionType(IDLType):
     def hasPossiblyEmptyDictionaryType(self):
         return (self._dictionaryType is not None and
                 self._dictionaryType.inner.canBeEmpty())
 
     def _getDependentObjects(self):
         return set(self.memberTypes)
 
 
-class IDLArrayType(IDLType):
-    def __init__(self, location, parameterType):
-        assert not parameterType.isVoid()
-        if parameterType.isSequence():
-            raise WebIDLError("Array type cannot parameterize over a sequence type",
-                              [location])
-        if parameterType.isMozMap():
-            raise WebIDLError("Array type cannot parameterize over a MozMap type",
-                              [location])
-        if parameterType.isDictionary():
-            raise WebIDLError("Array type cannot parameterize over a dictionary type",
-                              [location])
-
-        IDLType.__init__(self, location, parameterType.name)
-        self.inner = parameterType
-        self.builtin = False
-
-    def __eq__(self, other):
-        return isinstance(other, IDLArrayType) and self.inner == other.inner
-
-    def __str__(self):
-        return self.inner.__str__() + "Array"
-
-    def nullable(self):
-        return False
-
-    def isPrimitive(self):
-        return False
-
-    def isString(self):
-        return False
-
-    def isByteString(self):
-        return False
-
-    def isDOMString(self):
-        return False
-
-    def isUSVString(self):
-        return False
-
-    def isVoid(self):
-        return False
-
-    def isSequence(self):
-        assert not self.inner.isSequence()
-        return False
-
-    def isArray(self):
-        return True
-
-    def isDictionary(self):
-        assert not self.inner.isDictionary()
-        return False
-
-    def isInterface(self):
-        return False
-
-    def isEnum(self):
-        return False
-
-    def tag(self):
-        return IDLType.Tags.array
-
-    def resolveType(self, parentScope):
-        assert isinstance(parentScope, IDLScope)
-        self.inner.resolveType(parentScope)
-
-    def isComplete(self):
-        return self.inner.isComplete()
-
-    def complete(self, scope):
-        self.inner = self.inner.complete(scope)
-        self.name = self.inner.name
-
-        if self.inner.isDictionary():
-            raise WebIDLError("Array type must not contain "
-                              "dictionary as element type.",
-                              [self.inner.location])
-
-        assert not self.inner.isSequence()
-
-        return self
-
-    def unroll(self):
-        return self.inner.unroll()
-
-    def isDistinguishableFrom(self, other):
-        if other.isPromise():
-            return False
-        if other.isUnion():
-            # Just forward to the union; it'll deal
-            return other.isDistinguishableFrom(self)
-        return (other.isPrimitive() or other.isString() or other.isEnum() or
-                other.isDate() or other.isNonCallbackInterface())
-
-    def _getDependentObjects(self):
-        return self.inner._getDependentObjects()
-
-
 class IDLTypedefType(IDLType):
     def __init__(self, location, innerType, name):
         IDLType.__init__(self, location, name)
         self.inner = innerType
         self.builtin = False
 
     def __eq__(self, other):
         return isinstance(other, IDLTypedefType) and self.inner == other.inner
@@ -2713,19 +2602,16 @@ class IDLTypedefType(IDLType):
         return self.inner.isVoid()
 
     def isSequence(self):
         return self.inner.isSequence()
 
     def isMozMap(self):
         return self.inner.isMozMap()
 
-    def isArray(self):
-        return self.inner.isArray()
-
     def isDictionary(self):
         return self.inner.isDictionary()
 
     def isArrayBuffer(self):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
@@ -2831,19 +2717,16 @@ class IDLWrapperType(IDLType):
         return False
 
     def isVoid(self):
         return False
 
     def isSequence(self):
         return False
 
-    def isArray(self):
-        return False
-
     def isDictionary(self):
         return isinstance(self.inner, IDLDictionary)
 
     def isInterface(self):
         return (isinstance(self.inner, IDLInterface) or
                 isinstance(self.inner, IDLExternalInterface))
 
     def isCallbackInterface(self):
@@ -2900,18 +2783,17 @@ class IDLWrapperType(IDLType):
             return False
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         assert self.isInterface() or self.isEnum() or self.isDictionary()
         if self.isEnum():
             return (other.isPrimitive() or other.isInterface() or other.isObject() or
                     other.isCallback() or other.isDictionary() or
-                    other.isSequence() or other.isMozMap() or other.isArray() or
-                    other.isDate())
+                    other.isSequence() or other.isMozMap() or other.isDate())
         if self.isDictionary() and other.nullable():
             return False
         if (other.isPrimitive() or other.isString() or other.isEnum() or
             other.isDate() or other.isSequence()):
             return True
         if self.isDictionary():
             return other.isNonCallbackInterface()
 
@@ -2923,17 +2805,17 @@ class IDLWrapperType(IDLType):
             assert self.isGeckoInterface() and other.isGeckoInterface()
             if self.inner.isExternal() or other.unroll().inner.isExternal():
                 return self != other
             return (len(self.inner.interfacesBasedOnSelf &
                         other.unroll().inner.interfacesBasedOnSelf) == 0 and
                     (self.isNonCallbackInterface() or
                      other.isNonCallbackInterface()))
         if (other.isDictionary() or other.isCallback() or
-            other.isMozMap() or other.isArray()):
+            other.isMozMap()):
             return self.isNonCallbackInterface()
 
         # Not much else |other| can be
         assert other.isObject()
         return False
 
     def isExposedInAllOf(self, exposureSet):
         if not self.isInterface():
@@ -3133,49 +3015,45 @@ class IDLBuiltinType(IDLType):
             return False
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         if self.isBoolean():
             return (other.isNumeric() or other.isString() or other.isEnum() or
                     other.isInterface() or other.isObject() or
                     other.isCallback() or other.isDictionary() or
-                    other.isSequence() or other.isMozMap() or other.isArray() or
-                    other.isDate())
+                    other.isSequence() or other.isMozMap() or other.isDate())
         if self.isNumeric():
             return (other.isBoolean() or other.isString() or other.isEnum() or
                     other.isInterface() or other.isObject() or
                     other.isCallback() or other.isDictionary() or
-                    other.isSequence() or other.isMozMap() or other.isArray() or
-                    other.isDate())
+                    other.isSequence() or other.isMozMap() or other.isDate())
         if self.isString():
             return (other.isPrimitive() or other.isInterface() or
                     other.isObject() or
                     other.isCallback() or other.isDictionary() or
-                    other.isSequence() or other.isMozMap() or other.isArray() or
-                    other.isDate())
+                    other.isSequence() or other.isMozMap() or other.isDate())
         if self.isAny():
             # Can't tell "any" apart from anything
             return False
         if self.isObject():
             return other.isPrimitive() or other.isString() or other.isEnum()
         if self.isDate():
             return (other.isPrimitive() or other.isString() or other.isEnum() or
                     other.isInterface() or other.isCallback() or
                     other.isDictionary() or other.isSequence() or
-                    other.isMozMap() or other.isArray())
+                    other.isMozMap())
         if self.isVoid():
             return not other.isVoid()
         # Not much else we could be!
         assert self.isSpiderMonkeyInterface()
         # Like interfaces, but we know we're not a callback
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isCallback() or other.isDictionary() or
-                other.isSequence() or other.isMozMap() or other.isArray() or
-                other.isDate() or
+                other.isSequence() or other.isMozMap() or other.isDate() or
                 (other.isInterface() and (
                  # ArrayBuffer is distinguishable from everything
                  # that's not an ArrayBuffer or a callback interface
                  (self.isArrayBuffer() and not other.isArrayBuffer()) or
                  (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
                  # ArrayBufferView is distinguishable from everything
                  # that's not an ArrayBufferView or typed array.
                  (self.isArrayBufferView() and not other.isArrayBufferView() and
@@ -4591,22 +4469,16 @@ class IDLMethod(IDLInterfaceMember, IDLS
         'Getter',
         'Setter',
         'Creator',
         'Deleter',
         'LegacyCaller',
         base=IDLInterfaceMember.Special
     )
 
-    TypeSuffixModifier = enum(
-        'None',
-        'QMark',
-        'Brackets'
-    )
-
     NamedOrIndexed = enum(
         'Neither',
         'Named',
         'Indexed'
     )
 
     def __init__(self, location, identifier, returnType, arguments,
                  static=False, getter=False, setter=False, creator=False,
@@ -6398,128 +6270,114 @@ class Parser(Tokenizer):
     def p_TypeSingleType(self, p):
         """
             Type : SingleType
         """
         p[0] = p[1]
 
     def p_TypeUnionType(self, p):
         """
-            Type : UnionType TypeSuffix
-        """
-        p[0] = self.handleModifiers(p[1], p[2])
+            Type : UnionType Null
+        """
+        p[0] = self.handleNullable(p[1], p[2])
 
     def p_SingleTypeNonAnyType(self, p):
         """
             SingleType : NonAnyType
         """
         p[0] = p[1]
 
     def p_SingleTypeAnyType(self, p):
         """
-            SingleType : ANY TypeSuffixStartingWithArray
-        """
-        p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.any], p[2])
+            SingleType : ANY
+        """
+        p[0] = BuiltinTypes[IDLBuiltinType.Types.any]
 
     def p_UnionType(self, p):
         """
             UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN
         """
         types = [p[2], p[4]]
         types.extend(p[5])
         p[0] = IDLUnionType(self.getLocation(p, 1), types)
 
     def p_UnionMemberTypeNonAnyType(self, p):
         """
             UnionMemberType : NonAnyType
         """
         p[0] = p[1]
 
-    def p_UnionMemberTypeArrayOfAny(self, p):
-        """
-            UnionMemberTypeArrayOfAny : ANY LBRACKET RBRACKET
-        """
-        p[0] = IDLArrayType(self.getLocation(p, 2),
-                            BuiltinTypes[IDLBuiltinType.Types.any])
-
     def p_UnionMemberType(self, p):
         """
-            UnionMemberType : UnionType TypeSuffix
-                            | UnionMemberTypeArrayOfAny TypeSuffix
-        """
-        p[0] = self.handleModifiers(p[1], p[2])
+            UnionMemberType : UnionType Null
+        """
+        p[0] = self.handleNullable(p[1], p[2])
 
     def p_UnionMemberTypes(self, p):
         """
             UnionMemberTypes : OR UnionMemberType UnionMemberTypes
         """
         p[0] = [p[2]]
         p[0].extend(p[3])
 
     def p_UnionMemberTypesEmpty(self, p):
         """
             UnionMemberTypes :
         """
         p[0] = []
 
     def p_NonAnyType(self, p):
         """
-            NonAnyType : PrimitiveOrStringType TypeSuffix
-                       | ARRAYBUFFER TypeSuffix
-                       | SHAREDARRAYBUFFER TypeSuffix
-                       | OBJECT TypeSuffix
+            NonAnyType : PrimitiveOrStringType Null
+                       | ARRAYBUFFER Null
+                       | SHAREDARRAYBUFFER Null
+                       | OBJECT Null
         """
         if p[1] == "object":
             type = BuiltinTypes[IDLBuiltinType.Types.object]
         elif p[1] == "ArrayBuffer":
             type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
         elif p[1] == "SharedArrayBuffer":
             type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
         else:
             type = BuiltinTypes[p[1]]
 
-        p[0] = self.handleModifiers(type, p[2])
+        p[0] = self.handleNullable(type, p[2])
 
     def p_NonAnyTypeSequenceType(self, p):
         """
             NonAnyType : SEQUENCE LT Type GT Null
         """
         innerType = p[3]
         type = IDLSequenceType(self.getLocation(p, 1), innerType)
-        if p[5]:
-            type = IDLNullableType(self.getLocation(p, 5), type)
-        p[0] = type
+        p[0] = self.handleNullable(type, p[5])
 
     # Note: Promise<void> is allowed, so we want to parametrize on
     # ReturnType, not Type.  Also, we want this to end up picking up
     # the Promise interface for now, hence the games with IDLUnresolvedType.
     def p_NonAnyTypePromiseType(self, p):
         """
             NonAnyType : PROMISE LT ReturnType GT Null
         """
         innerType = p[3]
         promiseIdent = IDLUnresolvedIdentifier(self.getLocation(p, 1), "Promise")
         type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3])
-        if p[5]:
-            type = IDLNullableType(self.getLocation(p, 5), type)
-        p[0] = type
+        p[0] = self.handleNullable(type, p[5])
 
     def p_NonAnyTypeMozMapType(self, p):
         """
             NonAnyType : MOZMAP LT Type GT Null
         """
         innerType = p[3]
         type = IDLMozMapType(self.getLocation(p, 1), innerType)
-        if p[5]:
-            type = IDLNullableType(self.getLocation(p, 5), type)
-        p[0] = type
+        p[0] = self.handleNullable(type, p[5])
 
     def p_NonAnyTypeScopedName(self, p):
         """
-            NonAnyType : ScopedName TypeSuffix
+            NonAnyType : ScopedName Null
         """
         assert isinstance(p[1], IDLUnresolvedIdentifier)
 
         if p[1].name == "Promise":
             raise WebIDLError("Promise used without saying what it's "
                               "parametrized over",
                               [self.getLocation(p, 1)])
 
@@ -6531,50 +6389,46 @@ class Parser(Tokenizer):
                 assert not obj.isType()
                 if obj.isTypedef():
                     type = IDLTypedefType(self.getLocation(p, 1), obj.innerType,
                                           obj.identifier.name)
                 elif obj.isCallback() and not obj.isInterface():
                     type = IDLCallbackType(self.getLocation(p, 1), obj)
                 else:
                     type = IDLWrapperType(self.getLocation(p, 1), p[1])
-                p[0] = self.handleModifiers(type, p[2])
+                p[0] = self.handleNullable(type, p[2])
                 return
         except:
             pass
 
         type = IDLUnresolvedType(self.getLocation(p, 1), p[1])
-        p[0] = self.handleModifiers(type, p[2])
+        p[0] = self.handleNullable(type, p[2])
 
     def p_NonAnyTypeDate(self, p):
         """
-            NonAnyType : DATE TypeSuffix
-        """
-        p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date],
-                                    p[2])
+            NonAnyType : DATE Null
+        """
+        p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date],
+                                   p[2])
 
     def p_ConstType(self, p):
         """
             ConstType : PrimitiveOrStringType Null
         """
         type = BuiltinTypes[p[1]]
-        if p[2]:
-            type = IDLNullableType(self.getLocation(p, 1), type)
-        p[0] = type
+        p[0] = self.handleNullable(type, p[2])
 
     def p_ConstTypeIdentifier(self, p):
         """
             ConstType : IDENTIFIER Null
         """
         identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
 
         type = IDLUnresolvedType(self.getLocation(p, 1), identifier)
-        if p[2]:
-            type = IDLNullableType(self.getLocation(p, 1), type)
-        p[0] = type
+        p[0] = self.handleNullable(type, p[2])
 
     def p_PrimitiveOrStringTypeUint(self, p):
         """
             PrimitiveOrStringType : UnsignedIntegerType
         """
         p[0] = p[1]
 
     def p_PrimitiveOrStringTypeBoolean(self, p):
@@ -6672,58 +6526,25 @@ class Parser(Tokenizer):
         p[0] = True
 
     def p_OptionalLongEmpty(self, p):
         """
             OptionalLong :
         """
         p[0] = False
 
-    def p_TypeSuffixBrackets(self, p):
-        """
-            TypeSuffix : LBRACKET RBRACKET TypeSuffix
-        """
-        p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))]
-        p[0].extend(p[3])
-
-    def p_TypeSuffixQMark(self, p):
-        """
-            TypeSuffix : QUESTIONMARK TypeSuffixStartingWithArray
-        """
-        p[0] = [(IDLMethod.TypeSuffixModifier.QMark, self.getLocation(p, 1))]
-        p[0].extend(p[2])
-
-    def p_TypeSuffixEmpty(self, p):
-        """
-            TypeSuffix :
-        """
-        p[0] = []
-
-    def p_TypeSuffixStartingWithArray(self, p):
-        """
-            TypeSuffixStartingWithArray : LBRACKET RBRACKET TypeSuffix
-        """
-        p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))]
-        p[0].extend(p[3])
-
-    def p_TypeSuffixStartingWithArrayEmpty(self, p):
-        """
-            TypeSuffixStartingWithArray :
-        """
-        p[0] = []
-
     def p_Null(self, p):
         """
             Null : QUESTIONMARK
                  |
         """
         if len(p) > 1:
-            p[0] = True
+            p[0] = self.getLocation(p, 1)
         else:
-            p[0] = False
+            p[0] = None
 
     def p_ReturnTypeType(self, p):
         """
             ReturnType : Type
         """
         p[0] = p[1]
 
     def p_ReturnTypeVoid(self, p):
@@ -6871,25 +6692,19 @@ class Parser(Tokenizer):
 
         # xrange omits the last value.
         for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
             builtin = BuiltinTypes[x]
             name = builtin.name
             typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
 
     @ staticmethod
-    def handleModifiers(type, modifiers):
-        for (modifier, modifierLocation) in modifiers:
-            assert (modifier == IDLMethod.TypeSuffixModifier.QMark or
-                    modifier == IDLMethod.TypeSuffixModifier.Brackets)
-
-            if modifier == IDLMethod.TypeSuffixModifier.QMark:
-                type = IDLNullableType(modifierLocation, type)
-            elif modifier == IDLMethod.TypeSuffixModifier.Brackets:
-                type = IDLArrayType(modifierLocation, type)
+    def handleNullable(type, questionMarkLocation):
+        if questionMarkLocation is not None:
+            type = IDLNullableType(questionMarkLocation, type)
 
         return type
 
     def parse(self, t, filename=None):
         self.lexer.input(t)
 
         # for tok in iter(self.lexer.token, None):
         #    print tok
deleted file mode 100644
--- a/dom/bindings/parser/tests/test_array.py
+++ /dev/null
@@ -1,18 +0,0 @@
-def WebIDLTest(parser, harness):
-    threw = False
-    try:
-        parser.parse("""
-          dictionary Foo {
-            short a;
-          };
-
-          dictionary Foo1 {
-            Foo[] b;
-          };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(threw, "Array must not contain dictionary "
-                      "as element type.")
deleted file mode 100644
--- a/dom/bindings/parser/tests/test_array_of_interface.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import WebIDL
-
-def WebIDLTest(parser, harness):
-    parser.parse("""
-      interface A {
-        attribute long a;
-      };
-
-      interface B {
-        attribute A[] b;
-      };
-    """);
-    parser.finish()
--- a/dom/bindings/parser/tests/test_arraybuffer.py
+++ b/dom/bindings/parser/tests/test_arraybuffer.py
@@ -1,45 +1,45 @@
 import WebIDL
 
 def WebIDLTest(parser, harness):
     parser.parse("""
         interface TestArrayBuffer {
           attribute ArrayBuffer bufferAttr;
-          void bufferMethod(ArrayBuffer arg1, ArrayBuffer? arg2, ArrayBuffer[] arg3, sequence<ArrayBuffer> arg4);
+          void bufferMethod(ArrayBuffer arg1, ArrayBuffer? arg2, sequence<ArrayBuffer> arg3);
 
           attribute ArrayBufferView viewAttr;
-          void viewMethod(ArrayBufferView arg1, ArrayBufferView? arg2, ArrayBufferView[] arg3, sequence<ArrayBufferView> arg4);
+          void viewMethod(ArrayBufferView arg1, ArrayBufferView? arg2, sequence<ArrayBufferView> arg3);
 
           attribute Int8Array int8ArrayAttr;
-          void int8ArrayMethod(Int8Array arg1, Int8Array? arg2, Int8Array[] arg3, sequence<Int8Array> arg4);
+          void int8ArrayMethod(Int8Array arg1, Int8Array? arg2, sequence<Int8Array> arg3);
 
           attribute Uint8Array uint8ArrayAttr;
-          void uint8ArrayMethod(Uint8Array arg1, Uint8Array? arg2, Uint8Array[] arg3, sequence<Uint8Array> arg4);
+          void uint8ArrayMethod(Uint8Array arg1, Uint8Array? arg2, sequence<Uint8Array> arg3);
 
           attribute Uint8ClampedArray uint8ClampedArrayAttr;
-          void uint8ClampedArrayMethod(Uint8ClampedArray arg1, Uint8ClampedArray? arg2, Uint8ClampedArray[] arg3, sequence<Uint8ClampedArray> arg4);
+          void uint8ClampedArrayMethod(Uint8ClampedArray arg1, Uint8ClampedArray? arg2, sequence<Uint8ClampedArray> arg3);
 
           attribute Int16Array int16ArrayAttr;
-          void int16ArrayMethod(Int16Array arg1, Int16Array? arg2, Int16Array[] arg3, sequence<Int16Array> arg4);
+          void int16ArrayMethod(Int16Array arg1, Int16Array? arg2, sequence<Int16Array> arg3);
 
           attribute Uint16Array uint16ArrayAttr;
-          void uint16ArrayMethod(Uint16Array arg1, Uint16Array? arg2, Uint16Array[] arg3, sequence<Uint16Array> arg4);
+          void uint16ArrayMethod(Uint16Array arg1, Uint16Array? arg2, sequence<Uint16Array> arg3);
 
           attribute Int32Array int32ArrayAttr;
-          void int32ArrayMethod(Int32Array arg1, Int32Array? arg2, Int32Array[] arg3, sequence<Int32Array> arg4);
+          void int32ArrayMethod(Int32Array arg1, Int32Array? arg2, sequence<Int32Array> arg3);
 
           attribute Uint32Array uint32ArrayAttr;
-          void uint32ArrayMethod(Uint32Array arg1, Uint32Array? arg2, Uint32Array[] arg3, sequence<Uint32Array> arg4);
+          void uint32ArrayMethod(Uint32Array arg1, Uint32Array? arg2, sequence<Uint32Array> arg3);
 
           attribute Float32Array float32ArrayAttr;
-          void float32ArrayMethod(Float32Array arg1, Float32Array? arg2, Float32Array[] arg3, sequence<Float32Array> arg4);
+          void float32ArrayMethod(Float32Array arg1, Float32Array? arg2, sequence<Float32Array> arg3);
 
           attribute Float64Array float64ArrayAttr;
-          void float64ArrayMethod(Float64Array arg1, Float64Array? arg2, Float64Array[] arg3, sequence<Float64Array> arg4);
+          void float64ArrayMethod(Float64Array arg1, Float64Array? arg2, sequence<Float64Array> arg3);
         };
     """)
 
     results = parser.finish()
 
     iface = results[0]
 
     harness.ok(True, "TestArrayBuffer interface parsed without error")
@@ -51,30 +51,27 @@ def WebIDLTest(parser, harness):
         harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Expect an IDLAttribute")
         harness.ok(isinstance(method, WebIDL.IDLMethod), "Expect an IDLMethod")
 
         harness.check(str(attr.type), t, "Expect an ArrayBuffer type")
         harness.ok(attr.type.isSpiderMonkeyInterface(), "Should test as a js interface")
 
         (retType, arguments) = method.signatures()[0]
         harness.ok(retType.isVoid(), "Should have a void return type")
-        harness.check(len(arguments), 4, "Expect 4 arguments")
+        harness.check(len(arguments), 3, "Expect 3 arguments")
 
         harness.check(str(arguments[0].type), t,  "Expect an ArrayBuffer type")
         harness.ok(arguments[0].type.isSpiderMonkeyInterface(), "Should test as a js interface")
 
         harness.check(str(arguments[1].type), t + "OrNull",  "Expect an ArrayBuffer type")
         harness.ok(arguments[1].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface")
 
-        harness.check(str(arguments[2].type), t + "Array",  "Expect an ArrayBuffer type")
+        harness.check(str(arguments[2].type), t + "Sequence",  "Expect an ArrayBuffer type")
         harness.ok(arguments[2].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface")
 
-        harness.check(str(arguments[3].type), t + "Sequence",  "Expect an ArrayBuffer type")
-        harness.ok(arguments[3].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface")
-
 
     checkStuff(members[0],  members[1],  "ArrayBuffer")
     checkStuff(members[2],  members[3],  "ArrayBufferView")
     checkStuff(members[4],  members[5],  "Int8Array")
     checkStuff(members[6],  members[7],  "Uint8Array")
     checkStuff(members[8],  members[9],  "Uint8ClampedArray")
     checkStuff(members[10], members[11], "Int16Array")
     checkStuff(members[12], members[13], "Uint16Array")
--- a/dom/bindings/parser/tests/test_attr.py
+++ b/dom/bindings/parser/tests/test_attr.py
@@ -72,137 +72,33 @@ def WebIDLTest(parser, harness):
           attribute DOMString? str;
           readonly attribute DOMString? rstr;
           attribute object? obj;
           readonly attribute object? robj;
           attribute object? _object;
           attribute float? f;
           readonly attribute float? rf;
         };
-
-        interface TestAttrArray {
-          attribute byte[] b;
-          readonly attribute byte[] rb;
-          attribute octet[] o;
-          readonly attribute octet[] ro;
-          attribute short[] s;
-          readonly attribute short[] rs;
-          attribute unsigned short[] us;
-          readonly attribute unsigned short[] rus;
-          attribute long[] l;
-          readonly attribute long[] rl;
-          attribute unsigned long[] ul;
-          readonly attribute unsigned long[] rul;
-          attribute long long[] ll;
-          readonly attribute long long[] rll;
-          attribute unsigned long long[] ull;
-          readonly attribute unsigned long long[] rull;
-          attribute DOMString[] str;
-          readonly attribute DOMString[] rstr;
-          attribute object[] obj;
-          readonly attribute object[] robj;
-          attribute object[] _object;
-          attribute float[] f;
-          readonly attribute float[] rf;
-        };
-
-        interface TestAttrNullableArray {
-          attribute byte[]? b;
-          readonly attribute byte[]? rb;
-          attribute octet[]? o;
-          readonly attribute octet[]? ro;
-          attribute short[]? s;
-          readonly attribute short[]? rs;
-          attribute unsigned short[]? us;
-          readonly attribute unsigned short[]? rus;
-          attribute long[]? l;
-          readonly attribute long[]? rl;
-          attribute unsigned long[]? ul;
-          readonly attribute unsigned long[]? rul;
-          attribute long long[]? ll;
-          readonly attribute long long[]? rll;
-          attribute unsigned long long[]? ull;
-          readonly attribute unsigned long long[]? rull;
-          attribute DOMString[]? str;
-          readonly attribute DOMString[]? rstr;
-          attribute object[]? obj;
-          readonly attribute object[]? robj;
-          attribute object[]? _object;
-          attribute float[]? f;
-          readonly attribute float[]? rf;
-        };
-
-        interface TestAttrArrayOfNullableTypes {
-          attribute byte?[] b;
-          readonly attribute byte?[] rb;
-          attribute octet?[] o;
-          readonly attribute octet?[] ro;
-          attribute short?[] s;
-          readonly attribute short?[] rs;
-          attribute unsigned short?[] us;
-          readonly attribute unsigned short?[] rus;
-          attribute long?[] l;
-          readonly attribute long?[] rl;
-          attribute unsigned long?[] ul;
-          readonly attribute unsigned long?[] rul;
-          attribute long long?[] ll;
-          readonly attribute long long?[] rll;
-          attribute unsigned long long?[] ull;
-          readonly attribute unsigned long long?[] rull;
-          attribute DOMString?[] str;
-          readonly attribute DOMString?[] rstr;
-          attribute object?[] obj;
-          readonly attribute object?[] robj;
-          attribute object?[] _object;
-          attribute float?[] f;
-          readonly attribute float?[] rf;
-        };
-
-        interface TestAttrNullableArrayOfNullableTypes {
-          attribute byte?[]? b;
-          readonly attribute byte?[]? rb;
-          attribute octet?[]? o;
-          readonly attribute octet?[]? ro;
-          attribute short?[]? s;
-          readonly attribute short?[]? rs;
-          attribute unsigned short?[]? us;
-          readonly attribute unsigned short?[]? rus;
-          attribute long?[]? l;
-          readonly attribute long?[]? rl;
-          attribute unsigned long?[]? ul;
-          readonly attribute unsigned long?[]? rul;
-          attribute long long?[]? ll;
-          readonly attribute long long?[]? rll;
-          attribute unsigned long long?[]? ull;
-          readonly attribute unsigned long long?[]? rull;
-          attribute DOMString?[]? str;
-          readonly attribute DOMString?[]? rstr;
-          attribute object?[]? obj;
-          readonly attribute object?[]? robj;
-          attribute object?[]? _object;
-          attribute float?[]? f;
-          readonly attribute float?[]? rf;
-        };
     """)
 
     results = parser.finish()
 
     def checkAttr(attr, QName, name, type, readonly):
         harness.ok(isinstance(attr, WebIDL.IDLAttribute),
                   "Should be an IDLAttribute")
         harness.ok(attr.isAttr(), "Attr is an Attr")
         harness.ok(not attr.isMethod(), "Attr is not an method")
         harness.ok(not attr.isConst(), "Attr is not a const")
         harness.check(attr.identifier.QName(), QName, "Attr has the right QName")
         harness.check(attr.identifier.name, name, "Attr has the right name")
         harness.check(str(attr.type), type, "Attr has the right type")
         harness.check(attr.readonly, readonly, "Attr's readonly state is correct")
 
     harness.ok(True, "TestAttr interface parsed without error.")
-    harness.check(len(results), 6, "Should be six productions.")
+    harness.check(len(results), 2, "Should be two productions.")
     iface = results[0]
     harness.ok(isinstance(iface, WebIDL.IDLInterface),
                "Should be an IDLInterface")
     harness.check(iface.identifier.QName(), "::TestAttr", "Interface has the right QName")
     harness.check(iface.identifier.name, "TestAttr", "Interface has the right name")
     harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData))
 
     attrs = iface.members
@@ -223,76 +119,16 @@ def WebIDLTest(parser, harness):
     attrs = iface.members
 
     for i in range(len(attrs)):
         data = testData[i]
         attr = attrs[i]
         (QName, name, type, readonly) = data
         checkAttr(attr, QName % "Nullable", name, type % "OrNull", readonly)
 
-    iface = results[2]
-    harness.ok(isinstance(iface, WebIDL.IDLInterface),
-               "Should be an IDLInterface")
-    harness.check(iface.identifier.QName(), "::TestAttrArray", "Interface has the right QName")
-    harness.check(iface.identifier.name, "TestAttrArray", "Interface has the right name")
-    harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData))
-
-    attrs = iface.members
-
-    for i in range(len(attrs)):
-        data = testData[i]
-        attr = attrs[i]
-        (QName, name, type, readonly) = data
-        checkAttr(attr, QName % "Array", name, type % "Array", readonly)
-
-    iface = results[3]
-    harness.ok(isinstance(iface, WebIDL.IDLInterface),
-               "Should be an IDLInterface")
-    harness.check(iface.identifier.QName(), "::TestAttrNullableArray", "Interface has the right QName")
-    harness.check(iface.identifier.name, "TestAttrNullableArray", "Interface has the right name")
-    harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData))
-
-    attrs = iface.members
-
-    for i in range(len(attrs)):
-        data = testData[i]
-        attr = attrs[i]
-        (QName, name, type, readonly) = data
-        checkAttr(attr, QName % "NullableArray", name, type % "ArrayOrNull", readonly)
-
-    iface = results[4]
-    harness.ok(isinstance(iface, WebIDL.IDLInterface),
-               "Should be an IDLInterface")
-    harness.check(iface.identifier.QName(), "::TestAttrArrayOfNullableTypes", "Interface has the right QName")
-    harness.check(iface.identifier.name, "TestAttrArrayOfNullableTypes", "Interface has the right name")
-    harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData))
-
-    attrs = iface.members
-
-    for i in range(len(attrs)):
-        data = testData[i]
-        attr = attrs[i]
-        (QName, name, type, readonly) = data
-        checkAttr(attr, QName % "ArrayOfNullableTypes", name, type % "OrNullArray", readonly)
-
-    iface = results[5]
-    harness.ok(isinstance(iface, WebIDL.IDLInterface),
-               "Should be an IDLInterface")
-    harness.check(iface.identifier.QName(), "::TestAttrNullableArrayOfNullableTypes", "Interface has the right QName")
-    harness.check(iface.identifier.name, "TestAttrNullableArrayOfNullableTypes", "Interface has the right name")
-    harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData))
-
-    attrs = iface.members
-
-    for i in range(len(attrs)):
-        data = testData[i]
-        attr = attrs[i]
-        (QName, name, type, readonly) = data
-        checkAttr(attr, QName % "NullableArrayOfNullableTypes", name, type % "OrNullArrayOrNull", readonly)
-
     parser = parser.reset()
     threw = False
     try:
         parser.parse("""
           interface A {
             [SetterThrows] readonly attribute boolean foo;
           };
         """)
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -154,17 +154,17 @@ def WebIDLTest(parser, harness):
                  "boolean?", "DOMString", "ByteString", "Enum", "Enum2",
                  "Interface", "Interface?",
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
-                 "long[]", "short[]", "Date", "Date?", "any",
+                 "Date", "Date?", "any",
                  "Promise<any>", "Promise<any>?",
                  "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
                  "Uint8Array", "Uint16Array" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2 and
@@ -182,17 +182,16 @@ def WebIDLTest(parser, harness):
     sharedBufferSourceTypes = ["SharedArrayBuffer"]
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
                    "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
     nullables = ["long?", "short?", "boolean?", "Interface?",
                  "CallbackInterface?", "optional Dict", "optional Dict2",
                  "Date?", "any", "Promise<any>?"]
     dates = [ "Date", "Date?" ]
     sequences = [ "sequence<long>", "sequence<short>" ]
-    arrays = [ "long[]", "short[]" ]
     nonUserObjects = nonObjects + interfaces + dates + sequences
     otherObjects = allBut(argTypes, nonUserObjects + ["object"])
     notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
                             otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
     mozMaps = [ "MozMap<object>", "MozMap<Dict>", "MozMap<long>" ]
 
     # Build a representation of the distinguishability table as a dict
     # of dicts, holding True values where needed, holes elsewhere.
@@ -224,24 +223,22 @@ def WebIDLTest(parser, harness):
     setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables))
     setDistinguishable("CallbackInterface2", nonUserObjects)
     setDistinguishable("object", nonObjects)
     setDistinguishable("Callback", nonUserObjects)
     setDistinguishable("Callback2", nonUserObjects)
     setDistinguishable("optional Dict", allBut(nonUserObjects, nullables))
     setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables))
     setDistinguishable("sequence<long>",
-                       allBut(argTypes, sequences + arrays + ["object"]))
+                       allBut(argTypes, sequences + ["object"]))
     setDistinguishable("sequence<short>",
-                       allBut(argTypes, sequences + arrays + ["object"]))
+                       allBut(argTypes, sequences + ["object"]))
     setDistinguishable("MozMap<object>", nonUserObjects)
     setDistinguishable("MozMap<Dict>", nonUserObjects)
     setDistinguishable("MozMap<long>", nonUserObjects)
-    setDistinguishable("long[]", allBut(nonUserObjects, sequences))
-    setDistinguishable("short[]", allBut(nonUserObjects, sequences))
     setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
     setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
     setDistinguishable("any", [])
     setDistinguishable("Promise<any>", [])
     setDistinguishable("Promise<any>?", [])
     setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"]))
     setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"]))
     setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
--- a/dom/bindings/parser/tests/test_method.py
+++ b/dom/bindings/parser/tests/test_method.py
@@ -6,34 +6,33 @@ def WebIDLTest(parser, harness):
           void basic();
           static void basicStatic();
           void basicWithSimpleArgs(boolean arg1, byte arg2, unsigned long arg3);
           boolean basicBoolean();
           static boolean basicStaticBoolean();
           boolean basicBooleanWithSimpleArgs(boolean arg1, byte arg2, unsigned long arg3);
           void optionalArg(optional byte? arg1, optional sequence<byte> arg2);
           void variadicArg(byte?... arg1);
-          void crazyTypes(sequence<long?[]>? arg1, boolean?[][]? arg2);
           object getObject();
           void setObject(object arg1);
           void setAny(any arg1);
           float doFloats(float arg1);
         };
     """)
 
     results = parser.finish()
 
     harness.ok(True, "TestMethods interface parsed without error.")
     harness.check(len(results), 1, "Should be one production.")
     iface = results[0]
     harness.ok(isinstance(iface, WebIDL.IDLInterface),
                "Should be an IDLInterface")
     harness.check(iface.identifier.QName(), "::TestMethods", "Interface has the right QName")
     harness.check(iface.identifier.name, "TestMethods", "Interface has the right name")
-    harness.check(len(iface.members), 13, "Expect 13 members")
+    harness.check(len(iface.members), 12, "Expect 12 members")
 
     methods = iface.members
 
     def checkArgument(argument, QName, name, type, optional, variadic):
         harness.ok(isinstance(argument, WebIDL.IDLArgument),
                    "Should be an IDLArgument")
         harness.check(argument.identifier.QName(), QName, "Argument has the right QName")
         harness.check(argument.identifier.name, name, "Argument has the right name")
@@ -93,32 +92,27 @@ def WebIDLTest(parser, harness):
                 "optionalArg",
        [("Void",
         [("::TestMethods::optionalArg::arg1", "arg1", "ByteOrNull", True, False),
          ("::TestMethods::optionalArg::arg2", "arg2", "ByteSequence", True, False)])])
     checkMethod(methods[7], "::TestMethods::variadicArg",
                 "variadicArg",
        [("Void",
         [("::TestMethods::variadicArg::arg1", "arg1", "ByteOrNull", True, True)])])
-    checkMethod(methods[8], "::TestMethods::crazyTypes",
-                "crazyTypes",
-       [("Void",
-        [("::TestMethods::crazyTypes::arg1", "arg1", "LongOrNullArraySequenceOrNull", False, False),
-         ("::TestMethods::crazyTypes::arg2", "arg2", "BooleanOrNullArrayArrayOrNull", False, False)])])
-    checkMethod(methods[9], "::TestMethods::getObject",
+    checkMethod(methods[8], "::TestMethods::getObject",
                 "getObject", [("Object", [])])
-    checkMethod(methods[10], "::TestMethods::setObject",
+    checkMethod(methods[9], "::TestMethods::setObject",
                 "setObject",
        [("Void",
         [("::TestMethods::setObject::arg1", "arg1", "Object", False, False)])])
-    checkMethod(methods[11], "::TestMethods::setAny",
+    checkMethod(methods[10], "::TestMethods::setAny",
                 "setAny",
        [("Void",
         [("::TestMethods::setAny::arg1", "arg1", "Any", False, False)])])
-    checkMethod(methods[12], "::TestMethods::doFloats",
+    checkMethod(methods[11], "::TestMethods::doFloats",
                 "doFloats",
        [("Float",
         [("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])])
 
     parser = parser.reset()
     threw = False
     try:
         parser.parse("""
--- a/dom/bindings/parser/tests/test_nullable_equivalency.py
+++ b/dom/bindings/parser/tests/test_nullable_equivalency.py
@@ -48,26 +48,16 @@ def WebIDLTest(parser, harness):
           attribute double  a;
           attribute double? b;
         };
 
         interface TestNullableEquivalency10 {
           attribute object  a;
           attribute object? b;
         };
-
-        interface TestNullableEquivalency11 {
-          attribute double[]  a;
-          attribute double[]? b;
-        };
-
-        interface TestNullableEquivalency12 {
-          attribute TestNullableEquivalency9[]  a;
-          attribute TestNullableEquivalency9[]? b;
-        };
     """)
 
     for decl in parser.finish():
         if decl.isInterface():
             checkEquivalent(decl, harness)
 
 def checkEquivalent(iface, harness):
     type1 = iface.members[0].type
--- a/dom/bindings/parser/tests/test_union.py
+++ b/dom/bindings/parser/tests/test_union.py
@@ -134,19 +134,16 @@ def WebIDLTest(parser, harness):
     interface = testPre + """
         interface TestUnion {
         """
     for (i, type) in enumerate(validUnionTypes):
         interface += string.Template("""
           void method${i}(${type} arg);
           ${type} returnMethod${i}();
           attribute ${type} attr${i};
-          void arrayMethod${i}(${type}[] arg);
-          ${type}[] arrayReturnMethod${i}();
-          attribute ${type}[] arrayAttr${i};
           void optionalMethod${i}(${type}? arg);
         """).substitute(i=i, type=type)
     interface += """
         };
         """
     parser.parse(interface)
     results = parser.finish()
 
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -23,19 +23,19 @@ BluetoothChild* sBluetoothChild;
 
 inline
 void
 SendRequest(BluetoothReplyRunnable* aRunnable, const Request& aRequest)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  NS_WARN_IF_FALSE(sBluetoothChild,
-                   "Calling methods on BluetoothServiceChildProcess during "
-                   "shutdown!");
+  NS_WARNING_ASSERTION(
+    sBluetoothChild,
+    "Calling methods on BluetoothServiceChildProcess during shutdown!");
 
   if (sBluetoothChild) {
     BluetoothRequestChild* actor = new BluetoothRequestChild(aRunnable);
     sBluetoothChild->SendPBluetoothRequestConstructor(actor, aRequest);
   }
 }
 
 } // namespace
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1733,17 +1733,17 @@ CanvasRenderingContext2D::TrySkiaGLTarge
 
   if (!layerManager) {
     return false;
   }
 
   DemoteOldestContextIfNecessary();
   mBufferProvider = nullptr;
 
-#if USE_SKIA_GPU
+#ifdef USE_SKIA_GPU
   SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
   if (!glue || !glue->GetGrContext() || !glue->GetGLContext()) {
     return false;
   }
 
   SurfaceFormat format = GetSurfaceFormat();
   aOutDT = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(),
                                                       size, format);
new file mode 100644
--- /dev/null
+++ b/dom/canvas/crashtests/1299062-1.html
@@ -0,0 +1,5 @@
+<canvas id='id0' width='35376.4661501'></canvas>
+<script>
+var ctx=document.getElementById('id0').getContext('2d');
+ctx.getImageData(66,-1,32,87);
+</script>
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -31,9 +31,10 @@ load 1246775-1.html
 load 1284356-1.html
 load 1284578-1.html
 skip-if(d2d) load 1287515-1.html
 load 1287652-1.html
 load 1288872-1.html
 load 1290628-1.html
 load 1283113-1.html
 load 1286458-1.html
+load 1299062-1.html
 
--- a/dom/cellbroadcast/CellBroadcast.cpp
+++ b/dom/cellbroadcast/CellBroadcast.cpp
@@ -77,18 +77,18 @@ CellBroadcast::Create(nsPIDOMWindowInner
 }
 
 CellBroadcast::CellBroadcast(nsPIDOMWindowInner* aWindow,
                              nsICellBroadcastService* aService)
   : DOMEventTargetHelper(aWindow)
 {
   mListener = new Listener(this);
   DebugOnly<nsresult> rv = aService->RegisterListener(mListener);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                   "Failed registering Cell Broadcast callback");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Failed registering Cell Broadcast callback");
 }
 
 CellBroadcast::~CellBroadcast()
 {
   MOZ_ASSERT(mListener);
 
   mListener->Disconnect();
   nsCOMPtr<nsICellBroadcastService> service =
--- a/dom/crypto/WebCryptoThreadPool.cpp
+++ b/dom/crypto/WebCryptoThreadPool.cpp
@@ -23,17 +23,17 @@ NS_IMPL_ISUPPORTS(WebCryptoThreadPool, n
 
 /* static */ void
 WebCryptoThreadPool::Initialize()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(!gInstance, "More than one instance!");
 
   gInstance = new WebCryptoThreadPool();
-  NS_WARN_IF_FALSE(gInstance, "Failed create thread pool!");
+  NS_WARNING_ASSERTION(gInstance, "Failed create thread pool!");
 
   if (gInstance && NS_FAILED(gInstance->Init())) {
     NS_WARNING("Failed to initialize thread pool!");
     gInstance = nullptr;
   }
 }
 
 /* static */ nsresult
@@ -85,17 +85,17 @@ WebCryptoThreadPool::Shutdown()
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MutexAutoLock lock(mMutex);
 
   if (mPool) {
     mPool->Shutdown();
   }
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  NS_WARN_IF_FALSE(obs, "Failed to retrieve observer service!");
+  NS_WARNING_ASSERTION(obs, "Failed to retrieve observer service!");
 
   if (obs) {
     if (NS_FAILED(obs->RemoveObserver(this,
                                       NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID))) {
       NS_WARNING("Failed to remove shutdown observer!");
     }
   }
 }
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -162,17 +162,17 @@ public:
   {
     uint32_t lastIndex = aChain.Length() - 1;
     MOZ_ASSERT(&aChain[lastIndex] == aItem);
     aChain.RemoveElementAt(lastIndex);
   }
 
   bool IsValid()
   {
-    NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!");
+    NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
     return !!(mTarget);
   }
 
   EventTarget* GetNewTarget()
   {
     return mNewTarget;
   }
 
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -382,32 +382,34 @@ EventListenerManager::AddEventListenerIn
              aEventMessage <= ePointerEventLast) {
     nsPIDOMWindowInner* window = GetInnerWindowForTarget();
     if (aTypeAtom == nsGkAtoms::onpointerenter ||
         aTypeAtom == nsGkAtoms::onpointerleave) {
       mMayHavePointerEnterLeaveEventListener = true;
       if (window) {
 #ifdef DEBUG
         nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
-        NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
-                         "Please do not use pointerenter/leave events in chrome. "
-                         "They are slower than pointerover/out!");
+        NS_WARNING_ASSERTION(
+          !nsContentUtils::IsChromeDoc(d),
+          "Please do not use pointerenter/leave events in chrome. "
+          "They are slower than pointerover/out!");
 #endif
         window->SetHasPointerEnterLeaveEventListeners();
       }
     }
   } else if (aTypeAtom == nsGkAtoms::onmouseenter ||
              aTypeAtom == nsGkAtoms::onmouseleave) {
     mMayHaveMouseEnterLeaveEventListener = true;
     if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
 #ifdef DEBUG
       nsCOMPtr<nsIDocument> d = window->GetExtantDoc();
-      NS_WARN_IF_FALSE(!nsContentUtils::IsChromeDoc(d),
-                       "Please do not use mouseenter/leave events in chrome. "
-                       "They are slower than mouseover/out!");
+      NS_WARNING_ASSERTION(
+        !nsContentUtils::IsChromeDoc(d),
+        "Please do not use mouseenter/leave events in chrome. "
+        "They are slower than mouseover/out!");
 #endif
       window->SetHasMouseEnterLeaveEventListeners();
     }
 #ifdef MOZ_GAMEPAD
   } else if (aEventMessage >= eGamepadEventFirst &&
              aEventMessage <= eGamepadEventLast) {
     if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
       window->SetHasGamepadEventListener();
@@ -648,24 +650,25 @@ EventListenerManager::RemoveEventListene
   }
 
   Listener* listener;
 
   uint32_t count = mListeners.Length();
   uint32_t typeCount = 0;
   bool deviceType = IsDeviceType(aEventMessage);
 
+  RefPtr<EventListenerManager> kungFuDeathGrip(this);
+
   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;
         NotifyEventListenerRemoved(aUserType);
         if (!deviceType) {
           return;
         }
         --typeCount;
       }
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -518,22 +518,22 @@ EventStateManager::PreHandleEvent(nsPres
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   NS_ENSURE_ARG(aPresContext);
   if (!aEvent) {
     NS_ERROR("aEvent is null.  This should never happen.");
     return NS_ERROR_NULL_POINTER;
   }
 
-  NS_WARN_IF_FALSE(!aTargetFrame ||
-                   !aTargetFrame->GetContent() ||
-                   aTargetFrame->GetContent() == aTargetContent ||
-                   aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent ||
-                   aTargetFrame->IsGeneratedContentFrame(),
-                   "aTargetFrame should be related with aTargetContent");
+  NS_WARNING_ASSERTION(
+    !aTargetFrame || !aTargetFrame->GetContent() ||
+    aTargetFrame->GetContent() == aTargetContent ||
+    aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent ||
+    aTargetFrame->IsGeneratedContentFrame(),
+    "aTargetFrame should be related with aTargetContent");
 #if DEBUG
   if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
     nsCOMPtr<nsIContent> targetContent;
     aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
     MOZ_ASSERT(aTargetContent == targetContent,
                "Unexpected target for generated content frame!");
   }
 #endif
@@ -3017,17 +3017,17 @@ EventStateManager::PostHandleEvent(nsPre
         }
 
         // When the mouse is pressed, the default action is to focus the
         // target. Look for the nearest enclosing focusable frame.
         while (currFrame) {
           // If the mousedown happened inside a popup, don't
           // try to set focus on one of its containing elements
           const nsStyleDisplay* display = currFrame->StyleDisplay();
-          if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) {
+          if (display->mDisplay == StyleDisplay::Popup) {
             newFocus = nullptr;
             break;
           }
 
           int32_t tabIndexUnused;
           if (currFrame->IsFocusable(&tabIndexUnused, true)) {
             newFocus = currFrame->GetContent();
             nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -326,17 +326,18 @@ WheelTransaction::SetTimeout()
       return;
     }
     timer.swap(sTimer);
   }
   sTimer->Cancel();
   DebugOnly<nsresult> rv =
     sTimer->InitWithFuncCallback(OnTimeout, nullptr, GetTimeoutTime(),
                                  nsITimer::TYPE_ONE_SHOT);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "nsITimer::InitWithFuncCallback failed");
 }
 
 /* static */ nsIntPoint
 WheelTransaction::GetScreenPoint(WidgetGUIEvent* aEvent)
 {
   NS_ASSERTION(aEvent, "aEvent is null");
   NS_ASSERTION(aEvent->mWidget, "aEvent-mWidget is null");
   return (aEvent->mRefPoint + aEvent->mWidget->WidgetToScreenOffset())
--- a/dom/events/test/pointerevents/pointerevent_element_haspointercapture-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_element_haspointercapture-manual.html
@@ -30,31 +30,35 @@
                     detected_pointertypes[e.pointerType] = true;
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), false,
                                       "before target0.setPointerCapture, target0.hasPointerCapture should be false");
                     });
                     target1.setPointerCapture(e.pointerId);
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), false,
-                                      "target1.setPointerCapture, target0.hasPointerCapture should be false");
+                                      "after target1.setPointerCapture, target0.hasPointerCapture should be false");
+                        assert_equals(target1.hasPointerCapture(e.pointerId), true,
+                                      "after target1.setPointerCapture, target1.hasPointerCapture should be true");
                     });
                     target0.setPointerCapture(e.pointerId);
                     set_capture_to_target0 = true;
                     // hasPointerCapture will return true immediately after a call to setPointerCapture
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), true,
                                       "after target0.setPointerCapture, target0.hasPointerCapture should be true");
                     });
                     // hasPointerCapture will return false immediately after a call to releasePointerCapture
                     target0.releasePointerCapture(e.pointerId);
                     set_capture_to_target0 = false;
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), false,
                                       "after target0.releasePointerCapture, target0.hasPointerCapture should be false");
+                        assert_equals(target1.hasPointerCapture(e.pointerId), false,
+                                      "after target0.releasePointerCapture, target1.hasPointerCapture should be false");
                     });
                     target0.setPointerCapture(e.pointerId);
                     set_capture_to_target0 = true;
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), true,
                                       "after target0.setPointerCapture, target0.hasPointerCapture should be true");
                     });
                 });
@@ -78,34 +82,42 @@
                     set_capture_to_target0 = false;
                 });
 
                 on_event(target0, "lostpointercapture", function (e) {
                     test_pointerEvent.step(function () {
                         assert_equals(target0.hasPointerCapture(e.pointerId), false,
                                       "pointerup target0.hasPointerCapture should be false");
                     });
+                });
+
+                on_event(target1, "pointerup", function (e) {
+                    test_pointerEvent.step(function () {
+                        assert_equals(target1.hasPointerCapture(e.pointerId), false,
+                                      "pointerup target1.hasPointerCapture should be false");
+                    });
                     test_pointerEvent.done();
                 });
             }
         </script>
     </head>
     <body onload="run()">
         <h1>Element.hasPointerCapture test</h1>
         <!--
         <h4>
             Test Description: This test checks if Element.hasPointerCapture returns value correctly
             <ol>
                 <li> Press black rectangle and do not release
-                <li> Move your pointer to yellow rectangle
+                <li> Move your pointer to purple rectangle
                 <li> Release the pointer
+                <li> Click purple rectangle
             </ol>
         </h4>
         <p>
         -->
-        <div id="target0" style="background:black"></div>
-        <div id="target1" style="background:yellow"></div>
+        <div id="target0" touch-action:none></div>
+        <div id="target1" touch-action:none></div>
         <div id="complete-notice">
             <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
         </div>
         <div id="log"></div>
     </body>
 </html>
\ No newline at end of file
--- a/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture-manual.html
@@ -18,15 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         iframe.src = "pointerevent_element_haspointercapture-manual.html";
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
         sendMouseEvent(int_win, "target0", "mousedown", {button:0});
         sendMouseEvent(int_win, "target0", "mousemove", {button:0});
         sendMouseEvent(int_win, "target1", "mousemove", {button:0});
         sendMouseEvent(int_win, "target1", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target1", "mouseup", {button:0});
       }
     </script>
   </head>
   <body>
     <iframe id="testFrame" height="800" width="1000"></iframe>
   </body>
 </html>
--- a/dom/html/HTMLMenuElement.cpp
+++ b/dom/html/HTMLMenuElement.cpp
@@ -108,17 +108,17 @@ HTMLMenuElement::CreateBuilder(nsIMenuBu
 already_AddRefed<nsIMenuBuilder>
 HTMLMenuElement::CreateBuilder()
 {
   if (mType != MENU_TYPE_CONTEXT) {
     return nullptr;
   }
 
   nsCOMPtr<nsIMenuBuilder> builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
-  NS_WARN_IF_FALSE(builder, "No builder available");
+  NS_WARNING_ASSERTION(builder, "No builder available");
   return builder.forget();
 }
 
 NS_IMETHODIMP
 HTMLMenuElement::Build(nsIMenuBuilder* aBuilder)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
 
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -976,17 +976,17 @@ nsGenericHTMLElement::ParseBackgroundAtt
 
     nsString value(aValue);
     RefPtr<nsStringBuffer> buffer = nsCSSValue::BufferFromString(value);
     if (MOZ_UNLIKELY(!buffer)) {
       return false;
     }
 
     mozilla::css::URLValue *url =
-      new mozilla::css::URLValue(uri, buffer, doc->GetDocumentURI(),
+      new mozilla::css::URLValue(uri, buffer, baseURI, doc->GetDocumentURI(),
                                  NodePrincipal());
     aResult.SetTo(url, &aValue);
     return true;
   }
 
   return false;
 }
 
@@ -1285,17 +1285,17 @@ nsGenericHTMLElement::MapCommonAttribute
                                               nsRuleData* aData)
 {
   MapCommonAttributesIntoExceptHidden(aAttributes, aData);
 
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
     nsCSSValue* display = aData->ValueForDisplay();
     if (display->GetUnit() == eCSSUnit_Null) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
-        display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
+        display->SetIntValue(StyleDisplay::None_, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
@@ -3092,17 +3092,17 @@ IsOrHasAncestorWithDisplayNone(Element* 
   RefPtr<nsStyleContext> sc;
   for (int32_t i = elementsToCheck.Length() - 1; i >= 0; --i) {
     if (sc) {
       sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc);
     } else {
       sc = nsComputedDOMStyle::GetStyleContextForElementNoFlush(elementsToCheck[i],
                                                                 nullptr, aPresShell);
     }
-    if (sc->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_NONE) {
+    if (sc->StyleDisplay()->mDisplay == StyleDisplay::None_) {
       return true;
     }
   }
 
   return false;
 }
 
 void
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -252,24 +252,22 @@ NS_NewHTMLElement(Element** aResult, alr
                "Trying to HTML elements that don't have the XHTML namespace");
 
   // Per the Custom Element specification, unknown tags that are valid custom
   // element names should be HTMLElement instead of HTMLUnknownElement.
   int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name);
   if ((tag == eHTMLTag_userdefined &&
       nsContentUtils::IsCustomElementName(name)) ||
       aIs) {
-    nsIDocument* doc = nodeInfo->GetDocument();
-
     NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
     if (!*aResult) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    doc->SetupCustomElement(*aResult, kNameSpaceID_XHTML, aIs);
+    nsContentUtils::SetupCustomElement(*aResult, aIs);
 
     return NS_OK;
   }
 
   *aResult = CreateHTMLElement(tag,
                                nodeInfo.forget(), aFromParser).take();
   return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -552,36 +552,34 @@ nsHTMLDocument::StartDocumentLoad(const 
   bool loadAsHtml5 = true;
 
   if (!viewSource && xhtml) {
       // We're parsing XHTML as XML, remember that.
       mType = eXHTML;
       mCompatMode = eCompatibility_FullStandards;
       loadAsHtml5 = false;
   }
-  
+
   // TODO: Proper about:blank treatment is bug 543435
   if (loadAsHtml5 && view) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
     aChannel->GetOriginalURI(getter_AddRefs(uri));
     // Adapted from nsDocShell:
     // GetSpec can be expensive for some URIs, so check the scheme first.
     bool isAbout = false;
     if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
-      nsAutoCString str;
-      uri->GetSpec(str);
-      if (str.EqualsLiteral("about:blank")) {
-        loadAsHtml5 = false;    
+      if (uri->GetSpecOrDefault().EqualsLiteral("about:blank")) {
+        loadAsHtml5 = false;
       }
     }
   }
-  
+
   CSSLoader()->SetCompatibilityMode(mCompatMode);
-  
+
   nsresult rv = nsDocument::StartDocumentLoad(aCommand,
                                               aChannel, aLoadGroup,
                                               aContainer,
                                               aDocListener, aReset);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -743,17 +741,17 @@ nsHTMLDocument::StartDocumentLoad(const 
   SetDocumentCharacterSetSource(charsetSource);
   SetDocumentCharacterSet(charset);
 
   if (cachingChan) {
     NS_ASSERTION(charset == parserCharset,
                  "How did those end up different here?  wyciwyg channels are "
                  "not nsICachingChannel");
     rv = cachingChan->SetCacheTokenCachedCharset(charset);
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
     rv = NS_OK; // don't propagate error
   }
 
   // Set the parser as the stream listener for the document loader...
   rv = NS_OK;
   nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
   listener.forget(aDocListener);
 
@@ -1501,25 +1499,19 @@ nsHTMLDocument::Open(JSContext* cx,
 
   bool equals = false;
   if (NS_FAILED(callerPrincipal->Equals(NodePrincipal(), &equals)) ||
       !equals) {
 
 #ifdef DEBUG
     nsCOMPtr<nsIURI> callerDocURI = callerDoc->GetDocumentURI();
     nsCOMPtr<nsIURI> thisURI = nsIDocument::GetDocumentURI();
-    nsAutoCString callerSpec;
-    nsAutoCString thisSpec;
-    if (callerDocURI) {
-      callerDocURI->GetSpec(callerSpec);
-    }
-    if (thisURI) {
-      thisURI->GetSpec(thisSpec);
-    }
-    printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
+    printf("nsHTMLDocument::Open callerDoc %s this %s\n",
+           callerDocURI ? callerDocURI->GetSpecOrDefault().get() : "",
+           thisURI ? thisURI->GetSpecOrDefault().get() : "");
 #endif
 
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Stop current loads targeted at the window this document is in.
   if (mScriptGlobalObject) {
--- a/dom/icc/IccListener.cpp
+++ b/dom/icc/IccListener.cpp
@@ -40,18 +40,18 @@ IccListener::IccListener(IccManager* aIc
     nsString iccId;
     iccInfo->GetIccid(iccId);
     if (!iccId.IsEmpty()) {
       mIcc = new Icc(mIccManager->GetOwner(), mHandler, iccInfo);
     }
   }
 
   DebugOnly<nsresult> rv = mHandler->RegisterListener(this);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                   "Failed registering icc listener with Icc Handler");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Failed registering icc listener with Icc Handler");
 }
 
 IccListener::~IccListener()
 {
   Shutdown();
 }
 
 void
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -13252,26 +13252,29 @@ Factory::Create(const LoggingInfo& aLogg
   IncreaseBusyCount();
 
   MOZ_ASSERT(gLoggingInfoHashtable);
   RefPtr<DatabaseLoggingInfo> loggingInfo =
     gLoggingInfoHashtable->Get(aLoggingInfo.backgroundChildLoggingId());
   if (loggingInfo) {
     MOZ_ASSERT(aLoggingInfo.backgroundChildLoggingId() == loggingInfo->Id());
 #if !DISABLE_ASSERTS_FOR_FUZZING
-    NS_WARN_IF_FALSE(aLoggingInfo.nextTransactionSerialNumber() ==
-                       loggingInfo->mLoggingInfo.nextTransactionSerialNumber(),
-                     "NextTransactionSerialNumber doesn't match!");
-    NS_WARN_IF_FALSE(aLoggingInfo.nextVersionChangeTransactionSerialNumber() ==
-                       loggingInfo->mLoggingInfo.
-                         nextVersionChangeTransactionSerialNumber(),
-                     "NextVersionChangeTransactionSerialNumber doesn't match!");
-    NS_WARN_IF_FALSE(aLoggingInfo.nextRequestSerialNumber() ==
-                       loggingInfo->mLoggingInfo.nextRequestSerialNumber(),
-                     "NextRequestSerialNumber doesn't match!");
+    NS_WARNING_ASSERTION(
+      aLoggingInfo.nextTransactionSerialNumber() ==
+        loggingInfo->mLoggingInfo.nextTransactionSerialNumber(),
+      "NextTransactionSerialNumber doesn't match!");
+    NS_WARNING_ASSERTION(
+      aLoggingInfo.nextVersionChangeTransactionSerialNumber() ==
+        loggingInfo->mLoggingInfo.
+      nextVersionChangeTransactionSerialNumber(),
+      "NextVersionChangeTransactionSerialNumber doesn't match!");
+    NS_WARNING_ASSERTION(
+      aLoggingInfo.nextRequestSerialNumber() ==
+        loggingInfo->mLoggingInfo.nextRequestSerialNumber(),
+      "NextRequestSerialNumber doesn't match!");
 #endif // !DISABLE_ASSERTS_FOR_FUZZING
   } else {
     loggingInfo = new DatabaseLoggingInfo(aLoggingInfo);
     gLoggingInfoHashtable->Put(aLoggingInfo.backgroundChildLoggingId(),
                                loggingInfo);
   }
 
   RefPtr<Factory> actor = new Factory(loggingInfo.forget());
@@ -23084,29 +23087,30 @@ CommitOp::Run()
     if (DatabaseConnection* connection = database->GetConnection()) {
       // May be null if the VersionChangeOp was canceled.
       DatabaseConnection::UpdateRefcountFunction* fileRefcountFunction =
         connection->GetUpdateRefcountFunction();
 
       if (NS_SUCCEEDED(mResultCode)) {
         if (fileRefcountFunction) {
           mResultCode = fileRefcountFunction->WillCommit();
-          NS_WARN_IF_FALSE(NS_SUCCEEDED(mResultCode), "WillCommit() failed!");
+          NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode),
+                               "WillCommit() failed!");
         }
 
         if (NS_SUCCEEDED(mResultCode)) {
           mResultCode = WriteAutoIncrementCounts();
-          NS_WARN_IF_FALSE(NS_SUCCEEDED(mResultCode),
-                           "WriteAutoIncrementCounts() failed!");
+          NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode),
+                               "WriteAutoIncrementCounts() failed!");
 
           if (NS_SUCCEEDED(mResultCode)) {
             AssertForeignKeyConsistency(connection);
 
             mResultCode = connection->CommitWriteTransaction();
-            NS_WARN_IF_FALSE(NS_SUCCEEDED(mResultCode), "Commit failed!");
+            NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode), "Commit failed!");
 
             if (NS_SUCCEEDED(mResultCode) &&
                 mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH) {
               mResultCode = connection->Checkpoint();
             }
 
             if (NS_SUCCEEDED(mResultCode) && fileRefcountFunction) {
               fileRefcountFunction->DidCommit();
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1599,17 +1599,18 @@ private:
 
     // Going to always release here.
     nsCOMPtr<nsIInputStream> stream;
     mStream.swap(stream);
 
     nsCOMPtr<nsIThread> ioTarget;
     mIOTarget.swap(ioTarget);
 
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(stream->Close()), "Failed to close stream!");
+    DebugOnly<nsresult> rv = stream->Close();
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to close stream!");
 
     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(ioTarget, &nsIThread::Shutdown)));
 
     return NS_OK;
   }
 
   nsresult
   SendResponse()
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -27,16 +27,17 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
 #include "mozilla/dom/GetFilesHelper.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/ProcessGlobal.h"
+#include "mozilla/dom/PushNotifier.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
@@ -162,20 +163,16 @@
 #ifdef MOZ_X11
 #include "mozilla/X11Util.h"
 #endif
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
-#ifndef MOZ_SIMPLEPUSH
-#include "mozilla/dom/PushNotifier.h"
-#endif
-
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h"
 #include "mozilla/dom/icc/IccChild.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 #include "mozilla/dom/bluetooth/PBluetoothChild.h"
 #include "mozilla/dom/PFMRadioChild.h"
@@ -570,17 +567,17 @@ ContentChild::Init(MessageLoop* aIOLoop,
   XRE_InstallX11ErrorHandler();
 #endif
 
   NS_ASSERTION(!sSingleton, "only one ContentChild per child");
 
   // Once we start sending IPC messages, we need the thread manager to be
   // initialized so we can deal with the responses. Do that here before we
   // try to construct the crash reporter.
-  nsresult rv = nsThreadManager::get()->Init();
+  nsresult rv = nsThreadManager::get().Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   if (!Open(aChannel, aParentPid, aIOLoop)) {
     return false;
   }
   sSingleton = this;
@@ -3250,66 +3247,56 @@ ContentChild::RecvEndDragSession(const b
   return true;
 }
 
 bool
 ContentChild::RecvPush(const nsCString& aScope,
                        const IPC::Principal& aPrincipal,
                        const nsString& aMessageId)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
-#endif
   return true;
 }
 
 bool
 ContentChild::RecvPushWithData(const nsCString& aScope,
                                const IPC::Principal& aPrincipal,
                                const nsString& aMessageId,
                                InfallibleTArray<uint8_t>&& aData)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Some(aData));
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
-#endif
   return true;
 }
 
 bool
 ContentChild::RecvPushSubscriptionChange(const nsCString& aScope,
                                          const IPC::Principal& aPrincipal)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
-#endif
   return true;
 }
 
 bool
 ContentChild::RecvPushError(const nsCString& aScope, const IPC::Principal& aPrincipal,
                             const nsString& aMessage, const uint32_t& aFlags)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
-#endif
   return true;
 }
 
 bool
 ContentChild::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScope,
                                                           const IPC::Principal& aPrincipal)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
-#endif
   return true;
 }
 
 bool
 ContentChild::RecvBlobURLRegistration(const nsCString& aURI, PBlobChild* aBlobChild,
                                       const IPC::Principal& aPrincipal)
 {
   RefPtr<BlobImpl> blobImpl = static_cast<BlobChild*>(aBlobChild)->GetBlobImpl();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -61,16 +61,17 @@
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/icc/IccParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/PresentationParent.h"
 #include "mozilla/dom/PPresentationParent.h"
+#include "mozilla/dom/PushNotifier.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
 #include "mozilla/dom/quota/QuotaManagerService.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailParent.h"
 #include "mozilla/embedding/printingui/PrintingParent.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
@@ -258,20 +259,16 @@ using namespace mozilla::system;
 #include "nsIBrowserSearchService.h"
 #endif
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "nsIProfiler.h"
 #include "nsIProfileSaveEvent.h"
 #endif
 
-#ifndef MOZ_SIMPLEPUSH
-#include "mozilla/dom/PushNotifier.h"
-#endif
-
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsThread.h"
 #endif
 
@@ -5221,55 +5218,47 @@ ContentParent::StartProfiler(nsIProfiler
 #endif
 }
 
 bool
 ContentParent::RecvNotifyPushObservers(const nsCString& aScope,
                                        const IPC::Principal& aPrincipal,
                                        const nsString& aMessageId)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
-#endif
   return true;
 }
 
 bool
 ContentParent::RecvNotifyPushObserversWithData(const nsCString& aScope,
                                                const IPC::Principal& aPrincipal,
                                                const nsString& aMessageId,
                                                InfallibleTArray<uint8_t>&& aData)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Some(aData));
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
-#endif
   return true;
 }
 
 bool
 ContentParent::RecvNotifyPushSubscriptionChangeObservers(const nsCString& aScope,
                                                          const IPC::Principal& aPrincipal)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
-#endif
   return true;
 }
 
 bool
 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScope,
                                                            const IPC::Principal& aPrincipal)
 {
-#ifndef MOZ_SIMPLEPUSH
   PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
-#endif
   return true;
 }
 
 bool
 ContentParent::RecvNotifyLowMemory()
 {
 #ifdef MOZ_CRASHREPORTER
   nsThread::SaveMemoryReportNearOOM(nsThread::ShouldSaveMemoryReport::kForceReport);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -1083,17 +1083,18 @@ nsJSChannel::GetExecutionPolicy(uint32_t
 
 NS_IMETHODIMP
 nsJSChannel::SetExecuteAsync(bool aIsAsync)
 {
     if (!mIsActive) {
         mIsAsync = aIsAsync;
     }
     // else ignore this call
-    NS_WARN_IF_FALSE(!mIsActive, "Calling SetExecuteAsync on active channel?");
+    NS_WARNING_ASSERTION(!mIsActive,
+                         "Calling SetExecuteAsync on active channel?");
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJSChannel::GetExecuteAsync(bool* aIsAsync)
 {
     *aIsAsync = mIsAsync;
--- a/dom/media/AudioBufferUtils.h
+++ b/dom/media/AudioBufferUtils.h
@@ -78,18 +78,19 @@ public:
     // It's okay to have exactly zero samples here, it can happen we have an
     // audio callback driver because of a hint on MSG creation, but the
     // AudioOutputStream has not been created yet, or if all the streams have finished
     // but we're still running.
     // Note: it's also ok if we had data in the scratch buffer - and we usually do - and
     // all the streams were ended (no mixer callback occured).
     // XXX Remove this warning, or find a way to avoid it if the mixer callback
     // isn't called.
-    NS_WARN_IF_FALSE(Available() == 0 || mSampleWriteOffset == 0,
-            "Audio Buffer is not full by the end of the callback.");
+    NS_WARNING_ASSERTION(
+      Available() == 0 || mSampleWriteOffset == 0,
+      "Audio Buffer is not full by the end of the callback.");
     // Make sure the data returned is always set and not random!
     if (Available()) {
       PodZero(mBuffer + mSampleWriteOffset, FramesToSamples(CHANNELS, Available()));
     }
     MOZ_ASSERT(mSamples, "Buffer not set.");
     mSamples = 0;
     mSampleWriteOffset = 0;
     mBuffer = nullptr;
--- a/dom/media/AudioSegment.h
+++ b/dom/media/AudioSegment.h
@@ -360,18 +360,19 @@ public:
   // channels.
   void WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aChannelCount,
                uint32_t aSampleRate);
   // Mix the segment into a mixer, keeping it planar, up or down mixing to
   // aChannelCount channels.
   void Mix(AudioMixer& aMixer, uint32_t aChannelCount, uint32_t aSampleRate);
 
   int ChannelCount() {
-    NS_WARN_IF_FALSE(!mChunks.IsEmpty(),
-        "Cannot query channel count on a AudioSegment with no chunks.");
+    NS_WARNING_ASSERTION(
+      !mChunks.IsEmpty(),
+      "Cannot query channel count on a AudioSegment with no chunks.");
     // Find the first chunk that has non-zero channels. A chunk that hs zero
     // channels is just silence and we can simply discard it.
     for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
       if (ci->ChannelCount()) {
         return ci->ChannelCount();
       }
     }
     return 0;
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -144,18 +144,18 @@ void InitBrandName()
     mozilla::services::GetStringBundleService();
   if (stringBundleService) {
     nsCOMPtr<nsIStringBundle> brandBundle;
     nsresult rv = stringBundleService->CreateBundle(kBrandBundleURL,
                                            getter_AddRefs(brandBundle));
     if (NS_SUCCEEDED(rv)) {
       rv = brandBundle->GetStringFromName(u"brandShortName",
                                           getter_Copies(brandName));
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-          "Could not get the program name for a cubeb stream.");
+      NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv), "Could not get the program name for a cubeb stream.");
     }
   }
   /* cubeb expects a c-string. */
   const char* ascii = NS_LossyConvertUTF16toASCII(brandName).get();
   sBrandName = new char[brandName.Length() + 1];
   PodCopy(sBrandName.get(), ascii, brandName.Length());
   sBrandName[brandName.Length()] = 0;
 }
@@ -165,22 +165,22 @@ cubeb* GetCubebContextUnlocked()
   sMutex.AssertCurrentThreadOwns();
   if (sCubebContext) {
     return sCubebContext;
   }
 
   if (!sBrandName && NS_IsMainThread()) {
     InitBrandName();
   } else {
-    NS_WARN_IF_FALSE(sBrandName,
-        "Did not initialize sbrandName, and not on the main thread?");
+    NS_WARNING_ASSERTION(
+      sBrandName, "Did not initialize sbrandName, and not on the main thread?");
   }
 
   DebugOnly<int> rv = cubeb_init(&sCubebContext, sBrandName);
-  NS_WARN_IF_FALSE(rv == CUBEB_OK, "Could not get a cubeb context.");
+  NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
 
   return sCubebContext;
 }
 
 void ReportCubebBackendUsed()
 {
   StaticMutexAutoLock lock(sMutex);
 
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -148,21 +148,21 @@ public:
     if (track) {
       LOG(LogLevel::Debug, ("DOMMediaStream %p Track %d from owned stream %p "
                             "bound to MediaStreamTrack %p.",
                             mStream, aTrackID, aInputStream, track));
       return;
     }
 
     // Track had not been created on main thread before, create it now.
-    NS_WARN_IF_FALSE(!mStream->mTracks.IsEmpty(),
-                     "A new track was detected on the input stream; creating "
-                     "a corresponding MediaStreamTrack. Initial tracks "
-                     "should be added manually to immediately and "
-                     "synchronously be available to JS.");
+    NS_WARNING_ASSERTION(
+      !mStream->mTracks.IsEmpty(),
+      "A new track was detected on the input stream; creating a corresponding "
+      "MediaStreamTrack. Initial tracks should be added manually to "
+      "immediately and synchronously be available to JS.");
     RefPtr<MediaStreamTrackSource> source;
     if (mStream->mTrackSourceGetter) {
       source = mStream->mTrackSourceGetter->GetMediaStreamTrackSource(aTrackID);
     }
     if (!source) {
       NS_ASSERTION(false, "Dynamic track created without an explicit TrackSource");
       nsPIDOMWindowInner* window = mStream->GetParentObject();
       nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -481,17 +481,18 @@ OfflineClockDriver::WakeUp()
   MOZ_ASSERT(false, "An offline graph should not have to wake up.");
 }
 
 AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation)
   : mDriver(aDriver),
     mOperation(aOperation),
     mShutdownGrip(aDriver->GraphImpl())
 {
-  NS_WARN_IF_FALSE(mDriver->mAudioStream || aOperation == INIT, "No audio stream !");
+  NS_WARNING_ASSERTION(mDriver->mAudioStream || aOperation == INIT,
+                       "No audio stream!");
 }
 
 AsyncCubebTask::~AsyncCubebTask()
 {
 }
 
 /* static */
 nsresult
@@ -653,18 +654,19 @@ AudioCallbackDriver::Init()
                           "AudioCallbackDriver",
                           input_id,
                           mGraphImpl->mInputWanted ? &input : nullptr,
                           output_id,
                           mGraphImpl->mOutputWanted ? &output : nullptr, latency_frames,
                           DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
       mAudioStream.own(stream);
       DebugOnly<int> rv = cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale());
-      NS_WARN_IF_FALSE(rv == CUBEB_OK,
-          "Could not set the audio stream volume in GraphDriver.cpp");
+      NS_WARNING_ASSERTION(
+        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");
       // 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
@@ -1003,17 +1005,17 @@ AudioCallbackDriver::MixerCallback(Audio
   }
 
   MOZ_ASSERT(mBuffer.Available() <= aFrames);
 
   mBuffer.WriteFrames(aMixedBuffer, mBuffer.Available());
   MOZ_ASSERT(mBuffer.Available() == 0, "Missing frames to fill audio callback's buffer.");
 
   DebugOnly<uint32_t> written = mScratchBuffer.Fill(aMixedBuffer + toWrite * aChannels, aFrames - toWrite);
-  NS_WARN_IF_FALSE(written == aFrames - toWrite, "Dropping frames.");
+  NS_WARNING_ASSERTION(written == aFrames - toWrite, "Dropping frames.");
 };
 
 void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive)
 {
 #ifdef XP_MACOSX
   cubeb_device* out;
   int rv;
   char name[128];
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -1721,18 +1721,18 @@ MediaCacheStream::NotifyDataLength(int64
 }
 
 void
 MediaCacheStream::NotifyDataStarted(int64_t aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
-  NS_WARN_IF_FALSE(aOffset == mChannelOffset,
-                   "Server is giving us unexpected offset");
+  NS_WARNING_ASSERTION(aOffset == mChannelOffset,
+                       "Server is giving us unexpected offset");
   MOZ_ASSERT(aOffset >= 0);
   mChannelOffset = aOffset;
   if (mStreamLength >= 0) {
     // If we started reading at a certain offset, then for sure
     // the stream is at least that long.
     mStreamLength = std::max(mStreamLength, mChannelOffset);
   }
 }
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -277,17 +277,17 @@ public:
     switch (aDegree) {
       case 90:
         return kDegree_90;
       case 180:
         return kDegree_180;
       case 270:
         return kDegree_270;
       default:
-        NS_WARN_IF_FALSE(aDegree == 0, "Invalid rotation degree, ignored");
+        NS_WARNING_ASSERTION(aDegree == 0, "Invalid rotation degree, ignored");
         return kDegree_0;
     }
   }
 
   // Size in pixels at which the video is rendered. This is after it has
   // been scaled by its aspect ratio.
   nsIntSize mDisplay;
 
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -249,18 +249,19 @@ ChannelMediaResource::OnStartRequest(nsI
         //       For now, tell the decoder that the stream is infinite.
         if (rangeTotal == -1) {
           boundedSeekLimit = false;
         } else {
           contentLength = std::max(contentLength, rangeTotal);
         }
         // Give some warnings if the ranges are unexpected.
         // XXX These could be error conditions.
-        NS_WARN_IF_FALSE(mOffset == rangeStart,
-                         "response range start does not match current offset");
+        NS_WARNING_ASSERTION(
+          mOffset == rangeStart,
+          "response range start does not match current offset");
         mOffset = rangeStart;
         mCacheStream.NotifyDataStarted(rangeStart);
       }
       acceptsRanges = gotRangeHeader;
     } else if (mOffset > 0 && responseStatus == HTTP_OK_CODE) {
       // If we get an OK response but we were seeking, or requesting a byte
       // range, then we have to assume that seeking doesn't work. We also need
       // to tell the cache that it's getting data for the start of the stream.
--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -1773,18 +1773,18 @@ OggDemuxer::GetSeekRanges(TrackInfo::Tra
     if (NS_FAILED(Reset(aType))) {
       return NS_ERROR_FAILURE;
     }
     int64_t startOffset = range.mStart;
     int64_t endOffset = range.mEnd;
     startTime = RangeStartTime(aType, startOffset);
     if (startTime != -1 &&
         ((endTime = RangeEndTime(aType, endOffset)) != -1)) {
-      NS_WARN_IF_FALSE(startTime < endTime,
-                       "Start time must be before end time");
+      NS_WARNING_ASSERTION(startTime < endTime,
+                           "Start time must be before end time");
       aRanges.AppendElement(SeekRange(startOffset,
                                       endOffset,
                                       startTime,
                                       endTime));
      }
   }
   if (NS_FAILED(Reset(aType))) {
     return NS_ERROR_FAILURE;
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -1198,18 +1198,18 @@ nsresult OggReader::GetSeekRanges(nsTArr
       return NS_ERROR_FAILURE;
     }
     int64_t startOffset = range.mStart;
     int64_t endOffset = range.mEnd;
     startTime = RangeStartTime(startOffset);
     if (startTime != -1 &&
         ((endTime = RangeEndTime(endOffset)) != -1))
     {
-      NS_WARN_IF_FALSE(startTime < endTime,
-                       "Start time must be before end time");
+      NS_WARNING_ASSERTION(startTime < endTime,
+                           "Start time must be before end time");
       aRanges.AppendElement(SeekRange(startOffset,
                                       endOffset,
                                       startTime,
                                       endTime));
      }
   }
   if (NS_FAILED(ResetDecode())) {
     return NS_ERROR_FAILURE;
--- a/dom/media/webaudio/DelayBuffer.cpp
+++ b/dom/media/webaudio/DelayBuffer.cpp
@@ -233,18 +233,18 @@ void
 DelayBuffer::UpdateUpmixChannels(int aNewReadChunk, uint32_t aChannelCount,
                                  ChannelInterpretation aChannelInterpretation)
 {
   if (aNewReadChunk == mLastReadChunk) {
     MOZ_ASSERT(mUpmixChannels.Length() == aChannelCount);
     return;
   }
 
-  NS_WARN_IF_FALSE(mHaveWrittenBlock || aNewReadChunk != mCurrentChunk,
-                   "Smoothing is making feedback delay too small.");
+  NS_WARNING_ASSERTION(mHaveWrittenBlock || aNewReadChunk != mCurrentChunk,
+                       "Smoothing is making feedback delay too small.");
 
   mLastReadChunk = aNewReadChunk;
   mUpmixChannels = mChunks[aNewReadChunk].ChannelData<float>();
   MOZ_ASSERT(mUpmixChannels.Length() <= aChannelCount);
   if (mUpmixChannels.Length() < aChannelCount) {
     if (aChannelInterpretation == ChannelInterpretation::Speakers) {
       AudioChannelsUpMix(&mUpmixChannels,
                          aChannelCount, SilentChannel::ZeroChannel<float>());
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -140,19 +140,20 @@ public:
   void NotifyPull(MediaStreamGraph* aGraph,
                   SourceMediaStream *aSource,
                   TrackID aId,
                   StreamTime aDesiredTime,
                   const PrincipalHandle& aPrincipalHandle) override
   {
 #ifdef DEBUG
     StreamTracks::Track* data = aSource->FindTrack(aId);
-    NS_WARN_IF_FALSE(!data || data->IsEnded() ||
-                     aDesiredTime <= aSource->GetEndOfAppendedData(aId),
-                     "MediaEngineDefaultAudioSource data underrun");
+    NS_WARNING_ASSERTION(
+      !data || data->IsEnded() ||
+      aDesiredTime <= aSource->GetEndOfAppendedData(aId),
+      "MediaEngineDefaultAudioSource data underrun");
 #endif
   }
 
   void NotifyOutputData(MediaStreamGraph* aGraph,
                         AudioDataValue* aBuffer, size_t aFrames,
                         TrackRate aRate, uint32_t aChannels) override
   {}
   void NotifyInputData(MediaStreamGraph* aGraph,
--- a/dom/media/webrtc/PeerIdentity.cpp
+++ b/dom/media/webrtc/PeerIdentity.cpp
@@ -74,12 +74,13 @@ PeerIdentity::GetHost(const nsAString& a
 
 /* static */ void
 PeerIdentity::GetNormalizedHost(const nsCOMPtr<nsIIDNService>& aIdnService,
                                 const nsAString& aHost,
                                 nsACString& aNormalizedHost)
 {
   const nsCString chost = NS_ConvertUTF16toUTF8(aHost);
   DebugOnly<nsresult> rv = aIdnService->ConvertUTF8toACE(chost, aNormalizedHost);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to convert UTF-8 host to ASCII");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Failed to convert UTF-8 host to ASCII");
 }
 
 } /* namespace mozilla */
--- a/dom/media/webspeech/synth/SpeechSynthesisVoice.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesisVoice.cpp
@@ -48,45 +48,47 @@ SpeechSynthesisVoice::GetVoiceURI(nsStri
   aRetval = mUri;
 }
 
 void
 SpeechSynthesisVoice::GetName(nsString& aRetval) const
 {
   DebugOnly<nsresult> rv =
     nsSynthVoiceRegistry::GetInstance()->GetVoiceName(mUri, aRetval);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get SpeechSynthesisVoice.name");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Failed to get SpeechSynthesisVoice.name");
 }
 
 void
 SpeechSynthesisVoice::GetLang(nsString& aRetval) const
 {
   DebugOnly<nsresult> rv =
     nsSynthVoiceRegistry::GetInstance()->GetVoiceLang(mUri, aRetval);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get SpeechSynthesisVoice.lang");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "Failed to get SpeechSynthesisVoice.lang");
 }
 
 bool
 SpeechSynthesisVoice::LocalService() const
 {
   bool isLocal;
   DebugOnly<nsresult> rv =
     nsSynthVoiceRegistry::GetInstance()->IsLocalVoice(mUri, &isLocal);
-  NS_WARN_IF_FALSE(
+  NS_WARNING_ASSERTION(
     NS_SUCCEEDED(rv), "Failed to get SpeechSynthesisVoice.localService");
 
   return isLocal;
 }
 
 bool
 SpeechSynthesisVoice::Default() const
 {
   bool isDefault;
   DebugOnly<nsresult> rv =
     nsSynthVoiceRegistry::GetInstance()->IsDefaultVoice(mUri, &isDefault);
-  NS_WARN_IF_FALSE(
+  NS_WARNING_ASSERTION(
     NS_SUCCEEDED(rv), "Failed to get SpeechSynthesisVoice.default");
 
   return isDefault;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -597,17 +597,17 @@ nsSpeechTask::DispatchMarkImpl(const nsA
 
 void
 nsSpeechTask::Pause()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   if (mCallback) {
     DebugOnly<nsresult> rv = mCallback->OnPause();
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onPause() callback");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to call onPause() callback");
   }
 
   if (mStream) {
     mStream->Suspend();
   }
 
   if (!mInited) {
     mPrePaused = true;
@@ -620,17 +620,18 @@ nsSpeechTask::Pause()
 
 void
 nsSpeechTask::Resume()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   if (mCallback) {
     DebugOnly<nsresult> rv = mCallback->OnResume();
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onResume() callback");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                         "Unable to call onResume() callback");
   }
 
   if (mStream) {
     mStream->Resume();
   }
 
   if (mPrePaused) {
     mPrePaused = false;
@@ -646,17 +647,18 @@ void
 nsSpeechTask::Cancel()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   LOG(LogLevel::Debug, ("nsSpeechTask::Cancel"));
 
   if (mCallback) {
     DebugOnly<nsresult> rv = mCallback->OnCancel();
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onCancel() callback");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                         "Unable to call onCancel() callback");
   }
 
   if (mStream) {
     mStream->Suspend();
   }
 
   if (!mInited) {
     mPreCanceled = true;
--- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
+++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
@@ -809,17 +809,17 @@ nsSynthVoiceRegistry::SpeakImpl(VoiceDat
   LOG(LogLevel::Debug,
       ("nsSynthVoiceRegistry::SpeakImpl queueing text='%s' uri='%s' rate=%f pitch=%f",
        NS_ConvertUTF16toUTF8(aText).get(), NS_ConvertUTF16toUTF8(aVoice->mUri).get(),
        aRate, aPitch));
 
   SpeechServiceType serviceType;
 
   DebugOnly<nsresult> rv = aVoice->mService->GetServiceType(&serviceType);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get speech service type");
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to get speech service type");
 
   if (serviceType == nsISpeechService::SERVICETYPE_INDIRECT_AUDIO) {
     aTask->InitIndirectAudio();
   } else {
     aTask->InitDirectAudio();
   }
 
   if (NS_FAILED(aVoice->mService->Speak(aText, aVoice->mUri, aVolume, aRate,
--- a/dom/media/webspeech/synth/pico/nsPicoService.cpp
+++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp
@@ -600,17 +600,17 @@ nsPicoService::RegisterVoices()
     nsAutoString name;
     name.AssignLiteral("Pico ");
     name.Append(voice->mLanguage);
 
     // This service is multi-threaded and can handle more than one utterance at a
     // time before previous utterances end. So, aQueuesUtterances == false
     DebugOnly<nsresult> rv =
       registry->AddVoice(this, uri, name, voice->mLanguage, true, false);
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add voice");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to add voice");
   }
 
   mInitialized = true;
 }
 
 bool
 nsPicoService::GetVoiceFileLanguage(const nsACString& aFileName, nsAString& aLang)
 {
--- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp
+++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp
@@ -435,17 +435,17 @@ SpeechDispatcherService::RegisterVoices(
 
     // This service can only speak one utterance at a time, so we set
     // aQueuesUtterances to true in order to track global state and schedule
     // access to this service.
     DebugOnly<nsresult> rv =
       registry->AddVoice(this, iter.Key(), voice->mName, voice->mLanguage,
                          voice->mName.EqualsLiteral("default"), true);
 
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add voice");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to add voice");
   }
 
   mInitThread->Shutdown();
   mInitThread = nullptr;
 
   mInitialized = true;
 
   registry->NotifyVoicesChanged();
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -136,35 +136,36 @@ MobileConnection::MobileConnection(nsPID
   }
 
   mListener = new Listener(this);
   mVoice = new MobileConnectionInfo(GetOwner());
   mData = new MobileConnectionInfo(GetOwner());
 
   if (CheckPermission("mobileconnection")) {
     DebugOnly<nsresult> rv = mMobileConnection->RegisterListener(mListener);
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                     "Failed registering mobile connection messages with service");
+    NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "Failed registering mobile connection messages with service");
     UpdateVoice();
     UpdateData();
 
     nsCOMPtr<nsIIccService> iccService = do_GetService(ICC_SERVICE_CONTRACTID);
 
     if (iccService) {
       iccService->GetIccByServiceId(mClientId, getter_AddRefs(mIccHandler));
     }
 
     if (!mIccHandler) {
       NS_WARNING("Could not acquire nsIMobileConnection or nsIIcc!");
       return;
     }
 
     rv = mIccHandler->RegisterListener(mListener);
-    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                     "Failed registering icc messages with service");
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                         "Failed registering icc messages with service");
     UpdateIccId();
   }
 }
 
 void
 MobileConnection::Shutdown()
 {
   if (mListener) {
--- a/dom/mobilemessage/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/ipc/SmsIPCService.cpp
@@ -33,18 +33,18 @@ SmsIPCService* sSingleton = nullptr;
 PSmsChild*
 GetSmsChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gSmsChild) {
     gSmsChild = ContentChild::GetSingleton()->SendPSmsConstructor();
 
-    NS_WARN_IF_FALSE(gSmsChild,
-                     "Calling methods on SmsIPCService during shutdown!");
+    NS_WARNING_ASSERTION(gSmsChild,
+                         "Calling methods on SmsIPCService during shutdown!");
   }
 
   return gSmsChild;
 }
 
 nsresult
 SendRequest(const IPCSmsRequest& aRequest,
             nsIMobileMessageCallback* aRequestReply)
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -70,16 +70,17 @@ DIRS += [
     'jsurl',
     'asmjscache',
     'mathml',
     'media',
     'mobileconnection',
     'notification',
     'offline',
     'power',
+    'push',
     'quota',
     'security',
     'settings',
     'storage',
     'svg',
     'mobilemessage',
     'time',
     'locales',
@@ -130,21 +131,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += [
         'wappush',
     ]
 
 if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
-if CONFIG['MOZ_SIMPLEPUSH']:
-    DIRS += ['simplepush']
-else:
-    DIRS += ['push']
-
 if CONFIG['MOZ_SECUREELEMENT']:
     DIRS += ['secureelement']
 
 if CONFIG['MOZ_B2G']:
     DIRS += [
         'downloads',
         'identity'
     ]
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -33,16 +33,17 @@
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsIDocument.h"
 #include "nsILoadContext.h"
 #include "nsINotificationStorage.h"
 #include "nsIPermissionManager.h"
 #include "nsIPermission.h"
+#include "nsIPushService.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIServiceWorkerManager.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIXPConnect.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsServiceManagerUtils.h"
@@ -54,20 +55,16 @@
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 #ifdef MOZ_B2G
 #include "nsIDOMDesktopNotification.h"
 #endif
 
-#ifndef MOZ_SIMPLEPUSH
-#include "nsIPushService.h"
-#endif
-
 namespace mozilla {
 namespace dom {
 
 using namespace workers;
 
 struct NotificationStrings
 {
   const nsString mID;
@@ -1441,36 +1438,32 @@ NotificationObserver::Observe(nsISupport
   }
 
   return mObserver->Observe(aSubject, aTopic, aData);
 }
 
 nsresult
 NotificationObserver::AdjustPushQuota(const char* aTopic)
 {
-#ifdef MOZ_SIMPLEPUSH
-  return NS_ERROR_NOT_IMPLEMENTED;
-#else
   nsCOMPtr<nsIPushQuotaManager> pushQuotaManager =
     do_GetService("@mozilla.org/push/Service;1");
   if (!pushQuotaManager) {
     return NS_ERROR_FAILURE;
   }
 
   nsAutoCString origin;
   nsresult rv = mPrincipal->GetOrigin(origin);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (!strcmp("alertshow", aTopic)) {
     return pushQuotaManager->NotificationForOriginShown(origin.get());
   }
   return pushQuotaManager->NotificationForOriginClosed(origin.get());
-#endif
 }
 
 NS_IMETHODIMP
 MainThreadNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
                                         const char16_t* aData)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mNotificationRef);
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -944,22 +944,20 @@ nsresult nsPluginHost::SetUpPluginInstan
 }
 
 nsresult
 nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
                                      nsIURI *aURL,
                                      nsPluginInstanceOwner *aOwner)
 {
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec;
-  if (aURL != nullptr) aURL->GetSpec(urlSpec);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-        ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
-         PromiseFlatCString(aMimeType).get(), aOwner, urlSpec.get()));
+          ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
+           PromiseFlatCString(aMimeType).get(), aOwner,
+           aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
 #ifdef XP_WIN
   bool changed;
   if ((mRegKeyHKLM && NS_SUCCEEDED(mRegKeyHKLM->HasChanged(&changed)) && changed) ||
       (mRegKeyHKCU && NS_SUCCEEDED(mRegKeyHKCU->HasChanged(&changed)) && changed)) {
@@ -1008,23 +1006,20 @@ nsPluginHost::TrySetUpPluginInstance(con
 
   // Cancel the plugin unload timer since we are creating
   // an instance for it.
   if (pluginTag->mUnloadTimer) {
     pluginTag->mUnloadTimer->Cancel();
   }
 
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec2;
-  if (aURL)
-    aURL->GetSpec(urlSpec2);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
-         PromiseFlatCString(aMimeType).get(), rv, aOwner, urlSpec2.get()));
+         PromiseFlatCString(aMimeType).get(), rv, aOwner,
+         aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
   return rv;
 }
 
 bool
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -305,21 +305,19 @@ nsPluginStreamListenerPeer::~nsPluginStr
 
 // Called as a result of GetURL and PostURL, or by the host in the case of the
 // initial plugin stream.
 nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
                                                 nsNPAPIPluginInstance *aInstance,
                                                 nsNPAPIPluginStreamListener* aListener)
 {
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec;
-  if (aURL != nullptr) aURL->GetSpec(urlSpec);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-         ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance, urlSpec.get()));
+          ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n",
+           aInstance, aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
   // Not gonna work out
   if (!aInstance) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -22,17 +22,17 @@ XPCOMUtils.defineLazyGetter(this, "conso
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "PushService",
   "@mozilla.org/push/Service;1", "nsIPushService");
 
 const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
 
 /**
- * The Push component runs in the child process and exposes the SimplePush API
+ * The Push component runs in the child process and exposes the Push API
  * to the web application. The PushService running in the parent process is the
  * one actually performing all operations.
  */
 function Push() {
   console.debug("Push()");
 }
 
 Push.prototype = {
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -1053,17 +1053,17 @@ this.PushService = {
           return this._service.unregister(...params);
       }
       return Promise.reject(new Error("Unknown request type: " + action));
     });
   },
 
   /**
    * Called on message from the child process. aPageRecord is an object sent by
-   * navigator.push, identifying the sending page and other fields.
+   * the push manager, identifying the sending page and other fields.
    */
   _registerWithServer: function(aPageRecord) {
     console.debug("registerWithServer()", aPageRecord);
 
     Services.telemetry.getHistogramById("PUSH_API_SUBSCRIBE_ATTEMPT").add();
     return this._sendRequest("register", aPageRecord)
       .then(record => this._onRegisterSuccess(record),
             err => this._onRegisterError(err))
--- a/dom/security/SRICheck.cpp
+++ b/dom/security/SRICheck.cpp
@@ -58,23 +58,21 @@ IsEligible(nsIChannel* aChannel, const C
   nsCOMPtr<nsIURI> originalURI;
   rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
   NS_ENSURE_SUCCESS(rv, rv);
   nsAutoCString requestSpec;
   rv = originalURI->GetSpec(requestSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
-    nsAutoCString documentSpec, finalSpec;
+    nsAutoCString documentSpec;
     aDocument->GetDocumentURI()->GetAsciiSpec(documentSpec);
-    if (finalURI) {
-      finalURI->GetSpec(finalSpec);
-    }
     SRILOG(("SRICheck::IsEligible, documentURI=%s; requestURI=%s; finalURI=%s",
-            documentSpec.get(), requestSpec.get(), finalSpec.get()));
+            documentSpec.get(), requestSpec.get(),
+            finalURI ? finalURI->GetSpecOrDefault().get() : ""));
   }
 
   // Is the sub-resource same-origin?
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (NS_SUCCEEDED(ssm->CheckSameOriginURI(aDocument->GetDocumentURI(),
                                            finalURI, false))) {
     SRILOG(("SRICheck::IsEligible, same-origin"));
     return NS_OK;
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -104,19 +104,18 @@ nsCSPContext::ShouldLoad(nsContentPolicy
                          nsIURI*             aContentLocation,
                          nsIURI*             aRequestOrigin,
                          nsISupports*        aRequestContext,
                          const nsACString&   aMimeTypeGuess,
                          nsISupports*        aExtra,
                          int16_t*            outDecision)
 {
   if (CSPCONTEXTLOGENABLED()) {
-    nsAutoCString spec;
-    aContentLocation->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s", spec.get()));
+    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
+                   aContentLocation->GetSpecOrDefault().get()));
     CSPCONTEXTLOG((">>>>                      aContentType: %d", aContentType));
   }
 
   bool isPreload = nsContentUtils::IsPreloadType(aContentType);
 
   // Since we know whether we are dealing with a preload, we have to convert
   // the internal policytype ot the external policy type before moving on.
   // We still need to know if this is a worker so child-src can handle that
@@ -180,19 +179,20 @@ nsCSPContext::ShouldLoad(nsContentPolicy
                            : nsIContentPolicy::REJECT_SERVER;
 
   // Done looping, cache any relevant result
   if (cacheKey.Length() > 0 && !isPreload) {
     mShouldLoadCache.Put(cacheKey, *outDecision);
   }
 
   if (CSPCONTEXTLOGENABLED()) {
-    nsAutoCString spec;
-    aContentLocation->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, aContentLocation: %s", *outDecision > 0 ? "load" : "deny", spec.get()));
+    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
+                   "aContentLocation: %s",
+                   *outDecision > 0 ? "load" : "deny",
+                   aContentLocation->GetSpecOrDefault().get()));
   }
   return NS_OK;
 }
 
 bool
 nsCSPContext::permitsInternal(CSPDirective aDir,
                               nsIURI* aContentLocation,
                               nsIURI* aOriginalURI,
@@ -1221,19 +1221,18 @@ nsCSPContext::PermitsAncestry(nsIDocShel
       rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // We don't care if this succeeds, just want to delete a userpass if
       // there was one.
       uriClone->SetUserPass(EmptyCString());
 
       if (CSPCONTEXTLOGENABLED()) {
-        nsAutoCString spec;
-        uriClone->GetSpec(spec);
-        CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s", spec.get()));
+        CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s",
+                       uriClone->GetSpecOrDefault().get()));
       }
       ancestorsArray.AppendElement(uriClone);
     }
 
     // next ancestor
     treeItem = parentTreeItem;
   }
 
@@ -1241,19 +1240,18 @@ nsCSPContext::PermitsAncestry(nsIDocShel
 
   // Now that we've got the ancestry chain in ancestorsArray, time to check
   // them against any CSP.
   // NOTE:  the ancestors are not allowed to be sent cross origin; this is a
   // restriction not placed on subresource loads.
 
   for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
     if (CSPCONTEXTLOGENABLED()) {
-      nsAutoCString spec;
-      ancestorsArray[a]->GetSpec(spec);
-      CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
+      CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s",
+                     ancestorsArray[a]->GetSpecOrDefault().get()));
     }
     // omit the ancestor URI in violation reports if cross-origin as per spec
     // (it is a violation of the same-origin policy).
     bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
 
 
     bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
                                    ancestorsArray[a],
@@ -1288,21 +1286,19 @@ nsCSPContext::Permits(nsIURI* aURI,
                                 EmptyString(),  // no nonce
                                 false,    // not redirected.
                                 false,    // not a preload.
                                 aSpecific,
                                 true,     // send violation reports
                                 true);    // send blocked URI in violation reports
 
   if (CSPCONTEXTLOGENABLED()) {
-      nsAutoCString spec;
-      aURI->GetSpec(spec);
       CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
-                    spec.get(), aDir,
-                    *outPermits ? "allow" : "deny"));
+                     aURI->GetSpecOrDefault().get(), aDir,
+                     *outPermits ? "allow" : "deny"));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSPContext::ToJSON(nsAString& outCSPinJSON)
 {
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -1298,19 +1298,18 @@ nsCSPParser::parseContentSecurityPolicy(
                                         nsIURI *aSelfURI,
                                         bool aReportOnly,
                                         nsCSPContext* aCSPContext,
                                         bool aDeliveredViaMetaTag)
 {
   if (CSPPARSERLOGENABLED()) {
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, policy: %s",
                  NS_ConvertUTF16toUTF8(aPolicyString).get()));
-    nsAutoCString spec;
-    aSelfURI->GetSpec(spec);
-    CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s", spec.get()));
+    CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s",
+                 aSelfURI->GetSpecOrDefault().get()));
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, reportOnly: %s",
                  (aReportOnly ? "true" : "false")));
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, deliveredViaMetaTag: %s",
                  (aDeliveredViaMetaTag ? "true" : "false")));
   }
 
   NS_ASSERTION(aSelfURI, "Can not parseContentSecurityPolicy without aSelfURI");
 
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -112,20 +112,19 @@ CSPService::ShouldLoad(uint32_t aContent
                        nsIPrincipal *aRequestPrincipal,
                        int16_t *aDecision)
 {
   if (!aContentLocation) {
     return NS_ERROR_FAILURE;
   }
 
   if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
-    nsAutoCString location;
-    aContentLocation->GetSpec(location);
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
-           ("CSPService::ShouldLoad called for %s", location.get()));
+           ("CSPService::ShouldLoad called for %s",
+           aContentLocation->GetSpecOrDefault().get()));
   }
 
   // default decision, CSP can revise it if there's a policy to enforce
   *aDecision = nsIContentPolicy::ACCEPT;
 
   // No need to continue processing if CSP is disabled or if the protocol
   // or type is *not* subject to CSP.
   // Please note, the correct way to opt-out of CSP using a custom
@@ -205,20 +204,19 @@ CSPService::ShouldProcess(uint32_t      
                           nsIPrincipal     *aRequestPrincipal,
                           int16_t          *aDecision)
 {
   if (!aContentLocation) {
     return NS_ERROR_FAILURE;
   }
 
   if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
-    nsAutoCString location;
-    aContentLocation->GetSpec(location);
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
-        ("CSPService::ShouldProcess called for %s", location.get()));
+            ("CSPService::ShouldProcess called for %s",
+            aContentLocation->GetSpecOrDefault().get()));
   }
 
   // ShouldProcess is only relevant to TYPE_OBJECT, so let's convert the
   // internal contentPolicyType to the mapping external one.
   // If it is not TYPE_OBJECT, we can return at this point.
   // Note that we should still pass the internal contentPolicyType
   // (aContentType) to ShouldLoad().
   uint32_t policyType =
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -365,19 +365,18 @@ nsCSPBaseSrc::~nsCSPBaseSrc()
 // ::permits is only called for external load requests, therefore:
 // nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
 // implementation which will never allow the load.
 bool
 nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                       bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
   return false;
 }
 
 // ::allows is only called for inlined loads, therefore:
 // nsCSPSchemeSrc, nsCSPHostSrc fall back
 // to this base class implementation which will never allow the load.
 bool
@@ -401,19 +400,18 @@ nsCSPSchemeSrc::~nsCSPSchemeSrc()
 {
 }
 
 bool
 nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                         bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
   MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
   return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
 }
 
 bool
 nsCSPSchemeSrc::visit(nsCSPSrcVisitor* aVisitor) const
 {
@@ -522,19 +520,18 @@ permitsPort(const nsAString& aEnforcemen
   return false;
 }
 
 bool
 nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                       bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
 
   // we are following the enforcement rules from the spec, see:
   // http://www.w3.org/TR/CSP11/#match-source-expression
 
   // 4.3) scheme matching: Check if the scheme matches.
   if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
     return false;
@@ -747,20 +744,19 @@ nsCSPNonceSrc::~nsCSPNonceSrc()
 {
 }
 
 bool
 nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                        bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPNonceSrc::permits, aUri: %s, aNonce: %s",
-                spec.get(), NS_ConvertUTF16toUTF8(aNonce).get()));
+                 aUri->GetSpecOrDefault().get(),
+                 NS_ConvertUTF16toUTF8(aNonce).get()));
   }
 
   return mNonce.Equals(aNonce);
 }
 
 bool
 nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
 {
@@ -918,19 +914,18 @@ nsCSPDirective::~nsCSPDirective()
   }
 }
 
 bool
 nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                         bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
 
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure)) {
       return true;
     }
   }
   return false;
@@ -1273,20 +1268,19 @@ bool
 nsCSPPolicy::permits(CSPDirective aDir,
                      nsIURI* aUri,
                      const nsAString& aNonce,
                      bool aWasRedirected,
                      bool aSpecific,
                      nsAString& outViolatedDirective) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %d, aSpecific: %s",
-                 spec.get(), aDir, aSpecific ? "true" : "false"));
+                 aUri->GetSpecOrDefault().get(), aDir,
+                 aSpecific ? "true" : "false"));
   }
 
   NS_ASSERTION(aUri, "permits needs an uri to perform the check!");
   outViolatedDirective.Truncate();
 
   nsCSPDirective* defaultDir = nullptr;
 
   // Try to find a relevant directive
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -626,18 +626,18 @@ nsContentSecurityManager::IsOriginPotent
   nsresult rv = uri->GetScheme(scheme);
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
   // Blobs are expected to inherit their principal so we don't expect to have
   // a codebase principal with scheme 'blob' here.  We can't assert that though
   // since someone could mess with a non-blob URI to give it that scheme.
-  NS_WARN_IF_FALSE(!scheme.EqualsLiteral("blob"),
-                   "IsOriginPotentiallyTrustworthy ignoring blob scheme");
+  NS_WARNING_ASSERTION(!scheme.EqualsLiteral("blob"),
+                       "IsOriginPotentiallyTrustworthy ignoring blob scheme");
 
   // According to the specification, the user agent may choose to extend the
   // trust to other, vendor-specific URL schemes. We use this for "resource:",
   // which is technically a substituting protocol handler that is not limited to
   // local resource mapping, but in practice is never mapped remotely as this
   // would violate assumptions a lot of code makes.
   if (scheme.EqualsLiteral("https") ||
       scheme.EqualsLiteral("file") ||
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -226,20 +226,17 @@ LogMixedContentMessage(MixedContentTypes
     messageCategory.AssignLiteral("Mixed Content Message");
     if (aClassification == eMixedDisplay) {
       messageLookupKey.AssignLiteral("LoadingMixedDisplayContent2");
     } else {
       messageLookupKey.AssignLiteral("LoadingMixedActiveContent2");
     }
   }
 
-  nsAutoCString locationSpec;
-  aContentLocation->GetSpec(locationSpec);
-  NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
-
+  NS_ConvertUTF8toUTF16 locationSpecUTF16(aContentLocation->GetSpecOrDefault());
   const char16_t* strings[] = { locationSpecUTF16.get() };
   nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
                                   nsContentUtils::eSECURITY_PROPERTIES,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
 
 
deleted file mode 100644
--- a/dom/simplepush/Push.js
+++ /dev/null
@@ -1,147 +0,0 @@
-/* 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";
-
-// Don't modify this, instead set services.push.debug.
-var gDebuggingEnabled = false;
-
-function debug(s) {
-  if (gDebuggingEnabled)
-    dump("-*- Push.js: " + s + "\n");
-}
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
-Cu.import("resource://gre/modules/AppsUtils.jsm");
-
-const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
-
-/**
- * The Push component runs in the child process and exposes the SimplePush API
- * to the web application. The PushService running in the parent process is the
- * one actually performing all operations.
- */
-function Push() {
-  debug("Push Constructor");
-}
-
-Push.prototype = {
-  __proto__: DOMRequestIpcHelper.prototype,
-
-  contractID: "@mozilla.org/push/PushManager;1",
-
-  classID : PUSH_CID,
-
-  QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
-                                          Ci.nsISupportsWeakReference,
-                                          Ci.nsIObserver]),
-
-  init: function(aWindow) {
-    // Set debug first so that all debugging actually works.
-    // NOTE: We don't add an observer here like in PushService. Flipping the
-    // pref will require a reload of the app/page, which seems acceptable.
-    gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
-    debug("init()");
-
-    let principal = aWindow.document.nodePrincipal;
-    let appsService = Cc["@mozilla.org/AppsService;1"]
-                        .getService(Ci.nsIAppsService);
-
-    this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
-    this._pageURL = principal.URI;
-
-    this.initDOMRequestHelper(aWindow, [
-      "PushService:Register:OK",
-      "PushService:Register:KO",
-      "PushService:Unregister:OK",
-      "PushService:Unregister:KO",
-      "PushService:Registrations:OK",
-      "PushService:Registrations:KO"
-    ]);
-
-    this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
-                   .getService(Ci.nsISyncMessageSender);
-  },
-
-  receiveMessage: function(aMessage) {
-    debug("receiveMessage()");
-    let request = this.getRequest(aMessage.data.requestID);
-    let json = aMessage.data;
-    if (!request) {
-      debug("No request " + json.requestID);
-      return;
-    }
-
-    switch (aMessage.name) {
-      case "PushService:Register:OK":
-        Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
-        break;
-      case "PushService:Register:KO":
-        Services.DOMRequest.fireError(request, json.error);
-        break;
-      case "PushService:Unregister:OK":
-        Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
-        break;
-      case "PushService:Unregister:KO":
-        Services.DOMRequest.fireError(request, json.error);
-        break;
-      case "PushService:Registrations:OK":
-        Services.DOMRequest.fireSuccess(request, json.registrations);
-        break;
-      case "PushService:Registrations:KO":
-        Services.DOMRequest.fireError(request, json.error);
-        break;
-      default:
-        debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
-    }
-  },
-
-  register: function() {
-    debug("register()");
-    let req = this.createRequest();
-    if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
-      // If push socket is disabled by the user, immediately error rather than
-      // timing out.
-      Services.DOMRequest.fireErrorAsync(req, "NetworkError");
-      return req;
-    }
-
-    this._cpmm.sendAsyncMessage("Push:Register", {
-                                  pageURL: this._pageURL.spec,
-                                  manifestURL: this._manifestURL,
-                                  requestID: this.getRequestId(req)
-                                });
-    return req;
-  },
-
-  unregister: function(aPushEndpoint) {
-    debug("unregister(" + aPushEndpoint + ")");
-    let req = this.createRequest();
-    this._cpmm.sendAsyncMessage("Push:Unregister", {
-                                  pageURL: this._pageURL.spec,
-                                  manifestURL: this._manifestURL,
-                                  requestID: this.getRequestId(req),
-                                  pushEndpoint: aPushEndpoint
-                                });
-    return req;
-  },
-
-  registrations: function() {
-    debug("registrations()");
-    let req = this.createRequest();
-    this._cpmm.sendAsyncMessage("Push:Registrations", {
-                                  manifestURL: this._manifestURL,
-                                  requestID: this.getRequestId(req)
-                                });
-    return req;
-  }
-}
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
deleted file mode 100644
--- a/dom/simplepush/Push.manifest
+++ /dev/null
@@ -1,8 +0,0 @@
-# DOM API
-component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
-contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
-
-# Component to initialize PushService on startup.
-component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
-contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
-category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1
deleted file mode 100644
--- a/dom/simplepush/PushService.jsm
+++ /dev/null
@@ -1,1851 +0,0 @@
-/* jshint moz: true, esnext: true */
-/* 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";
-
-// Don't modify this, instead set services.push.debug.
-var gDebuggingEnabled = false;
-
-function debug(s) {
-  if (gDebuggingEnabled)
-    dump("-*- PushService.jsm: " + s + "\n");
-}
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.importGlobalProperties(["indexedDB"]);
-
-XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
-                                   "@mozilla.org/network/dns-service;1",
-                                   "nsIDNSService");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
-                                  "resource://gre/modules/AlarmService.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
-                                   "@mozilla.org/power/powermanagerservice;1",
-                                   "nsIPowerManagerService");
-
-var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
-
-this.EXPORTED_SYMBOLS = ["PushService"];
-
-const prefs = new Preferences("services.push.");
-// Set debug first so that all debugging actually works.
-gDebuggingEnabled = prefs.get("debug");
-
-const kPUSHDB_DB_NAME = "push";
-const kPUSHDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
-const kPUSHDB_STORE_NAME = "push";
-
-const kUDP_WAKEUP_WS_STATUS_CODE = 4774;  // WebSocket Close status code sent
-                                          // by server to signal that it can
-                                          // wake client up using UDP.
-
-const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
-                                 "Push:Registrations"];
-
-// This is a singleton
-this.PushDB = function PushDB() {
-  debug("PushDB()");
-
-  // set the indexeddb database
-  this.initDBHelper(kPUSHDB_DB_NAME, kPUSHDB_DB_VERSION,
-                    [kPUSHDB_STORE_NAME]);
-};
-
-this.PushDB.prototype = {
-  __proto__: IndexedDBHelper.prototype,
-
-  upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
-    debug("PushDB.upgradeSchema()");
-
-    let objectStore = aDb.createObjectStore(kPUSHDB_STORE_NAME,
-                                            { keyPath: "channelID" });
-
-    // index to fetch records based on endpoints. used by unregister
-    objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
-
-    // index to fetch records per manifest, so we can identify endpoints
-    // associated with an app. Since an app can have multiple endpoints
-    // uniqueness cannot be enforced
-    objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
-  },
-
-  /*
-   * @param aChannelRecord
-   *        The record to be added.
-   * @param aSuccessCb
-   *        Callback function to invoke with result ID.
-   * @param aErrorCb [optional]
-   *        Callback function to invoke when there was an error.
-   */
-  put: function(aChannelRecord, aSuccessCb, aErrorCb) {
-    debug("put()");
-
-    this.newTxn(
-      "readwrite",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        debug("Going to put " + aChannelRecord.channelID);
-        aStore.put(aChannelRecord).onsuccess = function setTxnResult(aEvent) {
-          debug("Request successful. Updated record ID: " +
-                aEvent.target.result);
-        };
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  /*
-   * @param aChannelID
-   *        The ID of record to be deleted.
-   * @param aSuccessCb
-   *        Callback function to invoke with result.
-   * @param aErrorCb [optional]
-   *        Callback function to invoke when there was an error.
-   */
-  delete: function(aChannelID, aSuccessCb, aErrorCb) {
-    debug("delete()");
-
-    this.newTxn(
-      "readwrite",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        debug("Going to delete " + aChannelID);
-        aStore.delete(aChannelID);
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  getByPushEndpoint: function(aPushEndpoint, aSuccessCb, aErrorCb) {
-    debug("getByPushEndpoint()");
-
-    this.newTxn(
-      "readonly",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        aTxn.result = undefined;
-
-        let index = aStore.index("pushEndpoint");
-        index.get(aPushEndpoint).onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
-          debug("Fetch successful " + aEvent.target.result);
-        }
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  getByChannelID: function(aChannelID, aSuccessCb, aErrorCb) {
-    debug("getByChannelID()");
-
-    this.newTxn(
-      "readonly",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        aTxn.result = undefined;
-
-        aStore.get(aChannelID).onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
-          debug("Fetch successful " + aEvent.target.result);
-        }
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  getAllByManifestURL: function(aManifestURL, aSuccessCb, aErrorCb) {
-    debug("getAllByManifestURL()");
-    if (!aManifestURL) {
-      if (typeof aErrorCb == "function") {
-        aErrorCb("PushDB.getAllByManifestURL: Got undefined aManifestURL");
-      }
-      return;
-    }
-
-    let self = this;
-    this.newTxn(
-      "readonly",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        let index = aStore.index("manifestURL");
-        let range = IDBKeyRange.only(aManifestURL);
-        aTxn.result = [];
-        index.openCursor(range).onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            debug(cursor.value.manifestURL + " " + cursor.value.channelID);
-            aTxn.result.push(cursor.value);
-            cursor.continue();
-          }
-        }
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  getAllChannelIDs: function(aSuccessCb, aErrorCb) {
-    debug("getAllChannelIDs()");
-
-    this.newTxn(
-      "readonly",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        aStore.mozGetAll().onsuccess = function(event) {
-          aTxn.result = event.target.result;
-        }
-      },
-      aSuccessCb,
-      aErrorCb
-    );
-  },
-
-  drop: function(aSuccessCb, aErrorCb) {
-    debug("drop()");
-    this.newTxn(
-      "readwrite",
-      kPUSHDB_STORE_NAME,
-      function txnCb(aTxn, aStore) {
-        aStore.clear();
-      },
-      aSuccessCb(),
-      aErrorCb()
-    );
-  }
-};
-
-/**
- * A proxy between the PushService and the WebSocket. The listener is used so
- * that the PushService can silence messages from the WebSocket by setting
- * PushWebSocketListener._pushService to null. This is required because
- * a WebSocket can continue to send messages or errors after it has been
- * closed but the PushService may not be interested in these. It's easier to
- * stop listening than to have checks at specific points.
- */
-this.PushWebSocketListener = function(pushService) {
-  this._pushService = pushService;
-}
-
-this.PushWebSocketListener.prototype = {
-  onStart: function(context) {
-    if (!this._pushService)
-        return;
-    this._pushService._wsOnStart(context);
-  },
-
-  onStop: function(context, statusCode) {
-    if (!this._pushService)
-        return;
-    this._pushService._wsOnStop(context, statusCode);
-  },
-
-  onAcknowledge: function(context, size) {
-    // EMPTY
-  },
-
-  onBinaryMessageAvailable: function(context, message) {
-    // EMPTY
-  },
-
-  onMessageAvailable: function(context, message) {
-    if (!this._pushService)
-        return;
-    this._pushService._wsOnMessageAvailable(context, message);
-  },
-
-  onServerClose: function(context, aStatusCode, aReason) {
-    if (!this._pushService)
-        return;
-    this._pushService._wsOnServerClose(context, aStatusCode, aReason);
-  }
-}
-
-// websocket states
-// websocket is off
-const STATE_SHUT_DOWN = 0;
-// Websocket has been opened on client side, waiting for successful open.
-// (_wsOnStart)
-const STATE_WAITING_FOR_WS_START = 1;
-// Websocket opened, hello sent, waiting for server reply (_handleHelloReply).
-const STATE_WAITING_FOR_HELLO = 2;
-// Websocket operational, handshake completed, begin protocol messaging.
-const STATE_READY = 3;
-
-/**
- * The implementation of the SimplePush system. This runs in the B2G parent
- * process and is started on boot. It uses WebSockets to communicate with the
- * server and PushDB (IndexedDB) for persistence.
- */
-this.PushService = {
-  observe: function observe(aSubject, aTopic, aData) {
-    switch (aTopic) {
-      /*
-       * We need to call uninit() on shutdown to clean up things that modules aren't very good
-       * at automatically cleaning up, so we don't get shutdown leaks on browser shutdown.
-       */
-      case "xpcom-shutdown":
-        this.uninit();
-      case "network-active-changed":         /* On B2G. */
-      case "network:offline-status-changed": /* On desktop. */
-        // In case of network-active-changed, always disconnect existing
-        // connections. In case of offline-status changing from offline to
-        // online, it is likely that these statements will be no-ops.
-        if (this._udpServer) {
-          this._udpServer.close();
-          // Set to null since this is checked in _listenForUDPWakeup()
-          this._udpServer = null;
-        }
-
-        this._shutdownWS();
-
-        // Try to connect if network-active-changed or the offline-status
-        // changed to online.
-        if (aTopic === "network-active-changed" || aData === "online") {
-          this._startListeningIfChannelsPresent();
-        }
-        break;
-      case "nsPref:changed":
-        if (aData == "services.push.serverURL") {
-          debug("services.push.serverURL changed! websocket. new value " +
-                prefs.get("serverURL"));
-          this._shutdownWS();
-        } else if (aData == "services.push.connection.enabled") {
-          if (prefs.get("connection.enabled")) {
-            this._startListeningIfChannelsPresent();
-          } else {
-            this._shutdownWS();
-          }
-        } else if (aData == "services.push.debug") {
-          gDebuggingEnabled = prefs.get("debug");
-        }
-        break;
-      case "timer-callback":
-        if (aSubject == this._requestTimeoutTimer) {
-          if (Object.keys(this._pendingRequests).length == 0) {
-            this._requestTimeoutTimer.cancel();
-          }
-
-          // Set to true if at least one request timed out.
-          let requestTimedOut = false;
-          for (let channelID in this._pendingRequests) {
-            let duration = Date.now() - this._pendingRequests[channelID].ctime;
-
-            // If any of the registration requests time out, all the ones after it
-            // also made to fail, since we are going to be disconnecting the socket.
-            if (requestTimedOut || duration > this._requestTimeout) {
-              debug("Request timeout: Removing " + channelID);
-              requestTimedOut = true;
-              this._pendingRequests[channelID]
-                .deferred.reject({status: 0, error: "TimeoutError"});
-
-              delete this._pendingRequests[channelID];
-              for (let i = this._requestQueue.length - 1; i >= 0; --i)
-                if (this._requestQueue[i][1].channelID == channelID)
-                  this._requestQueue.splice(i, 1);
-            }
-          }
-
-          // The most likely reason for a registration request timing out is
-          // that the socket has disconnected. Best to reconnect.
-          if (requestTimedOut) {
-            this._shutdownWS();
-            this._reconnectAfterBackoff();
-          }
-        }
-        break;
-      case "webapps-clear-data":
-        debug("webapps-clear-data");
-
-        let data = aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
-        if (!data) {
-          debug("webapps-clear-data: Failed to get information about application");
-          return;
-        }
-
-        // Only remove push registrations for apps.
-        if (data.browserOnly) {
-          return;
-        }
-
-        let appsService = Cc["@mozilla.org/AppsService;1"]
-                            .getService(Ci.nsIAppsService);
-        let manifestURL = appsService.getManifestURLByLocalId(data.appId);
-        if (!manifestURL) {
-          debug("webapps-clear-data: No manifest URL found for " + data.appId);
-          return;
-        }
-
-        this._db.getAllByManifestURL(manifestURL, function(records) {
-          debug("Got " + records.length);
-          for (let i = 0; i < records.length; i++) {
-            this._db.delete(records[i].channelID, null, function() {
-              debug("webapps-clear-data: " + manifestURL +
-                    " Could not delete entry " + records[i].channelID);
-            });
-            // courtesy, but don't establish a connection
-            // just for it
-            if (this._ws) {
-              debug("Had a connection, so telling the server");
-              this._send("unregister", {channelID: records[i].channelID});
-            }
-          }
-        }.bind(this), function() {
-          debug("webapps-clear-data: Error in getAllByManifestURL(" + manifestURL + ")");
-        });
-
-        break;
-    }
-  },
-
-  get _UAID() {
-    return prefs.get("userAgentID");
-  },
-
-  set _UAID(newID) {
-    if (typeof(newID) !== "string") {
-      debug("Got invalid, non-string UAID " + newID +
-            ". Not updating userAgentID");
-      return;
-    }
-    debug("New _UAID: " + newID);
-    prefs.set("userAgentID", newID);
-  },
-
-  // keeps requests buffered if the websocket disconnects or is not connected
-  _requestQueue: [],
-  _ws: null,
-  _pendingRequests: {},
-  _currentState: STATE_SHUT_DOWN,
-  _requestTimeout: 0,
-  _requestTimeoutTimer: null,
-  _retryFailCount: 0,
-
-  /**
-   * According to the WS spec, servers should immediately close the underlying
-   * TCP connection after they close a WebSocket. This causes wsOnStop to be
-   * called with error NS_BASE_STREAM_CLOSED. Since the client has to keep the
-   * WebSocket up, it should try to reconnect. But if the server closes the
-   * WebSocket because it will wake up the client via UDP, then the client
-   * shouldn't re-establish the connection. If the server says that it will
-   * wake up the client over UDP, this is set to true in wsOnServerClose. It is
-   * checked in wsOnStop.
-   */
-  _willBeWokenUpByUDP: false,
-
-  /**
-   * Holds if the adaptive ping is enabled. This is read on init().
-   * If adaptive ping is enabled, a new ping is calculed each time we receive
-   * a pong message, trying to maximize network resources while minimizing
-   * cellular signalling storms.
-   */
-  _adaptiveEnabled: false,
-
-  /**
-   * This saves a flag about if we need to recalculate a new ping, based on:
-   *   1) the gap between the maximum working ping and the first ping that
-   *      gives an error (timeout) OR
-   *   2) we have reached the pref of the maximum value we allow for a ping
-   *      (services.push.adaptive.upperLimit)
-   */
-  _recalculatePing: true,
-
-  /**
-   * This map holds a (pingInterval, triedTimes) of each pingInterval tried.
-   * It is used to check if the pingInterval has been tested enough to know that
-   * is incorrect and is above the limit the network allow us to keep the
-   * connection open.
-   */
-  _pingIntervalRetryTimes: {},
-
-  /**
-   * Holds the lastGoodPingInterval for our current connection.
-   */
-  _lastGoodPingInterval: 0,
-
-  /**
-   * Maximum ping interval that we can reach.
-   */
-  _upperLimit: 0,
-
-  /**
-   * Sends a message to the Push Server through an open websocket.
-   * typeof(msg) shall be an object
-   */
-  _wsSendMessage: function(msg) {
-    if (!this._ws) {
-      debug("No WebSocket initialized. Cannot send a message.");
-      return;
-    }
-    msg = JSON.stringify(msg);
-    debug("Sending message: " + msg);
-    this._ws.sendMsg(msg);
-  },
-
-  init: function() {
-    debug("init()");
-    if (!prefs.get("enabled"))
-        return null;
-
-    this._db = new PushDB();
-
-    let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
-                 .getService(Ci.nsIMessageBroadcaster);
-
-    kCHILD_PROCESS_MESSAGES.forEach(function addMessage(msgName) {
-        ppmm.addMessageListener(msgName, this);
-    }.bind(this));
-
-    this._alarmID = null;
-
-    this._requestTimeout = prefs.get("requestTimeout");
-    this._adaptiveEnabled = prefs.get('adaptive.enabled');
-    this._upperLimit = prefs.get('adaptive.upperLimit');
-
-    this._startListeningIfChannelsPresent();
-
-    Services.obs.addObserver(this, "xpcom-shutdown", false);
-    Services.obs.addObserver(this, "webapps-clear-data", false);
-
-    // On B2G the NetworkManager interface fires a network-active-changed
-    // event.
-    //
-    // The "active network" is based on priority - i.e. Wi-Fi has higher
-    // priority than data. The PushService should just use the preferred
-    // network, and not care about all interface changes.
-    // network-active-changed is not fired when the network goes offline, but
-    // socket connections time out. The check for Services.io.offline in
-    // _beginWSSetup() prevents unnecessary retries.  When the network comes
-    // back online, network-active-changed is fired.
-    //
-    // On non-B2G platforms, the offline-status-changed event is used to know
-    // when to (dis)connect. It may not fire if the underlying OS changes
-    // networks; in such a case we rely on timeout.
-    //
-    // On B2G both events fire, one after the other, when the network goes
-    // online, so we explicitly check for the presence of NetworkManager and
-    // don't add an observer for offline-status-changed on B2G.
-    Services.obs.addObserver(this, this._getNetworkStateChangeEventName(), false);
-
-    // This is only used for testing. Different tests require connecting to
-    // slightly different URLs.
-    prefs.observe("serverURL", this);
-    // Used to monitor if the user wishes to disable Push.
-    prefs.observe("connection.enabled", this);
-    // Debugging
-    prefs.observe("debug", this);
-
-    this._started = true;
-  },
-
-  _shutdownWS: function() {
-    debug("shutdownWS()");
-    this._currentState = STATE_SHUT_DOWN;
-    this._willBeWokenUpByUDP = false;
-
-    if (this._wsListener)
-      this._wsListener._pushService = null;
-    try {
-        this._ws.close(0, null);
-    } catch (e) {}
-    this._ws = null;
-
-    this._waitingForPong = false;
-    this._stopAlarm();
-  },
-
-  uninit: function() {
-    if (!this._started)
-      return;
-
-    debug("uninit()");
-
-    prefs.ignore("debug", this);
-    prefs.ignore("connection.enabled", this);
-    prefs.ignore("serverURL", this);
-    Services.obs.removeObserver(this, this._getNetworkStateChangeEventName());
-    Services.obs.removeObserver(this, "webapps-clear-data", false);
-    Services.obs.removeObserver(this, "xpcom-shutdown", false);
-
-    if (this._db) {
-      this._db.close();
-      this._db = null;
-    }
-
-    if (this._udpServer) {
-      this._udpServer.close();
-      this._udpServer = null;
-    }
-
-    // All pending requests (ideally none) are dropped at this point. We
-    // shouldn't have any applications performing registration/unregistration
-    // or receiving notifications.
-    this._shutdownWS();
-
-    // At this point, profile-change-net-teardown has already fired, so the
-    // WebSocket has been closed with NS_ERROR_ABORT (if it was up) and will
-    // try to reconnect. Stop the timer.
-    this._stopAlarm();
-
-    if (this._requestTimeoutTimer) {
-      this._requestTimeoutTimer.cancel();
-    }
-
-    debug("shutdown complete!");
-  },
-
-  /**
-   * How retries work:  The goal is to ensure websocket is always up on
-   * networks not supporting UDP. So the websocket should only be shutdown if
-   * onServerClose indicates UDP wakeup.  If WS is closed due to socket error,
-   * _reconnectAfterBackoff() is called.  The retry alarm is started and when
-   * it times out, beginWSSetup() is called again.
-   *
-   * On a successful connection, the alarm is cancelled in
-   * wsOnMessageAvailable() when the ping alarm is started.
-   *
-   * If we are in the middle of a timeout (i.e. waiting), but
-   * a register/unregister is called, we don't want to wait around anymore.
-   * _sendRequest will automatically call beginWSSetup(), which will cancel the
-   * timer. In addition since the state will have changed, even if a pending
-   * timer event comes in (because the timer fired the event before it was
-   * cancelled), so the connection won't be reset.
-   */
-  _reconnectAfterBackoff: function() {
-    debug("reconnectAfterBackoff()");
-    //Calculate new ping interval
-    this._calculateAdaptivePing(true /* wsWentDown */);
-
-    // Calculate new timeout, but cap it to pingInterval.
-    let retryTimeout = prefs.get("retryBaseInterval") *
-                       Math.pow(2, this._retryFailCount);
-    retryTimeout = Math.min(retryTimeout, prefs.get("pingInterval"));
-
-    this._retryFailCount++;
-
-    debug("Retry in " + retryTimeout + " Try number " + this._retryFailCount);
-    this._setAlarm(retryTimeout);
-  },
-
-  /**
-   * We need to calculate a new ping based on:
-   *  1) Latest good ping
-   *  2) A safe gap between 1) and the calculated new ping (which is
-   *  by default, 1 minute)
-   *
-   * This is for 3G networks, whose connections keepalives differ broadly,
-   * for example:
-   *  1) Movistar Spain: 29 minutes
-   *  2) VIVO Brazil: 5 minutes
-   *  3) Movistar Colombia: XXX minutes
-   *
-   * So a fixed ping is not good for us for two reasons:
-   *  1) We might lose the connection, so we need to reconnect again (wasting
-   *  resources)
-   *  2) We use a lot of network signaling just for pinging.
-   *
-   * This algorithm tries to search the best value between a disconnection and a
-   * valid ping, to ensure better battery life and network resources usage.
-   *
-   * The value is saved in services.push.pingInterval
-   * @param wsWentDown [Boolean] if the WebSocket was closed or it is still alive
-   *
-   */
-  _calculateAdaptivePing: function(wsWentDown) {
-    debug('_calculateAdaptivePing()');
-    if (!this._adaptiveEnabled) {
-      debug('Adaptive ping is disabled');
-      return;
-    }
-
-    if (this._retryFailCount > 0) {
-      debug('Push has failed to connect to the Push Server ' +
-        this._retryFailCount + ' times. ' +
-        'Do not calculate a new pingInterval now');
-      return;
-    }
-
-    if (!this._recalculatePing && !wsWentDown) {
-      debug('We do not need to recalculate the ping now, based on previous data');
-      return;
-    }
-
-    // Save actual state of the network
-    let ns = this._getNetworkInformation();
-
-    if (ns.ip) {
-      // mobile
-      debug('mobile');
-      let oldNetwork = prefs.get('adaptive.mobile');
-      let newNetwork = 'mobile-' + ns.mcc + '-' + ns.mnc;
-
-      // Mobile networks differ, reset all intervals and pings
-      if (oldNetwork !== newNetwork) {
-        // Network differ, reset all values
-        debug('Mobile networks differ. Old network is ' + oldNetwork +
-              ' and new is ' + newNetwork);
-        prefs.set('adaptive.mobile', newNetwork);
-        //We reset the upper bound member
-        this._recalculatePing = true;
-        this._pingIntervalRetryTimes = {};
-
-        // Put default values
-        let defaultPing = prefs.get('pingInterval.default');
-        prefs.set('pingInterval', defaultPing);
-        this._lastGoodPingInterval = defaultPing;
-
-      } else {
-        // Mobile network is the same, let's just update things
-        prefs.set('pingInterval', prefs.get('pingInterval.mobile'));
-        this._lastGoodPingInterval = prefs.get('adaptive.lastGoodPingInterval.mobile');
-      }
-
-    } else {
-      // wifi
-      debug('wifi');
-      prefs.set('pingInterval', prefs.get('pingInterval.wifi'));
-      this._lastGoodPingInterval = prefs.get('adaptive.lastGoodPingInterval.wifi');
-    }
-
-    let nextPingInterval;
-    let lastTriedPingInterval = prefs.get('pingInterval');
-
-    if (wsWentDown) {
-      debug('The WebSocket was disconnected, calculating next ping');
-
-      // If we have not tried this pingInterval yet, initialize
-      this._pingIntervalRetryTimes[lastTriedPingInterval] =
-           (this._pingIntervalRetryTimes[lastTriedPingInterval] || 0) + 1;
-
-       // Try the pingInterval at least 3 times, just to be sure that the
-       // calculated interval is not valid.
-       if (this._pingIntervalRetryTimes[lastTriedPingInterval] < 2) {
-         debug('pingInterval= ' + lastTriedPingInterval + ' tried only ' +
-           this._pingIntervalRetryTimes[lastTriedPingInterval] + ' times');
-         return;
-       }
-
-       // Latest ping was invalid, we need to lower the limit to limit / 2
-       nextPingInterval = Math.floor(lastTriedPingInterval / 2);
-
-      // If the new ping interval is close to the last good one, we are near
-      // optimum, so stop calculating.
-      if (nextPingInterval - this._lastGoodPingInterval < prefs.get('adaptive.gap')) {
-        debug('We have reached the gap, we have finished the calculation');
-        debug('nextPingInterval=' + nextPingInterval);
-        debug('lastGoodPing=' + this._lastGoodPingInterval);
-        nextPingInterval = this._lastGoodPingInterval;
-        this._recalculatePing = false;
-      } else {
-        debug('We need to calculate next time');
-        this._recalculatePing = true;
-      }
-
-    } else {
-      debug('The WebSocket is still up');
-      this._lastGoodPingInterval = lastTriedPingInterval;
-      nextPingInterval = Math.floor(lastTriedPingInterval * 1.5);
-    }
-
-    // Check if we have reached the upper limit
-    if (this._upperLimit < nextPingInterval) {
-      debug('Next ping will be bigger than the configured upper limit, capping interval');
-      this._recalculatePing = false;
-      this._lastGoodPingInterval = lastTriedPingInterval;
-      nextPingInterval = lastTriedPingInterval;
-    }
-
-    debug('Setting the pingInterval to ' + nextPingInterval);
-    prefs.set('pingInterval', nextPingInterval);
-
-    //Save values for our current network
-    if (ns.ip) {
-      prefs.set('pingInterval.mobile', nextPingInterval);
-      prefs.set('adaptive.lastGoodPingInterval.mobile', this._lastGoodPingInterval);
-    } else {
-      prefs.set('pingInterval.wifi', nextPingInterval);
-      prefs.set('adaptive.lastGoodPingInterval.wifi', this._lastGoodPingInterval);