merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 24 May 2016 14:52:23 +0200
changeset 298652 829d3be6ba64
parent 298268 f6e1ee9ac46c (current diff)
parent 298651 df5daa1095f2 (diff)
child 298653 3b664841d774
child 298679 f074838712a0
child 298777 f02ee7dd94e0
push id30281
push usercbook@mozilla.com
push dateTue, 24 May 2016 12:54:02 +0000
treeherdermozilla-central@829d3be6ba64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.0a1
first release with
nightly linux32
829d3be6ba64 / 49.0a1 / 20160524073714 / files
nightly linux64
829d3be6ba64 / 49.0a1 / 20160524073714 / files
nightly mac
829d3be6ba64 / 49.0a1 / 20160524073714 / files
nightly win32
829d3be6ba64 / 49.0a1 / 20160524073714 / files
nightly win64
829d3be6ba64 / 49.0a1 / 20160524073714 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/components/feeds/FeedWriter.js
browser/components/places/PlacesUIUtils.jsm
devtools/client/shared/inplace-editor.js
dom/html/HTMLMediaElement.h
dom/html/HTMLPropertiesCollection.cpp
dom/html/HTMLPropertiesCollection.h
dom/media/tests/mochitest/test_peerConnection_addTrack.html
dom/presentation/interfaces/nsITCPPresentationServer.idl
dom/presentation/provider/TCPPresentationServer.js
dom/presentation/tests/mochitest/file_presentation_1ua_receiver_oop.html
dom/presentation/tests/mochitest/file_presentation_non_receiver.html
dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html
dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe_oop.html
dom/presentation/tests/mochitest/file_presentation_non_receiver_oop.html
dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe.html
dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe_oop.html
dom/presentation/tests/mochitest/file_presentation_receiver_oop.html
dom/webidl/HTMLPropertiesCollection.webidl
gfx/layers/apz/src/FlingOverScrollerAnimation.cpp
gfx/layers/apz/src/FlingOverScrollerAnimation.h
ipc/app/sha256.c
ipc/app/sha256.h
js/src/tests/ecma_3/Date/15.9.3.2-1.js
js/src/tests/js1_5/Date/regress-301738-02.js
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-connect-src-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-eval-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-function-function-blocked.sub.html.ini
testing/web-platform/meta/web-animations/timing-model/animations/set-the-animation-start-time.html.ini
testing/web-platform/tests/html/dom/elements-microdata.js
toolkit/components/places/FaviconHelpers.cpp
toolkit/content/process-content.js
toolkit/content/tests/widgets/chrome.ini
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -28,17 +28,16 @@ scopes:
 # - pushlog_id:     id in the pushlog table of the repository
 #
 # and functions:
 # - as_slugid:      convert a label into a slugId
 # - from_now:       generate a timestamp at a fixed offset from now
 
 tasks:
   - taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
-    reruns: 3
     task:
       created: '{{now}}'
       deadline: '{{#from_now}}1 day{{/from_now}}'
       expires: '{{#from_now}}14 day{{/from_now}}'
       metadata:
         owner: mozilla-taskcluster-maintenance@mozilla.com
         source: {{{source}}}
         name: "Gecko Decision Task"
--- 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 1273625 - Update win32 rustc target to i686
+Bug 1271829 - Compile nss with SSE2 optimizations
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -185,26 +185,17 @@ Accessible::Description(nsString& aDescr
   if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT))
     return;
 
   nsTextEquivUtils::
     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
                            aDescription);
 
   if (aDescription.IsEmpty()) {
-    bool isXUL = mContent->IsXULElement();
-    if (isXUL) {
-      // Try XUL <description control="[id]">description text</description>
-      XULDescriptionIterator iter(Document(), mContent);
-      Accessible* descr = nullptr;
-      while ((descr = iter.Next())) {
-        nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
-                                                     &aDescription);
-      }
-    }
+    NativeDescription(aDescription);
 
     if (aDescription.IsEmpty()) {
       // Keep the Name() method logic.
       if (mContent->IsHTMLElement()) {
         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription);
       } else if (mContent->IsXULElement()) {
         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription);
       } else if (mContent->IsSVGElement()) {
@@ -1965,16 +1956,32 @@ Accessible::NativeName(nsString& aName)
     }
   }
 
   return eNameOK;
 }
 
 // Accessible protected
 void
+Accessible::NativeDescription(nsString& aDescription)
+{
+  bool isXUL = mContent->IsXULElement();
+  if (isXUL) {
+    // Try XUL <description control="[id]">description text</description>
+    XULDescriptionIterator iter(Document(), mContent);
+    Accessible* descr = nullptr;
+    while ((descr = iter.Next())) {
+      nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
+                                                   &aDescription);
+    }
+  }
+}
+
+// Accessible protected
+void
 Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
 {
   MOZ_ASSERT(aParent, "This method isn't used to set null parent");
   MOZ_ASSERT(!mParent, "The child was expected to be moved");
 
 #ifdef A11Y_LOG
   if (mParent) {
     logging::TreeInfo("BindToParent: stealing accessible", 0,
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -951,16 +951,22 @@ protected:
 
   /**
    * Return the accessible name provided by native markup. It doesn't take
    * into account ARIA markup used to specify the name.
    */
   virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName);
 
   /**
+   * Return the accessible description provided by native markup. It doesn't take
+   * into account ARIA markup used to specify the description.
+   */
+  virtual void NativeDescription(nsString& aDescription);
+
+  /**
    * Return object attributes provided by native markup. It doesn't take into
    * account ARIA.
    */
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes();
 
   //////////////////////////////////////////////////////////////////////////////
   // Initializing, cache and tree traverse methods
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -409,17 +409,17 @@
 @RESPATH@/components/nsSidebar.js
 @RESPATH@/components/nsAsyncShutdown.manifest
 @RESPATH@/components/nsAsyncShutdown.js
 @RESPATH@/components/htmlMenuBuilder.js
 @RESPATH@/components/htmlMenuBuilder.manifest
 @RESPATH@/components/PresentationDeviceInfoManager.manifest
 @RESPATH@/components/PresentationDeviceInfoManager.js
 @RESPATH@/components/BuiltinProviders.manifest
-@RESPATH@/components/TCPPresentationServer.js
+@RESPATH@/components/PresentationControlService.js
 @RESPATH@/components/PresentationDataChannelSessionTransport.js
 @RESPATH@/components/PresentationDataChannelSessionTransport.manifest
 
 #ifdef MOZ_SECUREELEMENT
 @RESPATH@/components/ACEService.js
 @RESPATH@/components/ACEService.manifest
 @RESPATH@/components/GPAccessRulesManager.js
 @RESPATH@/components/GPAccessRulesManager.manifest
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1307,17 +1307,17 @@ pref("ui.key.menuAccessKeyFocuses", true
 #endif
 
 // Encrypted media extensions.
 pref("media.eme.enabled", true);
 pref("media.eme.apiVisible", true);
 
 // Decode using Gecko Media Plugins in <video>, if a system decoder is not
 // availble and the preferred GMP is available.
-pref("media.gmp.decoder.enabled", true);
+pref("media.gmp.decoder.enabled", false);
 
 // If decoding-via-GMP is turned on for <video>, use Adobe's GMP for decoding,
 // if it's available. Note: We won't fallback to another GMP if Adobe's is not
 // installed.
 pref("media.gmp.decoder.aac", 2);
 pref("media.gmp.decoder.h264", 2);
 
 // Whether we should run a test-pattern through EME GMPs before assuming they'll
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1102,16 +1102,22 @@ var gBrowserInit = {
         // remote.
         try {
           if (tabToOpen.linkedBrowser.isRemoteBrowser) {
             if (!gMultiProcessBrowser) {
               throw new Error("Cannot drag a remote browser into a window " +
                               "without the remote tabs load context.");
             }
 
+            // We must set usercontextid before updateBrowserRemoteness()
+            // so that the newly created remote tab child has correct usercontextid
+            if (tabToOpen.hasAttribute("usercontextid")) {
+              let usercontextid = tabToOpen.getAttribute("usercontextid");
+              gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
+            }
             gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, true);
           }
           gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
         } catch(e) {
           Cu.reportError(e);
         }
       }
       // window.arguments[2]: referrer (nsIURI | string)
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -869,31 +869,31 @@ var RefreshBlocker = {
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsISupports]),
 };
 
 RefreshBlocker.init();
 
 var UserContextIdNotifier = {
   init() {
-    addEventListener("DOMContentLoaded", this);
+    addEventListener("DOMWindowCreated", this);
   },
 
   uninit() {
-    removeEventListener("DOMContentLoaded", this);
+    removeEventListener("DOMWindowCreated", this);
   },
 
   handleEvent(aEvent) {
-    // When the first content is loaded, we want to inform the tabbrowser about
+    // When the window is created, we want to inform the tabbrowser about
     // the userContextId in use in order to update the UI correctly.
     // Just because we cannot change the userContextId from an active docShell,
     // we don't need to check DOMContentLoaded again.
     this.uninit();
     let userContextId = content.document.nodePrincipal.originAttributes.userContextId;
-    sendAsyncMessage("Browser:FirstContentLoaded", { userContextId });
+    sendAsyncMessage("Browser:WindowCreated", { userContextId });
   }
 };
 
 UserContextIdNotifier.init();
 
 ExtensionContent.init(this);
 addEventListener("unload", () => {
   ExtensionContent.uninit(this);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3053,17 +3053,22 @@
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <parameter name="aSelectTab"/>
         <body>
         <![CDATA[
           // Swap the dropped tab with a new one we create and then close
           // it in the other window (making it seem to have moved between
           // windows).
-          let newTab = this.addTab("about:blank", { eventDetail: { adoptedTab: aTab } });
+          let params = { eventDetail: { adoptedTab: aTab } };
+          if (aTab.hasAttribute("usercontextid")) {
+            // new tab must have the same usercontextid as the old one
+            params.userContextId = aTab.getAttribute("usercontextid");
+          }
+          let newTab = this.addTab("about:blank", params);
           let newBrowser = this.getBrowserForTab(newTab);
           let newURL = aTab.linkedBrowser.currentURI.spec;
 
           // If we're an e10s browser window, an exception will be thrown
           // if we attempt to drag a non-remote browser in, so we need to
           // ensure that the remoteness of the newly created browser is
           // appropriate for the URL of the tab being dragged in.
           this.updateBrowserRemotenessByURL(newBrowser, newURL);
@@ -4312,22 +4317,23 @@
               let tab = this.getTabForBrowser(browser);
               if (!tab)
                 return undefined;
 
               this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser);
               browser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned })
               break;
             }
-            case "Browser:FirstContentLoaded": {
+            case "Browser:WindowCreated": {
               let tab = this.getTabForBrowser(browser);
               if (tab && data.userContextId) {
                 tab.setUserContextId(data.userContextId);
               }
 
+              updateUserContextUIIndicator(browser);
               break;
             }
             case "Findbar:Keypress": {
               let tab = this.getTabForBrowser(browser);
               // If the find bar for this tab is not yet alive, only initialize
               // it if there's a possibility FindAsYouType will be used.
               // There's no point in doing it for most random keypresses.
               if (!this.isFindBarInitialized(tab) &&
@@ -4466,17 +4472,17 @@
             this.mPanelContainer.classList.add("tabbrowser-tabpanels");
           } else {
             this._outerWindowIDBrowserMap.set(this.mCurrentBrowser.outerWindowID,
                                               this.mCurrentBrowser);
           }
           messageManager.addMessageListener("DOMWebNotificationClicked", this);
           messageManager.addMessageListener("DOMServiceWorkerFocusClient", this);
           messageManager.addMessageListener("RefreshBlocker:Blocked", this);
-          messageManager.addMessageListener("Browser:FirstContentLoaded", this);
+          messageManager.addMessageListener("Browser:WindowCreated", this);
 
           // To correctly handle keypresses for potential FindAsYouType, while
           // the tab's find bar is not yet initialized.
           this._findAsYouType = Services.prefs.getBoolPref("accessibility.typeaheadfind");
           Services.prefs.addObserver("accessibility.typeaheadfind", this, false);
           messageManager.addMessageListener("Findbar:Keypress", this);
         ]]>
       </constructor>
--- a/browser/components/contextualidentity/test/browser/browser_aboutURLs.js
+++ b/browser/components/contextualidentity/test/browser/browser_aboutURLs.js
@@ -1,8 +1,14 @@
+"use strict";
+
+// For some about: URLs, they will take more time to load and cause timeout.
+// See Bug 1270998.
+requestLongerTimeout(2);
+
 add_task(function* () {
   let aboutURLs = [];
 
   // List of about: URLs that will initiate network requests.
   let networkURLs = [
     "credits",
     "telemetry" // about:telemetry will fetch Telemetry asynchrounously and takes
                 // longer, we skip this for now.
--- a/browser/components/migration/tests/marionette/manifest.ini
+++ b/browser/components/migration/tests/marionette/manifest.ini
@@ -1,8 +1,5 @@
 [DEFAULT]
-qemu = false
-b2g = false
-browser = true
-skip = false
+run-if = buildapp == 'browser'
 
 [test_refresh_firefox.py]
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -375,16 +375,21 @@ BrowserGlue.prototype = {
         break;
       case "handle-xul-text-link":
         let linkHandled = subject.QueryInterface(Ci.nsISupportsPRBool);
         if (!linkHandled.data) {
           let win = RecentWindow.getMostRecentBrowserWindow();
           if (win) {
             data = JSON.parse(data);
             let where = win.whereToOpenLink(data);
+            // Preserve legacy behavior of non-modifier left-clicks
+            // opening in a new selected tab.
+            if (where == "current") {
+              where = "tab";
+            }
             win.openUILinkIn(data.href, where);
             linkHandled.data = true;
           }
         }
         break;
       case "profile-before-change":
          // Any component depending on Places should be finalized in
          // _onPlacesShutdown.  Any component that doesn't need to act after
--- a/browser/extensions/loop/manifest.ini
+++ b/browser/extensions/loop/manifest.ini
@@ -8,14 +8,12 @@
 ;
 ; Hence we duplicate the same files as support files, so that they can be loaded
 ; in a content context.
 ;
 ; This might get messy if we start having pre-processed files, but for now it
 ; seems to work.
 
 [DEFAULT]
-b2g = false
-browser = true
-qemu = false
+run-if = buildapp == 'browser'
 
 [chrome/content/shared/test/test_shared_all.py]
 [chrome/content/panels/test/test_desktop_all.py]
--- a/browser/extensions/loop/test/functional/manifest.ini
+++ b/browser/extensions/loop/test/functional/manifest.ini
@@ -1,7 +1,5 @@
 [DEFAULT]
-b2g = false
-browser = true
-qemu = false
+run-if = buildapp == 'browser'
 
 [test_1_browser_call.py]
 [test_2_linkclicker.py]
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -564,17 +564,17 @@
 #endif
 
 @RESPATH@/components/nsAsyncShutdown.manifest
 @RESPATH@/components/nsAsyncShutdown.js
 
 @RESPATH@/components/PresentationDeviceInfoManager.manifest
 @RESPATH@/components/PresentationDeviceInfoManager.js
 @RESPATH@/components/BuiltinProviders.manifest
-@RESPATH@/components/TCPPresentationServer.js
+@RESPATH@/components/PresentationControlService.js
 @RESPATH@/components/PresentationDataChannelSessionTransport.js
 @RESPATH@/components/PresentationDataChannelSessionTransport.manifest
 
 ; InputMethod API
 @RESPATH@/components/MozKeyboard.js
 @RESPATH@/components/InputMethod.manifest
 
 #ifdef MOZ_DEBUG
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -288,16 +288,40 @@ window:not([chromehidden~="toolbar"]) #u
   background-color: var(--tab-hover-background-color);
 }
 
 .tabbrowser-tab[visuallyselected] {
   color: var(--tab-selection-color) !important; /* Override color: inherit */
   background-color: var(--tab-selection-background-color);
 }
 
+.tab-icon-sound[visuallyselected=true][soundplaying] {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-white");
+}
+
+.tab-icon-sound[visuallyselected=true][soundplaying]:hover {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-white-hover");
+}
+
+.tab-icon-sound[visuallyselected=true][soundplaying]:hover:active {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-white-pressed");
+}
+
+.tab-icon-sound[visuallyselected=true][muted] {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted-white");
+}
+
+.tab-icon-sound[visuallyselected=true][muted]:hover {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted-white-hover");
+}
+
+.tab-icon-sound[visuallyselected=true][muted]:hover:active {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted-white-pressed");
+}
+
 /* Don't need space for the tab curves (66px - 30px) */
 .tabs-newtab-button {
   width: 36px;
 }
 
 .tabs-newtab-button:hover {
   /* Important needed because !important is used in browser.css */
   background-color: var(--tab-hover-background-color) !important;
--- a/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css
+++ b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css
@@ -61,17 +61,17 @@ p {
   line-height: 1.5em;
 }
 
 .list-row {
   overflow: auto;
 }
 
 .list-row > ul > li {
-  float: left;
+  float: inline-start;
   width: 220px;
   line-height: 1.5em;
   margin-inline-start: 1em;
   margin-bottom: 0;
 }
 
 .title {
   background-image: url("chrome://browser/skin/privatebrowsing/private-browsing.svg");
@@ -79,39 +79,47 @@ p {
   background-position: left, center;
   font-weight: lighter;
   line-height: 1.5em;
   min-height: 64px;
   margin-inline-start: 0;
   padding-inline-start: calc(var(--icon-margin) + 24px);
 }
 
+.title:dir(rtl) {
+  background-position: right, center;
+}
+
 .about-subheader {
   display: flex;
   align-items: center;
   font-size: 1.5em;
   font-weight: lighter;
   min-height: 32px;
   background-image: url("chrome://browser/skin/privatebrowsing/tracking-protection.svg");
   background-repeat: no-repeat;
   background-size: 32px;
   margin-inline-start: calc(var(--icon-margin) - 32px);
   padding-inline-start: 56px;
 }
 
+.about-subheader:dir(rtl) {
+  background-position: right;
+}
+
 .about-subheader.tp-off {
   background-image: url("chrome://browser/skin/privatebrowsing/tracking-protection-off.svg");
 }
 
 .about-info {
   font-size: .875em;
 }
 
 .tpTitle {
-  margin-right: 12px;
+  margin-inline-end: 12px;
 }
 
 .private strong {
   color: var(--color-grey-lightest);
   font-weight: normal;
 }
 
 a.button {
@@ -148,34 +156,49 @@ a.button {
   box-shadow: 0 0 1px 1px hsla(0, 0%, 0%, .1),
               0 1px 0 hsla(0, 0%, 0%, .2);
   border-radius: 50%;
   background: white;
   transition: left .2s ease;
 }
 
 .toggle + .toggle-btn::before {
-  float: left;
+  float: inline-start;
   left: 9px;
   visibility: hidden;
   background-size: 16px;
   background-repeat: no-repeat;
   background-color: transparent;
   background-image: url("chrome://browser/skin/privatebrowsing/check.svg");
 }
 
+.toggle + .toggle-btn:dir(rtl)::after {
+  left: auto;
+  right: 0;
+  transition-property: right;
+}
+
+.toggle + .toggle-btn:dir(rtl)::before {
+  left: auto;
+  right: 9px;
+}
+
 .toggle:checked + .toggle-btn {
   background: #3fc455;
   border: 1px solid #269939;
 }
 
 .toggle:checked + .toggle-btn::after {
   left: 35px;
 }
 
+.toggle:checked + .toggle-btn:dir(rtl)::after {
+  right: 35px;
+}
+
 .toggle:checked + .toggle-btn::before {
   visibility: visible;
 }
 
 .toggle:-moz-focusring + .toggle-btn {
   outline: 2px solid rgba(0, 149, 221, 0.5);
   outline-offset: 1px;
   -moz-outline-radius: 2px;
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -171,36 +171,42 @@
 .tab-icon-sound[muted]:hover {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-backgroundTab-muted-hover");
 }
 
 .tab-icon-sound[muted]:hover:active {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-backgroundTab-muted-pressed");
 }
 
+.tab-icon-sound:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][soundplaying] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio");
 }
 
+.tab-icon-sound:hover:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][soundplaying]:hover {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-hover");
 }
 
+.tab-icon-sound:hover:active:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][soundplaying]:hover:active {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-pressed");
 }
 
+.tab-icon-sound[muted]:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][muted] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted");
 }
 
+.tab-icon-sound[muted]:hover:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][muted]:hover {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted-hover");
 }
 
+.tab-icon-sound[muted]:hover:active:-moz-lwtheme,
 .tab-icon-sound[visuallyselected=true][muted]:hover:active {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted-pressed");
 }
 
 #TabsToolbar[brighttext] .tab-icon-sound[soundplaying] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-white");
 }
 
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -546,17 +546,16 @@ BasePrincipal::GetUnknownAppId(bool* aUn
 already_AddRefed<BasePrincipal>
 BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs)
 {
   // If the URI is supposed to inherit the security context of whoever loads it,
   // we shouldn't make a codebase principal for it.
   bool inheritsPrincipal;
   nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                                     &inheritsPrincipal);
-  nsCOMPtr<nsIPrincipal> principal;
   if (NS_FAILED(rv) || inheritsPrincipal) {
     return nsNullPrincipal::Create(aAttrs);
   }
 
   // Check whether the URI knows what its principal is supposed to be.
   nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
   if (uriPrinc) {
     nsCOMPtr<nsIPrincipal> principal;
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -55,11 +55,8 @@ LOCAL_INCLUDES += [
 ]
 
 if CONFIG['ENABLE_TESTS']:
     DIRS += ['tests/gtest']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
-
-if CONFIG['GNU_CXX']:
-    CXXFLAGS += ['-Wno-error=shadow']
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -667,17 +667,17 @@ EqualOrSubdomain(nsIURI* aProbeArg, nsIU
     nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
     NS_ENSURE_TRUE(tldService, false);
     while (true) {
         if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
             return true;
         }
 
         nsAutoCString host, newHost;
-        nsresult rv = probe->GetHost(host);
+        rv = probe->GetHost(host);
         NS_ENSURE_SUCCESS(rv, false);
 
         rv = tldService->GetNextSubDomain(host, newHost);
         if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
             return false;
         }
         NS_ENSURE_SUCCESS(rv, false);
         rv = probe->SetHost(newHost);
@@ -845,18 +845,16 @@ nsScriptSecurityManager::CheckLoadURIWit
               sourceScheme.EqualsIgnoreCase(targetScheme.get()) &&
               NS_SUCCEEDED(aTargetURI->SchemeIs("view-source", &targetIsViewSource)) &&
               targetIsViewSource))
     {
         // every scheme can access another URI from the same scheme,
         // as long as they don't represent null principals...
         // Or they don't require an special permission to do so
         // See bug#773886
-
-        bool hasFlags;
         rv = NS_URIChainHasFlags(targetBaseURI,
                                  nsIProtocolHandler::URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM,
                                  &hasFlags);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (hasFlags) {
             // Let apps load the whitelisted theme resources even if they don't
             // have the webapps-manage permission but have the themeable one.
--- a/caps/nsSystemPrincipal.cpp
+++ b/caps/nsSystemPrincipal.cpp
@@ -69,17 +69,17 @@ nsSystemPrincipal::GetCsp(nsIContentSecu
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument,
                              nsIContentSecurityPolicy** aCSP)
 {
   // CSP on a system principal makes no sense
-  return NS_OK;
+  return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP)
 {
   *aPreloadCSP = nullptr;
   return NS_OK;
 }
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -71,17 +71,17 @@ nsChromeProtocolHandler::NewURI(const ns
                                 const char *aCharset,
                                 nsIURI *aBaseURI,
                                 nsIURI **result)
 {
 
     // Chrome: URLs (currently) have no additional structure beyond that provided
     // by standard URLs, so there is no "outer" given to CreateInstance
 
-    RefPtr<nsStandardURL> surl = new nsStandardURL();
+    RefPtr<mozilla::net::nsStandardURL> surl = new mozilla::net::nsStandardURL();
 
     nsresult rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec,
                              aCharset, aBaseURI);
     if (NS_FAILED(rv))
         return rv;
 
     // Canonify the "chrome:" URL; e.g., so that we collapse
     // "chrome://navigator/content/" and "chrome://navigator/content"
--- a/config/external/nss/Makefile.in
+++ b/config/external/nss/Makefile.in
@@ -240,17 +240,17 @@ DEFAULT_GMAKE_FLAGS += \
 endif
 
 DEFAULT_GMAKE_FLAGS += FREEBL_NO_DEPEND=0 $(FREEBL_LOWHASH_FLAG)
 
 ifdef MOZ_NO_WLZDEFS
 DEFAULT_GMAKE_FLAGS += ZDEFS_FLAG=
 endif
 ifdef MOZ_CFLAGS_NSS
-DEFAULT_GMAKE_FLAGS += XCFLAGS='$(filter-out -W%,$(CFLAGS))'
+XCFLAGS += $(filter-out -W%,$(CFLAGS))
 DEFAULT_GMAKE_FLAGS += DARWIN_DYLIB_VERSIONS='-compatibility_version 1 -current_version 1 $(LDFLAGS)'
 endif
 ifeq (1_1,$(CLANG_CL)_$(MOZ_ASAN))
 XLDFLAGS := $(OS_LDFLAGS)
 DEFAULT_GMAKE_FLAGS += XLDFLAGS='$(XLDFLAGS)'
 endif
 
 DEFAULT_GMAKE_FLAGS += NSS_NO_PKCS11_BYPASS=1
@@ -263,19 +263,29 @@ DEFAULT_GMAKE_FLAGS += MODULE_INCLUDES='
 # Work around NSS's MAKE_OBJDIR being racy. See bug #836220
 DEFAULT_GMAKE_FLAGS += MAKE_OBJDIR='$$(INSTALL) -D $$(OBJDIR)'
 
 # Work around NSS adding IMPORT_LIBRARY to TARGETS with no rule for
 # it, creating race conditions. See bug #836220
 DEFAULT_GMAKE_FLAGS += TARGETS='$$(LIBRARY) $$(SHARED_LIBRARY) $$(PROGRAM)'
 
 ifdef MOZ_FOLD_LIBS_FLAGS
-DEFAULT_GMAKE_FLAGS += XCFLAGS='$(MOZ_FOLD_LIBS_FLAGS)'
+XCFLAGS += $(MOZ_FOLD_LIBS_FLAGS)
 endif
 
+# Pass on the MSVC target arch from the main build system.
+# Note this is case- and switch-character sensitive, while
+# the MSVC option is not.
+ifeq (WINNT,$(OS_TARGET))
+XCFLAGS += $(filter -arch:%,$(CFLAGS))
+endif
+
+# Export accumulated XCFLAGS to modify nss defaults.
+DEFAULT_GMAKE_FLAGS += XCFLAGS='$(XCFLAGS)'
+
 NSS_SRCDIR = $(topsrcdir)
 
 NSS_DIRS =
 ifndef MOZ_FOLD_LIBS
 NSS_DIRS += nss/lib
 else
 ifndef NSS_DISABLE_DBM
 NSS_DIRS += nss/lib/dbm
--- a/config/gcc-stl-wrapper.template.h
+++ b/config/gcc-stl-wrapper.template.h
@@ -12,54 +12,54 @@
 // compiling ObjC.
 #if defined(__EXCEPTIONS) && __EXCEPTIONS && !(__OBJC__ && __GNUC__ && XP_IOS)
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
 // Silence "warning: #include_next is a GCC extension"
 #pragma GCC system_header
 
+#if defined(DEBUG) && !defined(_GLIBCXX_DEBUG)
+// Enable checked iterators and other goodies
+//
+// FIXME/bug 551254: gcc's debug STL implementation requires -frtti.
+// Figure out how to resolve this with -fno-rtti.  Maybe build with
+// -frtti in DEBUG builds?
+//
+//  # define _GLIBCXX_DEBUG 1
+#endif
+
 // Don't include mozalloc for cstdlib. See bug 1245076.
 #ifndef moz_dont_include_mozalloc_for_cstdlib
 #  define moz_dont_include_mozalloc_for_cstdlib
 #endif
-#ifndef moz_dont_include_mozalloc_for_${HEADER}
-// mozalloc.h wants <new>; break the cycle by always explicitly
-// including <new> here.  NB: this is a tad sneaky.  Sez the gcc docs:
-//
-//    `#include_next' does not distinguish between <file> and "file"
-//    inclusion, nor does it check that the file you specify has the
-//    same name as the current file. It simply looks for the file
-//    named, starting with the directory in the search path after the
-//    one where the current file was found.
-#  include_next <new>
 
+// Include mozalloc after the STL header and all other headers it includes
+// have been preprocessed.
+#if !defined(MOZ_INCLUDE_MOZALLOC_H) && \
+    !defined(moz_dont_include_mozalloc_for_${HEADER})
+#  define MOZ_INCLUDE_MOZALLOC_H
+#  define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
+#endif
+
+#pragma GCC visibility push(default)
+#include_next <${HEADER}>
+#pragma GCC visibility pop
+
+#ifdef MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
 // See if we're in code that can use mozalloc.  NB: this duplicates
 // code in nscore.h because nscore.h pulls in prtypes.h, and chromium
 // can't build with that being included before base/basictypes.h.
 #  if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
 #    include "mozilla/mozalloc.h"
 #  else
 #    error "STL code can only be used with infallible ::operator new()"
 #  endif
-
 #endif
 
-// Don't enable debug mode with the clang plugin; clang doesn't recognize
-// the debug/ versions of the stdlib headers as being system headers, leading
-// to complaints about code that's out of our control.
-#if defined(DEBUG) && !defined(_GLIBCXX_DEBUG) && !defined(MOZ_CLANG_PLUGIN)
-// Enable checked iterators and other goodies
-  # define _GLIBCXX_DEBUG 1
-#endif
-
-#pragma GCC visibility push(default)
-#include_next <${HEADER}>
-#pragma GCC visibility pop
-
 // gcc calls a __throw_*() function from bits/functexcept.h when it
 // wants to "throw an exception".  functexcept exists nominally to
 // support -fno-exceptions, but since we'll always use the system
 // libstdc++, and it's compiled with exceptions, then in practice
 // these __throw_*() functions will always throw exceptions (shades of
 // -fshort-wchar).  We don't want that and so define our own inlined
 // __throw_*().
 #ifndef mozilla_throw_gcc_h
--- a/config/make-stl-wrappers.py
+++ b/config/make-stl-wrappers.py
@@ -25,28 +25,26 @@ def header_path(header, compiler):
 def is_comment(line):
     return re.match(r'\s*#.*', line)
 
 def main(outdir, compiler, template_file, header_list_file):
     if not os.path.isdir(outdir):
         os.mkdir(outdir)
 
     template = open(template_file, 'r').read()
-    path_to_new = header_path('new', compiler)
 
     for header in open(header_list_file, 'r'):
         header = header.rstrip()
         if 0 == len(header) or is_comment(header):
             continue
 
         path = header_path(header, compiler)
         with FileAvoidWrite(os.path.join(outdir, header)) as f:
             f.write(string.Template(template).substitute(HEADER=header,
-                                                         HEADER_PATH=path,
-                                                         NEW_HEADER_PATH=path_to_new))
+                                                         HEADER_PATH=path))
 
 
 if __name__ == '__main__':
     if 5 != len(sys.argv):
         print("""Usage:
   python {0} OUT_DIR ('msvc'|'gcc') TEMPLATE_FILE HEADER_LIST_FILE
 """.format(sys.argv[0]), file=sys.stderr)
         sys.exit(1)
--- a/config/msvc-stl-wrapper.template.h
+++ b/config/msvc-stl-wrapper.template.h
@@ -3,45 +3,33 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_${HEADER}_h
 #define mozilla_${HEADER}_h
 
-#ifndef MOZ_HAVE_INCLUDED_ALLOC
-#define MOZ_HAVE_INCLUDED_ALLOC
-
 #if _HAS_EXCEPTIONS
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
+// Include mozalloc after the STL header and all other headers it includes
+// have been preprocessed.
+#if !defined(MOZ_INCLUDE_MOZALLOC_H)
+#  define MOZ_INCLUDE_MOZALLOC_H
+#  define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
+#endif
+
 // Code built with !_HAS_EXCEPTIONS calls std::_Throw(), but the win2k
 // CRT doesn't export std::_Throw().  So we define it.
 #ifndef mozilla_Throw_h
 #  include "mozilla/throw_msvc.h"
 #endif
 
-// Code might include <new> before other wrapped headers, but <new>
-// includes <exception> and so we want to wrap it.  But mozalloc.h
-// wants <new> also, so we break the cycle by always explicitly
-// including <new> here.
-#include <${NEW_HEADER_PATH}>
-
-// See if we're in code that can use mozalloc.  NB: this duplicates
-// code in nscore.h because nscore.h pulls in prtypes.h, and chromium
-// can't build with that being included before base/basictypes.h.
-#if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
-#  include "mozilla/mozalloc.h"
-#else
-#  error "STL code can only be used with infallible ::operator new()"
-#endif
-#endif /* MOZ_HAVE_INCLUDED_ALLOC */
-
 #ifdef _DEBUG
 // From
 //   http://msdn.microsoft.com/en-us/library/aa985982%28VS.80%29.aspx
 // and
 //   http://msdn.microsoft.com/en-us/library/aa985965%28VS.80%29.aspx
 // there appear to be two types of STL container checking.  The
 // former is enabled by -D_DEBUG (which is implied by -MDd or -MTd), and
 // looks to be full generation/mutation checked iterators as done by
@@ -70,9 +58,20 @@
 //        but that's OK because we're not throwing them.
 #pragma warning( push )
 #pragma warning( disable : 4275 4530 )
 
 #include <${HEADER_PATH}>
 
 #pragma warning( pop )
 
+#ifdef MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
+// See if we're in code that can use mozalloc.  NB: this duplicates
+// code in nscore.h because nscore.h pulls in prtypes.h, and chromium
+// can't build with that being included before base/basictypes.h.
+#  if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
+#    include "mozilla/mozalloc.h"
+#  else
+#    error "STL code can only be used with infallible ::operator new()"
+#  endif
+#endif
+
 #endif  // if mozilla_${HEADER}_h
--- a/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
+++ b/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
@@ -72,15 +72,16 @@ function hasExpectedProperties(container
   }
 
   return true;
 }
 
 function hasExpectedWarnings(containerEl) {
   let warnings = [...containerEl.querySelectorAll(".warning")];
   for (let warning of warnings) {
-    if (warning.getAttribute("title") ==
-         L10N.getStr("AnimationWarningTransformWithGeometricProperties")) {
+    let warningID =
+      "CompositorAnimationWarningTransformWithGeometricProperties";
+    if (warning.getAttribute("title") == L10N.getStr(warningID)) {
       return true;
     }
   }
   return false;
 }
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -126,21 +126,25 @@ function MarkupView(inspector, frame, co
   this._onNewSelection = this._onNewSelection.bind(this);
   this._onCopy = this._onCopy.bind(this);
   this._onFocus = this._onFocus.bind(this);
   this._onMouseMove = this._onMouseMove.bind(this);
   this._onMouseLeave = this._onMouseLeave.bind(this);
   this._onToolboxPickerHover = this._onToolboxPickerHover.bind(this);
   this._onCollapseAttributesPrefChange =
     this._onCollapseAttributesPrefChange.bind(this);
+  this._onBlur = this._onBlur.bind(this);
+
+  EventEmitter.decorate(this);
 
   // Listening to various events.
   this._elt.addEventListener("click", this._onMouseClick, false);
   this._elt.addEventListener("mousemove", this._onMouseMove, false);
   this._elt.addEventListener("mouseleave", this._onMouseLeave, false);
+  this._elt.addEventListener("blur", this._onBlur, true);
   this.win.addEventListener("mouseup", this._onMouseUp);
   this.win.addEventListener("copy", this._onCopy);
   this._frame.addEventListener("focus", this._onFocus, false);
   this.walker.on("mutations", this._mutationObserver);
   this.walker.on("display-change", this._onDisplayChange);
   this._inspector.selection.on("new-node-front", this._onNewSelection);
   this._inspector.toolbox.on("picker-node-hovered", this._onToolboxPickerHover);
 
@@ -149,18 +153,16 @@ function MarkupView(inspector, frame, co
 
   this._prefObserver = new PrefObserver("devtools.markup");
   this._prefObserver.on(ATTR_COLLAPSE_ENABLED_PREF,
                         this._onCollapseAttributesPrefChange);
   this._prefObserver.on(ATTR_COLLAPSE_LENGTH_PREF,
                         this._onCollapseAttributesPrefChange);
 
   this._initShortcuts();
-
-  EventEmitter.decorate(this);
 }
 
 MarkupView.prototype = {
   /**
    * How long does a node flash when it mutates (in ms).
    */
   CONTAINER_FLASHING_DURATION: 500,
 
@@ -216,16 +218,35 @@ MarkupView.prototype = {
       }
     }
     this._showContainerAsHovered(container.node);
 
     this.emit("node-hover");
   },
 
   /**
+   * If focus is moved outside of the markup view document and there is a
+   * selected container, make its contents not focusable by a keyboard.
+   */
+  _onBlur: function (event) {
+    if (!this._selectedContainer) {
+      return;
+    }
+
+    let {relatedTarget} = event;
+    if (relatedTarget && relatedTarget.ownerDocument === this.doc) {
+      return;
+    }
+
+    if (this._selectedContainer) {
+      this._selectedContainer.clearFocus();
+    }
+  },
+
+  /**
    * Executed on each mouse-move while a node is being dragged in the view.
    * Auto-scrolls the view to reveal nodes below the fold to drop the dragged
    * node in.
    */
   _autoScroll: function (event) {
     let docEl = this.doc.documentElement;
 
     if (this._autoScrollInterval) {
@@ -536,50 +557,51 @@ MarkupView.prototype = {
       // We could be destroyed by now.
       if (this._destroyer) {
         return promise.reject("markupview destroyed");
       }
 
       // Mark the node as selected.
       this.markNodeAsSelected(selection.nodeFront);
 
-      // Make sure the new selection receives focus so the keyboard can be used.
-      this.maybeFocusNewSelection();
+      // Make sure the new selection is navigated to.
+      this.maybeNavigateToNewSelection();
       return undefined;
     }).catch(e => {
       if (!this._destroyer) {
         console.error(e);
       } else {
         console.warn("Could not mark node as selected, the markup-view was " +
           "destroyed while showing the node.");
       }
     });
 
     promise.all([onShowBoxModel, onShow]).then(done);
   },
 
   /**
-   * Maybe focus the current node selection's MarkupContainer depending on why
-   * the current node got selected.
+   * Maybe make selected the current node selection's MarkupContainer depending
+   * on why the current node got selected.
    */
-  maybeFocusNewSelection: function () {
+  maybeNavigateToNewSelection: function () {
     let {reason, nodeFront} = this._inspector.selection;
 
-    // The list of reasons that should lead to focusing the node.
-    let reasonsToFocus = [
+    // The list of reasons that should lead to navigating to the node.
+    let reasonsToNavigate = [
       // If the user picked an element with the element picker.
       "picker-node-picked",
       // If the user selected an element with the browser context menu.
       "browser-context-menu",
       // If the user added a new node by clicking in the inspector toolbar.
       "node-inserted"
     ];
 
-    if (reasonsToFocus.includes(reason)) {
-      this.getContainer(nodeFront).focus();
+    if (reasonsToNavigate.includes(reason)) {
+      this.getContainer(this._rootNode).elt.focus();
+      this.navigate(this.getContainer(nodeFront));
     }
   },
 
   /**
    * Create a TreeWalker to find the next/previous
    * node for selection.
    */
   _selectionWalker: function (start) {
@@ -628,17 +650,17 @@ MarkupView.prototype = {
      "markupView.edit.key",
      "markupView.scrollInto.key"].forEach(name => {
        let key = this.strings.GetStringFromName(name);
        shortcuts.on(key, (_, event) => this._onShortcut(name, event));
      });
 
     // Process generic keys:
     ["Delete", "Backspace", "Home", "Left", "Right", "Up", "Down", "PageUp",
-     "PageDown", "Esc"].forEach(key => {
+     "PageDown", "Esc", "Enter", "Space"].forEach(key => {
        shortcuts.on(key, this._onShortcut);
      });
   },
 
   /**
    * Key shortcut listener.
    */
   _onShortcut(name, event) {
@@ -737,16 +759,27 @@ MarkupView.prototype = {
           if (!nextNode) {
             break;
           }
           selection = nextNode.container;
         }
         this.navigate(selection);
         break;
       }
+      case "Enter":
+      case "Space": {
+        if (!this._selectedContainer.canFocus) {
+          this._selectedContainer.canFocus = true;
+          this._selectedContainer.focus();
+        } else {
+          // Return early to prevent cancelling the event.
+          return;
+        }
+        break;
+      }
       case "Esc": {
         if (this.isDragging) {
           this.cancelDragging();
         } else {
           // Return early to prevent cancelling the event when not
           // dragging, to allow the split console to be toggled.
           return;
         }
@@ -837,40 +870,34 @@ MarkupView.prototype = {
    * If an editable item is focused, select its container.
    */
   _onFocus: function (event) {
     let parent = event.target;
     while (!parent.container) {
       parent = parent.parentNode;
     }
     if (parent) {
-      this.navigate(parent.container, true);
+      this.navigate(parent.container);
     }
   },
 
   /**
    * Handle a user-requested navigation to a given MarkupContainer,
    * updating the inspector's currently-selected node.
    *
    * @param  {MarkupContainer} container
    *         The container we're navigating to.
-   * @param  {Boolean} ignoreFocus
-   *         If false, keyboard focus will be moved to the container too.
    */
-  navigate: function (container, ignoreFocus) {
+  navigate: function (container) {
     if (!container) {
       return;
     }
 
     let node = container.node;
     this.markNodeAsSelected(node, "treepanel");
-
-    if (!ignoreFocus) {
-      container.focus();
-    }
   },
 
   /**
    * Make sure a node is included in the markup tool.
    *
    * @param  {NodeFront} node
    *         The node in the content document.
    * @param  {Boolean} flashNode
@@ -939,18 +966,21 @@ MarkupView.prototype = {
         // we're not viewing.
         continue;
       }
       if (type === "attributes" || type === "characterData"
         || type === "events" || type === "pseudoClassLock") {
         container.update();
       } else if (type === "childList" || type === "nativeAnonymousChildList") {
         container.childrenDirty = true;
-        // Update the children to take care of changes in the markup view DOM.
-        this._updateChildren(container, {flash: true});
+        // Update the children to take care of changes in the markup view DOM
+        // and update container (and its subtree) DOM tree depth level for
+        // accessibility where necessary.
+        this._updateChildren(container, {flash: true}).then(() =>
+          container.updateLevel());
       }
     }
 
     this._waitForChildren().then(() => {
       if (this._destroyer) {
         console.warn("Could not fully update after markup mutations, " +
           "the markup-view was destroyed while waiting for children.");
         return;
@@ -1382,23 +1412,25 @@ MarkupView.prototype = {
    *         The NodeFront to mark as selected.
    * @param  {String} reason
    *         The reason for marking the node as selected.
    * @return {Boolean} False if the node is already marked as selected, true
    *         otherwise.
    */
   markNodeAsSelected: function (node, reason) {
     let container = this.getContainer(node);
+
     if (this._selectedContainer === container) {
       return false;
     }
 
-    // Un-select the previous container.
+    // Un-select and remove focus from the previous container.
     if (this._selectedContainer) {
       this._selectedContainer.selected = false;
+      this._selectedContainer.clearFocus();
     }
 
     // Select the new container.
     this._selectedContainer = container;
     if (node) {
       this._selectedContainer.selected = true;
     }
 
@@ -1483,16 +1515,19 @@ MarkupView.prototype = {
    * @return {Promise} that will be resolved when the children are ready
    *         (which may be immediately).
    */
   _updateChildren: function (container, options) {
     let expand = options && options.expand;
     let flash = options && options.flash;
 
     container.hasChildren = container.node.hasChildren;
+    // Accessibility should either ignore empty children or semantically
+    // consider them a group.
+    container.setChildrenRole();
 
     if (!this._queuedChildUpdates) {
       this._queuedChildUpdates = new Map();
     }
 
     if (this._queuedChildUpdates.has(container)) {
       return this._queuedChildUpdates.get(container);
     }
@@ -1651,16 +1686,17 @@ MarkupView.prototype = {
     this.undo = null;
 
     this.popup.destroy();
     this.popup = null;
 
     this._elt.removeEventListener("click", this._onMouseClick, false);
     this._elt.removeEventListener("mousemove", this._onMouseMove, false);
     this._elt.removeEventListener("mouseleave", this._onMouseLeave, false);
+    this._elt.removeEventListener("blur", this._onBlur, true);
     this.win.removeEventListener("mouseup", this._onMouseUp);
     this.win.removeEventListener("copy", this._onCopy);
     this._frame.removeEventListener("focus", this._onFocus, false);
     this.walker.off("mutations", this._mutationObserver);
     this.walker.off("display-change", this._onDisplayChange);
     this._inspector.selection.off("new-node-front", this._onNewSelection);
     this._inspector.toolbox.off("picker-node-hovered",
                                 this._onToolboxPickerHover);
@@ -1788,16 +1824,22 @@ MarkupView.prototype = {
  *
  * This should not be instantiated directly, instead use one of:
  *    MarkupReadOnlyContainer
  *    MarkupTextContainer
  *    MarkupElementContainer
  */
 function MarkupContainer() { }
 
+/**
+ * Unique identifier used to set markup container node id.
+ * @type {Number}
+ */
+let markupContainerID = 0;
+
 MarkupContainer.prototype = {
   /*
    * Initialize the MarkupContainer.  Should be called while one
    * of the other contain classes is instantiated.
    *
    * @param  {MarkupView} markupView
    *         The markup view that owns this container.
    * @param  {NodeFront} node
@@ -1805,30 +1847,32 @@ MarkupContainer.prototype = {
    * @param  {String} templateID
    *         Which template to render for this container
    */
   initialize: function (markupView, node, templateID) {
     this.markup = markupView;
     this.node = node;
     this.undo = this.markup.undo;
     this.win = this.markup._frame.contentWindow;
+    this.id = "treeitem-" + markupContainerID++;
 
     // The template will fill the following properties
     this.elt = null;
     this.expander = null;
     this.tagState = null;
     this.tagLine = null;
     this.children = null;
     this.markup.template(templateID, this);
     this.elt.container = this;
 
     this._onMouseDown = this._onMouseDown.bind(this);
     this._onToggle = this._onToggle.bind(this);
     this._onMouseUp = this._onMouseUp.bind(this);
     this._onMouseMove = this._onMouseMove.bind(this);
+    this._onKeyDown = this._onKeyDown.bind(this);
 
     // Binding event listeners
     this.elt.addEventListener("mousedown", this._onMouseDown, false);
     this.win.addEventListener("mouseup", this._onMouseUp, true);
     this.win.addEventListener("mousemove", this._onMouseMove, true);
     this.elt.addEventListener("dblclick", this._onToggle, false);
     if (this.expander) {
       this.expander.addEventListener("click", this._onToggle, false);
@@ -1876,38 +1920,139 @@ MarkupContainer.prototype = {
   },
 
   set hasChildren(value) {
     this._hasChildren = value;
     this.updateExpander();
   },
 
   /**
+   * A list of all elements with tabindex that are not in container's children.
+   */
+  get focusableElms() {
+    return [...this.tagLine.querySelectorAll("[tabindex]")];
+  },
+
+  /**
+   * An indicator that the container internals are focusable.
+   */
+  get canFocus() {
+    return this._canFocus;
+  },
+
+  /**
+   * Toggle focusable state for container internals.
+   */
+  set canFocus(value) {
+    if (this._canFocus === value) {
+      return;
+    }
+
+    this._canFocus = value;
+
+    if (value) {
+      this.tagLine.addEventListener("keydown", this._onKeyDown, true);
+      this.focusableElms.forEach(elm => elm.setAttribute("tabindex", "0"));
+    } else {
+      this.tagLine.removeEventListener("keydown", this._onKeyDown, true);
+      // Exclude from tab order.
+      this.focusableElms.forEach(elm => elm.setAttribute("tabindex", "-1"));
+    }
+  },
+
+  /**
+   * If conatiner and its contents are focusable, exclude them from tab order,
+   * and, if necessary, remove focus.
+   */
+  clearFocus: function () {
+    if (!this.canFocus) {
+      return;
+    }
+
+    this.canFocus = false;
+    let doc = this.markup.doc;
+
+    if (!doc.activeElement || doc.activeElement === doc.body) {
+      return;
+    }
+
+    let parent = doc.activeElement;
+
+    while (parent && parent !== this.elt) {
+      parent = parent.parentNode;
+    }
+
+    if (parent) {
+      doc.activeElement.blur();
+    }
+  },
+
+  /**
    * True if the current node can be expanded.
    */
   get canExpand() {
     return this._hasChildren && !this.node.singleTextChild;
   },
 
   /**
    * True if this is the root <html> element and can't be collapsed.
    */
   get mustExpand() {
     return this.node._parent === this.markup.walker.rootNode;
   },
 
+  /**
+   * True if current node can be expanded and collapsed.
+   */
+  get showExpander() {
+    return this.canExpand && !this.mustExpand;
+  },
+
   updateExpander: function () {
     if (!this.expander) {
       return;
     }
 
-    if (this.canExpand && !this.mustExpand) {
+    if (this.showExpander) {
       this.expander.style.visibility = "visible";
+      // Update accessibility expanded state.
+      this.tagLine.setAttribute("aria-expanded", this.expanded);
     } else {
       this.expander.style.visibility = "hidden";
+      // No need for accessible expanded state indicator when expander is not
+      // shown.
+      this.tagLine.removeAttribute("aria-expanded");
+    }
+  },
+
+  /**
+   * If current node has no children, ignore them. Otherwise, consider them a
+   * group from the accessibility point of view.
+   */
+  setChildrenRole: function () {
+    this.children.setAttribute("role",
+      this.hasChildren ? "group" : "presentation");
+  },
+
+  /**
+   * Set an appropriate DOM tree depth level for a node and its subtree.
+   */
+  updateLevel: function () {
+    // ARIA level should already be set when container template is rendered.
+    let currentLevel = this.tagLine.getAttribute("aria-level");
+    let newLevel = this.level;
+    if (currentLevel === newLevel) {
+      // If level did not change, ignore this node and its subtree.
+      return;
+    }
+
+    this.tagLine.setAttribute("aria-level", newLevel);
+    let childContainers = this.getChildContainers();
+    if (childContainers) {
+      childContainers.forEach(container => container.updateLevel());
     }
   },
 
   /**
    * If the node has children, return the list of containers for all these
    * children.
    */
   getChildContainers: function () {
@@ -1940,59 +2085,84 @@ MarkupContainer.prototype = {
     if (value && this.elt.classList.contains("collapsed")) {
       // Expanding a node means cloning its "inline" closing tag into a new
       // tag-line that the user can interact with and showing the children.
       let closingTag = this.elt.querySelector(".close");
       if (closingTag) {
         if (!this.closeTagLine) {
           let line = this.markup.doc.createElement("div");
           line.classList.add("tag-line");
+          // Closing tag is not important for accessibility.
+          line.setAttribute("role", "presentation");
 
           let tagState = this.markup.doc.createElement("div");
           tagState.classList.add("tag-state");
           line.appendChild(tagState);
 
           line.appendChild(closingTag.cloneNode(true));
 
           flashElementOff(line);
           this.closeTagLine = line;
         }
         this.elt.appendChild(this.closeTagLine);
       }
 
       this.elt.classList.remove("collapsed");
       this.expander.setAttribute("open", "");
       this.hovered = false;
+      this.markup.emit("expanded");
     } else if (!value) {
       if (this.closeTagLine) {
         this.elt.removeChild(this.closeTagLine);
         this.closeTagLine = undefined;
       }
       this.elt.classList.add("collapsed");
       this.expander.removeAttribute("open");
+      this.markup.emit("collapsed");
+    }
+    if (this.showExpander) {
+      this.tagLine.setAttribute("aria-expanded", this.expanded);
     }
   },
 
   parentContainer: function () {
     return this.elt.parentNode ? this.elt.parentNode.container : null;
   },
 
+  /**
+   * Determine tree depth level of a given node. This is used to specify ARIA
+   * level for node tree items and to give them better semantic context.
+   */
+  get level() {
+    let level = 1;
+    let parent = this.node.parentNode();
+    while (parent && parent !== this.markup.walker.rootNode) {
+      level++;
+      parent = parent.parentNode();
+    }
+    return level;
+  },
+
   _isDragging: false,
   _dragStartY: 0,
 
   set isDragging(isDragging) {
+    let rootElt = this.markup.getContainer(this.markup._rootNode).elt;
     this._isDragging = isDragging;
     this.markup.isDragging = isDragging;
+    this.tagLine.setAttribute("aria-grabbed", isDragging);
 
     if (isDragging) {
       this.elt.classList.add("dragging");
       this.markup.doc.body.classList.add("dragging");
+      rootElt.setAttribute("aria-dropeffect", "move");
     } else {
       this.elt.classList.remove("dragging");
       this.markup.doc.body.classList.remove("dragging");
+      rootElt.setAttribute("aria-dropeffect", "none");
     }
   },
 
   get isDragging() {
     return this._isDragging;
   },
 
   /**
@@ -2005,45 +2175,121 @@ MarkupContainer.prototype = {
            !this.node.isAnonymous &&
            !this.node.isDocumentElement &&
            tagName !== "body" &&
            tagName !== "head" &&
            this.win.getSelection().isCollapsed &&
            this.node.parentNode().tagName !== null;
   },
 
+  /**
+   * Move keyboard focus to a next/previous focusable element inside container
+   * that is not part of its children (only if current focus is on first or last
+   * element).
+   *
+   * @param  {DOMNode} current  currently focused element
+   * @param  {Boolean} back     direction
+   * @return {DOMNode}          newly focused element if any
+   */
+  _wrapMoveFocus: function (current, back) {
+    let elms = this.focusableElms;
+    let next;
+    if (back) {
+      if (elms.indexOf(current) === 0) {
+        next = elms[elms.length - 1];
+        next.focus();
+      }
+    } else if (elms.indexOf(current) === elms.length - 1) {
+      next = elms[0];
+      next.focus();
+    }
+    return next;
+  },
+
+  _onKeyDown: function (event) {
+    let {target, keyCode, shiftKey} = event;
+    let isInput = this.markup._isInputOrTextarea(target);
+
+    // Ignore all keystrokes that originated in editors except for when 'Tab' is
+    // pressed.
+    if (isInput && keyCode !== event.DOM_VK_TAB) {
+      return;
+    }
+
+    switch (keyCode) {
+      case event.DOM_VK_TAB:
+        // Only handle 'Tab' if tabbable element is on the edge (first or last).
+        if (isInput) {
+          // Corresponding tabbable element is editor's next sibling.
+          let next = this._wrapMoveFocus(target.nextSibling, shiftKey);
+          if (next) {
+            event.preventDefault();
+            // Keep the editing state if possible.
+            if (next._editable) {
+              let e = this.markup.doc.createEvent("Event");
+              e.initEvent(next._trigger, true, true);
+              next.dispatchEvent(e);
+            }
+          }
+        } else {
+          let next = this._wrapMoveFocus(target, shiftKey);
+          if (next) {
+            event.preventDefault();
+          }
+        }
+        break;
+      case event.DOM_VK_ESCAPE:
+        this.clearFocus();
+        this.markup.getContainer(this.markup._rootNode).elt.focus();
+        if (this.isDragging) {
+          // Escape when dragging is handled by markup view itself.
+          return;
+        }
+        event.preventDefault();
+        break;
+      default:
+        return;
+    }
+    event.stopPropagation();
+  },
+
   _onMouseDown: function (event) {
     let {target, button, metaKey, ctrlKey} = event;
     let isLeftClick = button === 0;
     let isMiddleClick = button === 1;
     let isMetaClick = isLeftClick && (metaKey || ctrlKey);
 
     // The "show more nodes" button already has its onclick, so early return.
     if (target.nodeName === "button") {
       return;
     }
 
     // target is the MarkupContainer itself.
     this.hovered = false;
     this.markup.navigate(this);
+    // Make container tabbable descendants tabbable and focus in.
+    this.canFocus = true;
+    this.focus();
     event.stopPropagation();
 
     // Preventing the default behavior will avoid the body to gain focus on
     // mouseup (through bubbling) when clicking on a non focusable node in the
     // line. So, if the click happened outside of a focusable element, do
     // prevent the default behavior, so that the tagname or textcontent gains
     // focus.
     if (!target.closest(".editor [tabindex]")) {
       event.preventDefault();
     }
 
     // Follow attribute links if middle or meta click.
     if (isMiddleClick || isMetaClick) {
       let link = target.dataset.link;
       let type = target.dataset.type;
+      // Make container tabbable descendants not tabbable (by default).
+      this.canFocus = false;
       this.markup._inspector.followAttributeLink(type, link);
       return;
     }
 
     // Start node drag & drop (if the mouse moved, see _onMouseMove).
     if (isLeftClick && this.isDraggable()) {
       this._isPreDragging = true;
       this._dragStartY = event.pageY;
@@ -2177,17 +2423,21 @@ MarkupContainer.prototype = {
   get selected() {
     return this._selected;
   },
 
   set selected(value) {
     this.tagState.classList.remove("flash-out");
     this._selected = value;
     this.editor.selected = value;
+    // Markup tree item should have accessible selected state.
+    this.tagLine.setAttribute("aria-selected", value);
     if (this._selected) {
+      this.markup.getContainer(this.markup._rootNode).elt.setAttribute(
+        "aria-activedescendant", this.id);
       this.tagLine.setAttribute("selected", "");
       this.tagState.classList.add("theme-selected");
     } else {
       this.tagLine.removeAttribute("selected");
       this.tagState.classList.remove("theme-selected");
     }
   },
 
@@ -2206,17 +2456,18 @@ MarkupContainer.prototype = {
       this.editor.update();
     }
   },
 
   /**
    * Try to put keyboard focus on the current editor.
    */
   focus: function () {
-    let focusable = this.editor.elt.querySelector("[tabindex]");
+    // Elements with tabindex of -1 are not focusable.
+    let focusable = this.editor.elt.querySelector("[tabindex='0']");
     if (focusable) {
       focusable.focus();
     }
   },
 
   _onToggle: function (event) {
     this.markup.navigate(this);
     if (this.hasChildren) {
@@ -2228,16 +2479,17 @@ MarkupContainer.prototype = {
   /**
    * Get rid of event listeners and references, when the container is no longer
    * needed
    */
   destroy: function () {
     // Remove event listeners
     this.elt.removeEventListener("mousedown", this._onMouseDown, false);
     this.elt.removeEventListener("dblclick", this._onToggle, false);
+    this.tagLine.removeEventListener("keydown", this._onKeyDown, true);
     if (this.win) {
       this.win.removeEventListener("mouseup", this._onMouseUp, true);
       this.win.removeEventListener("mousemove", this._onMouseMove, true);
     }
 
     this.win = null;
 
     if (this.expander) {
@@ -2485,16 +2737,20 @@ MarkupElementContainer.prototype = Herit
 });
 
 /**
  * Dummy container node used for the root document element.
  */
 function RootContainer(markupView, node) {
   this.doc = markupView.doc;
   this.elt = this.doc.createElement("ul");
+  // Root container has tree semantics for accessibility.
+  this.elt.setAttribute("role", "tree");
+  this.elt.setAttribute("tabindex", "0");
+  this.elt.setAttribute("aria-dropeffect", "none");
   this.elt.container = this;
   this.children = this.elt;
   this.node = node;
   this.toString = () => "[root container]";
 }
 
 RootContainer.prototype = {
   hasChildren: true,
@@ -2509,17 +2765,27 @@ RootContainer.prototype = {
   getChildContainers: function () {
     return [...this.children.children].map(node => node.container);
   },
 
   /**
    * Set the expanded state of the container node.
    * @param  {Boolean} value
    */
-  setExpanded: function () {}
+  setExpanded: function () {},
+
+  /**
+   * Set an appropriate role of the container's children node.
+   */
+  setChildrenRole: function () {},
+
+  /**
+   * Set an appropriate DOM tree depth level for a node and its subtree.
+   */
+  updateLevel: function () {}
 };
 
 /**
  * Creates an editor for non-editable nodes.
  */
 function GenericEditor(container, node) {
   this.container = container;
   this.markup = this.container.markup;
@@ -2675,17 +2941,18 @@ function ElementEditor(container, node) 
   this.closeElt = null;
 
   // Create the main editor
   this.template("element", this);
 
   // Make the tag name editable (unless this is a remote node or
   // a document element)
   if (!node.isDocumentElement) {
-    this.tag.setAttribute("tabindex", "0");
+    // Make the tag optionally tabbable but not by default.
+    this.tag.setAttribute("tabindex", "-1");
     editableField({
       element: this.tag,
       trigger: "dblclick",
       stopOnReturn: true,
       done: this.onTagEdit.bind(this),
     });
   }
 
--- a/devtools/client/inspector/markup/markup.xhtml
+++ b/devtools/client/inspector/markup/markup.xhtml
@@ -14,88 +14,88 @@
           src="chrome://devtools/content/shared/theme-switching.js"/>
 
 </head>
 <body class="theme-body devtools-monospace" role="application">
 
 <!-- NOTE THAT WE MAKE EXTENSIVE USE OF HTML COMMENTS IN THIS FILE IN ORDER -->
 <!-- TO MAKE SPANS READABLE WHILST AVOIDING SIGNIFICANT WHITESPACE          -->
 
-  <div id="root-wrapper">
-    <div id="root"></div>
+  <div id="root-wrapper" role="presentation">
+    <div id="root" role="presentation"></div>
   </div>
   <div id="templates" style="display:none">
 
     <ul class="children">
-      <li id="template-elementcontainer" save="${elt}" class="child collapsed">
-        <div save="${tagLine}" class="tag-line"><!--
-        --><span save="${tagState}" class="tag-state"></span><!--
-        --><span save="${expander}" class="theme-twisty expander"></span><!--
+      <li id="template-elementcontainer" save="${elt}" class="child collapsed" role="presentation">
+        <div save="${tagLine}" id="${id}" class="tag-line" role="treeitem" aria-level="${level}" aria-grabbed="${isDragging}"><!--
+        --><span save="${tagState}" class="tag-state" role="presentation"></span><!--
+        --><span save="${expander}" class="theme-twisty expander" role="presentation"></span><!--
      --></div>
-        <ul save="${children}" class="children"></ul>
+        <ul save="${children}" class="children" role="group"></ul>
       </li>
 
-      <li id="template-textcontainer" save="${elt}" class="child collapsed">
-        <div save="${tagLine}" class="tag-line"><span save="${tagState}" class="tag-state"></span></div>
-        <ul save="${children}" class="children"></ul>
+      <li id="template-textcontainer" save="${elt}" class="child collapsed" role="presentation">
+        <div save="${tagLine}" id="${id}" class="tag-line" role="treeitem" aria-level="${level}" aria-grabbed="${isDragging}"><span save="${tagState}" class="tag-state" role="presentation"></span></div>
+        <ul save="${children}" class="children" role="group"></ul>
       </li>
 
-      <li id="template-readonlycontainer" save="${elt}" class="child collapsed">
-        <div save="${tagLine}" class="tag-line"><!--
-        --><span save="${tagState}" class="tag-state"></span><!--
-        --><span save="${expander}" class="theme-twisty expander"></span><!--
+      <li id="template-readonlycontainer" save="${elt}" class="child collapsed" role="presentation">
+        <div save="${tagLine}" id="${id}" class="tag-line" role="treeitem" aria-level="${level}" aria-grabbed="${isDragging}"><!--
+        --><span save="${tagState}" class="tag-state" role="presentation"></span><!--
+        --><span save="${expander}" class="theme-twisty expander" role="presentation"></span><!--
      --></div>
-        <ul save="${children}" class="children"></ul>
+        <ul save="${children}" class="children" role="group"></ul>
       </li>
 
       <li id="template-more-nodes"
           class="more-nodes devtools-class-comment"
           save="${elt}"><!--
       --><span>${showing}</span> <!--
       --><button href="#" onclick="${allButtonClick}">${showAll}</button>
       </li>
     </ul>
 
     <span id="template-generic" save="${elt}" class="editor"><span save="${tag}" class="tag"></span></span>
 
     <span id="template-element" save="${elt}" class="editor"><!--
    --><span class="open">&lt;<!--
-     --><span save="${tag}" class="tag theme-fg-color3" tabindex="0"></span><!--
+     --><span save="${tag}" class="tag theme-fg-color3" tabindex="-1"></span><!--
      --><span save="${attrList}"></span><!--
-     --><span save="${newAttr}" class="newattr" tabindex="0"></span><!--
+     --><span save="${newAttr}" class="newattr" tabindex="-1"></span><!--
      --><span class="closing-bracket">&gt;</span><!--
    --></span><!--
    --><span class="close">&lt;/<!--
      --><span save="${closeTag}" class="tag theme-fg-color3"></span><!--
      -->&gt;<!--
    --></span><!--
      --><div save="${eventNode}" class="markupview-events" data-event="true">ev</div><!--
  --></span>
 
     <span id="template-attribute"
           save="${attr}"
           data-attr="${attrName}"
           data-value="${attrValue}"
           class="attreditor"
           style="display:none"> <!--
-   --><span class="editable" save="${inner}" tabindex="0"><!--
+   --><span class="editable" save="${inner}" tabindex="-1"><!--
      --><span save="${name}" class="attr-name theme-fg-color2"></span><!--
      -->=&quot;<!--
      --><span save="${val}" class="attr-value theme-fg-color6"></span><!--
      -->&quot;<!--
    --></span><!--
  --></span>
 
     <span id="template-text" save="${elt}" class="editor text"><!--
-   --><pre save="${value}" style="display:inline-block; white-space: normal;" tabindex="0"></pre><!--
+   --><pre save="${value}" style="display:inline-block; white-space: normal;" tabindex="-1"></pre><!--
  --></span>
 
     <span id="template-comment"
           save="${elt}"
           class="editor comment theme-comment"><!--
    --><span>&lt;!--</span><!--
-   --><pre save="${value}" style="display:inline-block; white-space: normal;" tabindex="0"></pre><!--
+   --><pre save="${value}" style="display:inline-block; white-space: normal;" tabindex="-1"></pre><!--
    --><span>--&gt;</span><!--
  --></span>
 
   </div>
 </body>
 </html>
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -45,16 +45,21 @@ support-files =
   lib_jquery_1.11.1_min.js
   lib_jquery_2.1.1_min.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
+[browser_markup_accessibility_focus_blur.js]
+skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
+[browser_markup_accessibility_navigation.js]
+skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
+[browser_markup_accessibility_semantics.js]
 [browser_markup_anonymous_01.js]
 [browser_markup_anonymous_02.js]
 skip-if = e10s # scratchpad.xul is not loading in e10s window
 [browser_markup_anonymous_03.js]
 [browser_markup_anonymous_04.js]
 [browser_markup_copy_image_data.js]
 [browser_markup_css_completion_style_attribute_01.js]
 [browser_markup_css_completion_style_attribute_02.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_focus_blur.js
@@ -0,0 +1,59 @@
+/* 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";
+
+// Test inspector markup view handling focus and blur when moving between markup
+// view, its root and other containers, and other parts of inspector.
+
+add_task(function* () {
+  let {inspector, testActor} = yield openInspectorForURL(
+    "data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
+  let markup = inspector.markup;
+  let doc = markup.doc;
+  let win = doc.defaultView;
+
+  let spanContainer = yield getContainerForSelector("span", inspector);
+  let rootContainer = markup.getContainer(markup._rootNode);
+
+  is(doc.activeElement, doc.body,
+    "Keyboard focus by default is on document body");
+
+  yield selectNode("span", inspector);
+
+  is(doc.activeElement, doc.body,
+    "Keyboard focus is still on document body");
+
+  info("Focusing on the test span node using 'Return' key");
+  // Focus on the tree element.
+  rootContainer.elt.focus();
+  EventUtils.synthesizeKey("VK_RETURN", {}, win);
+
+  is(doc.activeElement, spanContainer.editor.tag,
+    "Keyboard focus should be on tag element of focused container");
+
+  info("Focusing on search box, external to markup view document");
+  yield focusSearchBoxUsingShortcut(inspector.panelWin);
+
+  is(doc.activeElement, doc.body,
+    "Keyboard focus should be removed from focused container");
+
+  info("Selecting the test span node again");
+  yield selectNode("span", inspector);
+
+  is(doc.activeElement, doc.body,
+    "Keyboard focus should again be on document body");
+
+  info("Focusing on the test span node using 'Space' key");
+  // Focus on the tree element.
+  rootContainer.elt.focus();
+  EventUtils.synthesizeKey("VK_SPACE", {}, win);
+
+  is(doc.activeElement, spanContainer.editor.tag,
+    "Keyboard focus should again be on tag element of focused container");
+
+  yield clickOnInspectMenuItem(testActor, "h1");
+  is(doc.activeElement, rootContainer.elt,
+    "When inspect menu item is used keyboard focus should move to tree.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_navigation.js
@@ -0,0 +1,301 @@
+/* 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";
+
+/* global getContainerForSelector, openInspectorForURL */
+
+// Test keyboard navigation accessibility of inspector's markup view.
+
+/**
+ * Test data has the format of:
+ * {
+ *   desc              {String}   description for better logging
+ *   key               {String}   key event's key
+ *   options           {?Object}  optional event data such as shiftKey, etc
+ *   focused           {String}   path to expected focused element relative to
+ *                                its container
+ *   activedescendant  {String}   path to expected aria-activedescendant element
+ *                                relative to its container
+ *   waitFor           {String}   optional event to wait for if keyboard actions
+ *                                result in asynchronous updates
+ * }
+ */
+const TESTS = [
+  {
+    desc: "Collapse body container",
+    focused: "root.elt",
+    activedescendant: "body.tagLine",
+    key: "VK_LEFT",
+    options: { },
+    waitFor: "collapsed"
+  },
+  {
+    desc: "Expand body container",
+    focused: "root.elt",
+    activedescendant: "body.tagLine",
+    key: "VK_RIGHT",
+    options: { },
+    waitFor: "expanded"
+  },
+  {
+    desc: "Select header container",
+    focused: "root.elt",
+    activedescendant: "header.tagLine",
+    key: "VK_DOWN",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+  {
+    desc: "Expand header container",
+    focused: "root.elt",
+    activedescendant: "header.tagLine",
+    key: "VK_RIGHT",
+    options: { },
+    waitFor: "expanded"
+  },
+  {
+    desc: "Select text container",
+    focused: "root.elt",
+    activedescendant: "container-0.tagLine",
+    key: "VK_DOWN",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+  {
+    desc: "Select header container again",
+    focused: "root.elt",
+    activedescendant: "header.tagLine",
+    key: "VK_UP",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+  {
+    desc: "Collapse header container",
+    focused: "root.elt",
+    activedescendant: "header.tagLine",
+    key: "VK_LEFT",
+    options: { },
+    waitFor: "collapsed"
+  },
+  {
+    desc: "Focus on header container tag",
+    focused: "header.focusableElms.0",
+    activedescendant: "header.tagLine",
+    key: "VK_RETURN",
+    options: { }
+  },
+  {
+    desc: "Remove focus from header container tag",
+    focused: "root.elt",
+    activedescendant: "header.tagLine",
+    key: "VK_ESCAPE",
+    options: { }
+  },
+  {
+    desc: "Focus on header container tag again",
+    focused: "header.focusableElms.0",
+    activedescendant: "header.tagLine",
+    key: "VK_SPACE",
+    options: { }
+  },
+  {
+    desc: "Focus on header id attribute",
+    focused: "header.focusableElms.1",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Focus on header class attribute",
+    focused: "header.focusableElms.2",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Focus on header new attribute",
+    focused: "header.focusableElms.3",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Circle back and focus on header tag again",
+    focused: "header.focusableElms.0",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Circle back and focus on header new attribute again",
+    focused: "header.focusableElms.3",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { shiftKey: true }
+  },
+  {
+    desc: "Tab back and focus on header class attribute",
+    focused: "header.focusableElms.2",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { shiftKey: true }
+  },
+  {
+    desc: "Tab back and focus on header id attribute",
+    focused: "header.focusableElms.1",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { shiftKey: true }
+  },
+  {
+    desc: "Tab back and focus on header tag",
+    focused: "header.focusableElms.0",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { shiftKey: true }
+  },
+  {
+    desc: "Expand header container, ensure that focus is still on header tag",
+    focused: "header.focusableElms.0",
+    activedescendant: "header.tagLine",
+    key: "VK_RIGHT",
+    options: { },
+    waitFor: "expanded"
+  },
+  {
+    desc: "Activate header tag editor",
+    focused: "header.editor.tag.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_RETURN",
+    options: { }
+  },
+  {
+    desc: "Activate header id attribute editor",
+    focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Deselect text in header id attribute editor",
+    focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Activate header class attribute editor",
+    focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Deselect text in header class attribute editor",
+    focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Activate header new attribute editor",
+    focused: "header.editor.newAttr.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Circle back and activate header tag editor again",
+    focused: "header.editor.tag.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Circle back and activate header new attribute editor again",
+    focused: "header.editor.newAttr.inplaceEditor.input",
+    activedescendant: "header.tagLine",
+    key: "VK_TAB",
+    options: { shiftKey: true }
+  },
+  {
+    desc: "Exit edit mode and keep focus on header new attribute",
+    focused: "header.focusableElms.3",
+    activedescendant: "header.tagLine",
+    key: "VK_ESCAPE",
+    options: { }
+  },
+  {
+    desc: "Move the selection to body and reset focus to container tree",
+    focused: "docBody",
+    activedescendant: "body.tagLine",
+    key: "VK_UP",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+];
+
+let elms = {};
+let containerID = 0;
+
+add_task(function* () {
+  let { inspector } = yield openInspectorForURL(`data:text/html;charset=utf-8,
+    <h1 id="some-id" class="some-class">foo<span>Child span<span></h1>`);
+  let markup = inspector.markup;
+  let doc = markup.doc;
+  let win = doc.defaultView;
+
+  // Record containers that are created after inspector is initialized to be
+  // useful in testing.
+  inspector.on("container-created", memorizeContainer);
+  registerCleanupFunction(() => {
+    inspector.off("container-created", memorizeContainer);
+  });
+
+  elms.docBody = doc.body;
+  elms.root = markup.getContainer(markup._rootNode);
+  elms.header = yield getContainerForSelector("h1", inspector);
+  elms.body = yield getContainerForSelector("body", inspector);
+
+  // Initial focus is on root element and active descendant should be set on
+  // body tag line.
+  testNavigationState(doc, elms.docBody, elms.body.tagLine);
+
+  // Focus on the tree element.
+  elms.root.elt.focus();
+
+  for (let {desc, waitFor, focused, activedescendant, key, options} of TESTS) {
+    info(desc);
+    let updated;
+    if (waitFor) {
+      updated = waitFor === "inspector-updated" ?
+        inspector.once(waitFor) : markup.once(waitFor);
+    } else {
+      updated = Promise.resolve();
+    }
+
+    EventUtils.synthesizeKey(key, options, win);
+    yield updated;
+    testNavigationState(doc, getElm(focused), getElm(activedescendant));
+  }
+});
+
+// Record all containers that are created dynamically into elms object.
+function memorizeContainer(event, container) {
+  elms[`container-${containerID++}`] = container;
+}
+
+// Parse and lookup an element from elms object based on dotted path.
+function getElm(path) {
+  let segments = path.split(".");
+  return segments.reduce((prev, current) => prev[current], elms);
+}
+
+function testNavigationState(doc, focused, activedescendant) {
+  let id = activedescendant.getAttribute("id");
+  is(doc.activeElement, focused, `Keyboard focus should be set to ${focused}`);
+  is(elms.root.elt.getAttribute("aria-activedescendant"), id,
+    `Active descendant should be set to ${id}`);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_semantics.js
@@ -0,0 +1,100 @@
+/* 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";
+
+// Test that inspector markup view has all expected ARIA properties set and
+// updated.
+
+const TOP_CONTAINER_LEVEL = 3;
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(`
+    data:text/html;charset=utf-8,
+    <h1>foo</h1>
+    <span>bar</span>
+    <ul>
+      <li></li>
+    </ul>`);
+  let markup = inspector.markup;
+  let doc = markup.doc;
+  let win = doc.defaultView;
+
+  let rootElt = markup.getContainer(markup._rootNode).elt;
+  let bodyContainer = yield getContainerForSelector("body", inspector);
+  let spanContainer = yield getContainerForSelector("span", inspector);
+  let headerContainer = yield getContainerForSelector("h1", inspector);
+  let listContainer = yield getContainerForSelector("ul", inspector);
+
+  // Focus on the tree element.
+  rootElt.focus();
+
+  // Test tree related semantics
+  is(rootElt.getAttribute("role"), "tree",
+    "Root container should have tree semantics");
+  is(rootElt.getAttribute("aria-dropeffect"), "none",
+    "By default root container's drop effect should be set to none");
+  is(rootElt.getAttribute("aria-activedescendant"),
+    bodyContainer.tagLine.getAttribute("id"),
+    "Default active descendant should be set to body");
+  is(bodyContainer.tagLine.getAttribute("aria-level"), TOP_CONTAINER_LEVEL - 1,
+    "Body container tagLine should have nested level up to date");
+  [spanContainer, headerContainer, listContainer].forEach(container => {
+    let treeitem = container.tagLine;
+    is(treeitem.getAttribute("role"), "treeitem",
+      "Child container tagLine elements should have tree item semantics");
+    is(treeitem.getAttribute("aria-level"), TOP_CONTAINER_LEVEL,
+      "Child container tagLine should have nested level up to date");
+    is(treeitem.getAttribute("aria-grabbed"), "false",
+      "Child container should be draggable but not grabbed by default");
+    is(container.children.getAttribute("role"), "group",
+      "Container with children should have its children element have group " +
+      "semantics");
+    ok(treeitem.id, "Tree item should have id assigned");
+    if (container.closeTagLine) {
+      is(container.closeTagLine.getAttribute("role"), "presentation",
+        "Ignore closing tag");
+    }
+    if (container.expander) {
+      is(container.expander.getAttribute("role"), "presentation",
+        "Ignore expander");
+    }
+  });
+
+  // Test expanding/expandable semantics
+  ok(!spanContainer.tagLine.hasAttribute("aria-expanded"),
+    "Non expandable tree items should not have aria-expanded attribute");
+  ok(!headerContainer.tagLine.hasAttribute("aria-expanded"),
+    "Non expandable tree items should not have aria-expanded attribute");
+  is(listContainer.tagLine.getAttribute("aria-expanded"), "false",
+    "Closed tree item should have aria-expanded unset");
+
+  info("Selecting and expanding list container");
+  let updated = waitForMultipleChildrenUpdates(inspector);
+  yield selectNode("ul", inspector);
+  EventUtils.synthesizeKey("VK_RIGHT", {}, win);
+  yield updated;
+
+  is(rootElt.getAttribute("aria-activedescendant"),
+    listContainer.tagLine.getAttribute("id"),
+    "Active descendant should not be set to list container tagLine");
+  is(listContainer.tagLine.getAttribute("aria-expanded"), "true",
+    "Open tree item should have aria-expanded set");
+  let listItemContainer = yield getContainerForSelector("li", inspector);
+  is(listItemContainer.tagLine.getAttribute("aria-level"),
+    TOP_CONTAINER_LEVEL + 1,
+    "Grand child container tagLine should have nested level up to date");
+  is(listItemContainer.children.getAttribute("role"), "presentation",
+    "Container with no children should have its children element ignored by " +
+    "accessibility");
+
+  info("Collapsing list container");
+  updated = waitForMultipleChildrenUpdates(inspector);
+  EventUtils.synthesizeKey("VK_LEFT", {}, win);
+  yield updated;
+
+  is(listContainer.tagLine.getAttribute("aria-expanded"), "false",
+    "Closed tree item should have aria-expanded unset");
+});
+
--- a/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js
@@ -9,17 +9,17 @@ requestLongerTimeout(2);
 // Tests tabbing through attributes on a node
 
 const TEST_URL = "data:text/html;charset=utf8,<div id='test' a b c d e></div>";
 
 add_task(function* () {
   let {inspector} = yield openInspectorForURL(TEST_URL);
 
   info("Focusing the tag editor of the test element");
-  let {editor} = yield getContainerForSelector("div", inspector);
+  let {editor} = yield focusNode("div", inspector);
   editor.tag.focus();
 
   info("Pressing tab and expecting to focus the ID attribute, always first");
   EventUtils.sendKey("tab", inspector.panelWin);
   checkFocusedAttribute("id");
 
   info("Hit enter to turn the attribute to edit mode");
   EventUtils.sendKey("return", inspector.panelWin);
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js
@@ -9,17 +9,17 @@
 const TEST_URL = `data:text/html,
                   <div id='test-div'>Test modifying my ID attribute</div>`;
 
 add_task(function* () {
   info("Opening the inspector on the test page");
   let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Selecting the test node");
-  yield selectNode("#test-div", inspector);
+  yield focusNode("#test-div", inspector);
 
   info("Verify attributes, only ID should be there for now");
   yield assertAttributes("#test-div", {
     id: "test-div"
   }, testActor);
 
   info("Focus the ID attribute and change its content");
   let {editor} = yield getContainerForSelector("#test-div", inspector);
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js
@@ -10,17 +10,17 @@ const TEST_URL = `data:text/html;charset
                   <div id='retag-me'><div id='retag-me-2'></div></div>`;
 
 add_task(function* () {
   let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   yield inspector.markup.expandAll();
 
   info("Selecting the test node");
-  yield selectNode("#retag-me", inspector);
+  yield focusNode("#retag-me", inspector);
 
   info("Getting the markup-container for the test node");
   let container = yield getContainerForSelector("#retag-me", inspector);
   ok(container.expanded, "The container is expanded");
 
   let parentInfo = yield testActor.getNodeInfo("#retag-me");
   is(parentInfo.tagName.toLowerCase(), "div",
      "We've got #retag-me element, it's a DIV");
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js
@@ -32,17 +32,17 @@ function* testCollapsedLongAttribute(ins
   yield onMutated;
 
   yield assertAttributes("#node24", {
     id: "node24",
     "class": "",
     "data-long": LONG_ATTRIBUTE
   }, testActor);
 
-  let {editor} = yield getContainerForSelector("#node24", inspector);
+  let {editor} = yield focusNode("#node24", inspector);
   let attr = editor.attrElements.get("data-long").querySelector(".editable");
 
   // Check to make sure it has expanded after focus
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
   let input = inplaceEditor(attr).input;
   is(input.value, `data-long="${LONG_ATTRIBUTE}"`);
   EventUtils.sendKey("escape", inspector.panelWin);
@@ -66,17 +66,17 @@ function* testModifyInlineStyleWithQuote
   info("Modify inline style containing \"");
 
   yield assertAttributes("#node26", {
     id: "node26",
     style: 'background-image: url("moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F");'
   }, testActor);
 
   let onMutated = inspector.once("markupmutation");
-  let {editor} = yield getContainerForSelector("#node26", inspector);
+  let {editor} = yield focusNode("#node26", inspector);
   let attr = editor.attrElements.get("style").querySelector(".editable");
 
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   let input = inplaceEditor(attr).input;
   let value = input.value;
 
@@ -102,17 +102,17 @@ function* testEditingAttributeWithMixedQ
   info("Modify class containing \" and \'");
 
   yield assertAttributes("#node27", {
     "id": "node27",
     "class": 'Double " and single \''
   }, testActor);
 
   let onMutated = inspector.once("markupmutation");
-  let {editor} = yield getContainerForSelector("#node27", inspector);
+  let {editor} = yield focusNode("#node27", inspector);
   let attr = editor.attrElements.get("class").querySelector(".editable");
 
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   let input = inplaceEditor(attr).input;
   let value = input.value;
 
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js
@@ -21,17 +21,17 @@ add_task(function* () {
 function* testWellformedMixedCase(inspector, testActor) {
   info("Modifying a mixed-case attribute, " +
     "expecting the attribute's case to be preserved");
 
   info("Listening to markup mutations");
   let onMutated = inspector.once("markupmutation");
 
   info("Focusing the viewBox attribute editor");
-  let {editor} = yield getContainerForSelector("svg", inspector);
+  let {editor} = yield focusNode("svg", inspector);
   let attr = editor.attrElements.get("viewBox").querySelector(".editable");
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   info("Editing the attribute value and waiting for the mutation event");
   let input = inplaceEditor(attr).input;
   input.value = "viewBox=\"0 0 1 1\"";
   EventUtils.sendKey("return", inspector.panelWin);
@@ -47,17 +47,17 @@ function* testWellformedMixedCase(inspec
 function* testMalformedMixedCase(inspector, testActor) {
   info("Modifying a malformed, mixed-case attribute, " +
     "expecting the attribute's case to be preserved");
 
   info("Listening to markup mutations");
   let onMutated = inspector.once("markupmutation");
 
   info("Focusing the viewBox attribute editor");
-  let {editor} = yield getContainerForSelector("svg", inspector);
+  let {editor} = yield focusNode("svg", inspector);
   let attr = editor.attrElements.get("viewBox").querySelector(".editable");
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   info("Editing the attribute value and waiting for the mutation event");
   let input = inplaceEditor(attr).input;
   input.value = "viewBox=\"<>\"";
   EventUtils.sendKey("return", inspector.panelWin);
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js
@@ -6,20 +6,19 @@
 
 // Tests that invalid tagname updates are handled correctly
 
 const TEST_URL = "data:text/html;charset=utf-8,<div></div>";
 
 add_task(function* () {
   let {inspector} = yield openInspectorForURL(TEST_URL);
   yield inspector.markup.expandAll();
-  yield selectNode("div", inspector);
 
   info("Updating the DIV tagname to an invalid value");
-  let container = yield getContainerForSelector("div", inspector);
+  let container = yield focusNode("div", inspector);
   let onCancelReselect = inspector.markup.once("canceledreselectonremoved");
   let tagEditor = container.editor.tag;
   setEditableFieldValue(tagEditor, "<<<", inspector);
   yield onCancelReselect;
   ok(true, "The markup-view emitted the canceledreselectonremoved event");
   is(inspector.selection.nodeFront, container.node,
      "The test DIV is still selected");
 
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js
@@ -15,24 +15,24 @@ add_task(function* () {
   let {inspector} = yield openInspectorForURL(TEST_URL);
 
   // Overriding the editTagName walkerActor method here to check that it isn't
   // called when blurring the tagname field.
   inspector.walker.editTagName = function () {
     isEditTagNameCalled = true;
   };
 
-  yield selectNode("div", inspector);
-  let container = yield getContainerForSelector("div", inspector);
+  let container = yield focusNode("div", inspector);
   let tagEditor = container.editor.tag;
 
   info("Blurring the tagname field");
   tagEditor.blur();
   is(isEditTagNameCalled, false, "The editTagName method wasn't called");
 
   info("Updating the tagname to uppercase");
+  yield focusNode("div", inspector);
   setEditableFieldValue(tagEditor, "DIV", inspector);
   is(isEditTagNameCalled, false, "The editTagName method wasn't called");
 
   info("Updating the tagname to a different value");
   setEditableFieldValue(tagEditor, "SPAN", inspector);
   is(isEditTagNameCalled, true, "The editTagName method was called");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js
@@ -84,15 +84,15 @@ function* editAttributeAndTab(newValue, 
   yield onEditMutation;
 }
 
 /**
  * Given a markup container, focus and turn in edit mode its first attribute
  * field.
  */
 function* activateFirstAttribute(container, inspector) {
-  let {editor} = yield getContainerForSelector(container, inspector);
+  let {editor} = yield focusNode(container, inspector);
   editor.tag.focus();
 
   // Go to "id" attribute and trigger edit mode.
   EventUtils.sendKey("tab", inspector.panelWin);
   EventUtils.sendKey("return", inspector.panelWin);
 }
--- a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js
@@ -48,17 +48,17 @@ function* getNodeValue(selector, testAct
 
 function* editContainer(inspector, testActor,
                         {selector, newValue, oldValue, shortValue}) {
   let nodeValue = yield getNodeValue(selector, testActor);
   is(nodeValue, oldValue, "The test node's text content is correct");
 
   info("Changing the text content");
   let onMutated = inspector.once("markupmutation");
-  let container = yield getContainerForSelector(selector, inspector);
+  let container = yield focusNode(selector, inspector);
   let field = container.elt.querySelector("pre");
 
   if (shortValue) {
     is(oldValue.indexOf(
        field.textContent.substring(0, field.textContent.length - 1)),
        0,
        "The shortened value starts with the full value " + field.textContent);
     ok(oldValue.length > field.textContent.length,
--- a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_02.js
@@ -17,18 +17,17 @@ add_task(function* () {
   yield inspector.markup.expandAll();
   yield waitForMultipleChildrenUpdates(inspector);
 
   let nodeValue = yield getNodeValue(SELECTOR, testActor);
   let expectedValue = "line6";
   is(nodeValue, expectedValue, "The test node's text content is correct");
 
   info("Open editable field for .node6");
-  let nodeFront = yield getNodeFront(SELECTOR, inspector);
-  let container = getContainerForNodeFront(nodeFront, inspector);
+  let container = yield focusNode(SELECTOR, inspector);
   let field = container.elt.querySelector("pre");
   field.focus();
   EventUtils.sendKey("return", inspector.panelWin);
   let editor = inplaceEditor(field);
 
   info("Initially, all the input content should be selected");
   checkSelectionPositions(editor, 0, expectedValue.length);
 
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -155,17 +155,17 @@ function setEditableFieldValue(field, va
  * @param {String} text The new attribute text to be entered (e.g. "id='test'")
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @return a promise that resolves when the node has mutated
  */
 var addNewAttributes = Task.async(function* (selector, text, inspector) {
   info(`Entering text "${text}" in new attribute field for node ${selector}`);
 
-  let container = yield getContainerForSelector(selector, inspector);
+  let container = yield focusNode(selector, inspector);
   ok(container, "The container for '" + selector + "' was found");
 
   info("Listening for the markupmutation event");
   let nodeMutated = inspector.once("markupmutation");
   setEditableFieldValue(container.editor.newAttr, text, inspector);
   yield nodeMutated;
 });
 
--- a/devtools/client/inspector/markup/test/helper_attributes_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_attributes_test_runner.js
@@ -130,17 +130,17 @@ function* runEditAttributesTest(test, in
   info("Selecting the test node " + test.node);
   yield selectNode(test.node, inspector);
 
   info("Asserting that the node has the right attributes to start with");
   yield assertAttributes(test.node, test.originalAttributes, testActor);
 
   info("Editing attribute " + test.name + " with value " + test.value);
 
-  let container = yield getContainerForSelector(test.node, inspector);
+  let container = yield focusNode(test.node, inspector);
   ok(container && container.editor, "The markup-container for " + test.node +
     " was found");
 
   info("Listening for the markupmutation event");
   let nodeMutated = inspector.once("markupmutation");
   let attr = container.editor.attrElements.get(test.name)
                                           .querySelector(".editable");
   setEditableFieldValue(attr, test.value, inspector);
--- a/devtools/client/inspector/markup/test/helper_style_attr_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_style_attr_test_runner.js
@@ -26,18 +26,17 @@
  *        Array of arrays representing the characters to type for the new
  *        attribute as well as the expected state at each step
  */
 function* runStyleAttributeAutocompleteTests(inspector, testData) {
   info("Expand all markup nodes");
   yield inspector.markup.expandAll();
 
   info("Select #node14");
-  let nodeFront = yield getNodeFront("#node14", inspector);
-  let container = getContainerForNodeFront(nodeFront, inspector);
+  let container = yield focusNode("#node14", inspector);
 
   info("Focus and open the new attribute inplace-editor");
   let attr = container.editor.newAttr;
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
   let editor = inplaceEditor(attr);
 
   for (let i = 0; i < testData.length; i++) {
--- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
@@ -13,18 +13,18 @@
 //    modifers,
 //    expected input box value after keypress,
 //    selectedIndex of the popup,
 //    total items in the popup,
 //    expect ruleview-changed
 //  ]
 var testData = [
   ["d", {}, "display", 1, 3, false],
-  ["VK_TAB", {}, "", -1, 41, true],
-  ["VK_DOWN", {}, "block", 0, 41, true],
+  ["VK_TAB", {}, "", -1, 43, true],
+  ["VK_DOWN", {}, "block", 0, 43, true],
   ["n", {}, "none", -1, 0, true],
   ["VK_TAB", {shiftKey: true}, "display", -1, 0, true],
   ["VK_BACK_SPACE", {}, "", -1, 0, false],
   ["o", {}, "overflow", 13, 16, false],
   ["u", {}, "outline", 0, 5, false],
   ["VK_DOWN", {}, "outline-color", 1, 5, false],
   ["VK_TAB", {}, "none", -1, 0, true],
   ["r", {}, "rebeccapurple", 0, 6, true],
--- a/devtools/client/inspector/test/browser_inspector_addNode_03.js
+++ b/devtools/client/inspector/test/browser_inspector_addNode_03.js
@@ -1,18 +1,19 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that adding nodes does work as expected: the parent gets expanded, the
-// new node gets selected and the corresponding markup-container focused.
+// new node gets selected.
 
 const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
+const PARENT_TREE_LEVEL = 3;
 
 add_task(function* () {
   let {inspector} = yield openInspectorForURL(TEST_URL);
 
   info("Adding in element that has no children and is collapsed");
   let parentNode = yield getNodeFront("#foo", inspector);
   yield selectNode(parentNode, inspector);
   yield testAddNode(parentNode, inspector);
@@ -33,16 +34,20 @@ add_task(function* () {
   parentNode = yield getNodeFront("#bar", inspector);
   yield selectNode(parentNode, inspector);
   yield testAddNode(parentNode, inspector);
 });
 
 function* testAddNode(parentNode, inspector) {
   let btn = inspector.panelDoc.querySelector("#inspector-element-add-button");
   let markupWindow = inspector.markup.win;
+  let parentContainer = inspector.markup.getContainer(parentNode);
+
+  is(parentContainer.tagLine.getAttribute("aria-level"), PARENT_TREE_LEVEL,
+    "Parent level should be up to date.");
 
   info("Clicking 'add node' and expecting a markup mutation and focus event");
   let onMutation = inspector.once("markupmutation");
   btn.click();
   let mutations = yield onMutation;
 
   info("Expecting an inspector-updated event right after the mutation event " +
        "to wait for the new node selection");
@@ -51,26 +56,29 @@ function* testAddNode(parentNode, inspec
   is(mutations.length, 1, "There is one mutation only");
   is(mutations[0].added.length, 1, "There is one new node only");
 
   let newNode = mutations[0].added[0];
 
   is(newNode, inspector.selection.nodeFront,
      "The new node is selected");
 
-  ok(inspector.markup.getContainer(parentNode).expanded,
-     "The parent node is now expanded");
+  ok(parentContainer.expanded, "The parent node is now expanded");
 
   is(inspector.selection.nodeFront.parentNode(), parentNode,
      "The new node is inside the right parent");
 
   let focusedElement = markupWindow.document.activeElement;
-  let focusedContainer = focusedElement.closest(".child").container;
-  is(focusedContainer.node, inspector.selection.nodeFront,
-     "The right container is focused in the markup-view");
-  ok(focusedElement.classList.contains("tag"),
-     "The tagName part of the container is focused");
+  let focusedContainer = focusedElement.container;
+  let selectedContainer = inspector.markup._selectedContainer;
+  is(selectedContainer.tagLine.getAttribute("aria-level"),
+    PARENT_TREE_LEVEL + 1, "Added container level should be up to date.");
+  is(selectedContainer.node, inspector.selection.nodeFront,
+     "The right container is selected in the markup-view");
+  ok(selectedContainer.selected, "Selected container is set to selected");
+  is(focusedContainer.toString(), "[root container]",
+    "Root container is focused");
 }
 
 function collapseNode(node, inspector) {
   let container = inspector.markup.getContainer(node);
   container.setExpanded(false);
 }
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -135,16 +135,32 @@ var selectNode = Task.async(function* (s
   info("Selecting the node for '" + selector + "'");
   let nodeFront = yield getNodeFront(selector, inspector);
   let updated = inspector.once("inspector-updated");
   inspector.selection.setNodeFront(nodeFront, reason);
   yield updated;
 });
 
 /**
+ * Select node for a given selector, make it focusable and set focus in its
+ * container element.
+ * @param {String|NodeFront} selector
+ * @param {InspectorPanel} inspector The current inspector-panel instance.
+ * @return {MarkupContainer}
+ */
+function* focusNode(selector, inspector) {
+  getContainerForNodeFront(inspector.walker.rootNode, inspector).elt.focus();
+  let nodeFront = yield getNodeFront(selector, inspector);
+  let container = getContainerForNodeFront(nodeFront, inspector);
+  yield selectNode(nodeFront, inspector);
+  EventUtils.sendKey("return", inspector.panelWin);
+  return container;
+}
+
+/**
  * Set the inspector's current selection to null so that no node is selected
  *
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
  * @return a promise that resolves when the inspector is updated
  */
 function clearCurrentNodeSelection(inspector) {
   info("Clearing the current selection");
--- a/devtools/client/shared/inplace-editor.js
+++ b/devtools/client/shared/inplace-editor.js
@@ -186,16 +186,19 @@ function editableItem(options, callback)
 
   // Mark the element editable field for tab
   // navigation while editing.
   element._editable = true;
 
   // Save the trigger type so we can dispatch this later
   element._trigger = trigger;
 
+  // Add button semantics to the element, to indicate that it can be activated.
+  element.setAttribute("role", "button");
+
   return function turnOnEditMode() {
     callback(element);
   };
 }
 
 exports.editableItem = editableItem;
 
 /*
--- a/devtools/client/shared/test/browser_inplace-editor-01.js
+++ b/devtools/client/shared/test/browser_inplace-editor-01.js
@@ -146,16 +146,18 @@ function onDone(value, isCommit, def) {
 }
 
 function createInplaceEditorAndClick(options, doc) {
   doc.body.innerHTML = "";
   let span = options.element = createSpan(doc);
 
   info("Creating an inplace-editor field");
   editableField(options);
+  is(span.getAttribute("role"), "button",
+    "Editable element should have button semantics");
 
   info("Clicking on the inplace-editor field to turn to edit mode");
   span.click();
 }
 
 function createSpan(doc) {
   info("Creating a new span element");
   let span = doc.createElement("span");
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -168,17 +168,17 @@ ul.children + .tag-line::before {
   display: inline-block;
   margin-left: -14px;
   vertical-align: middle;
   /* Make sure the expander still appears above the tag-state */
   position: relative;
   z-index: 1;
 }
 
-.child.collapsed .child {
+.child.collapsed .child, .child.collapsed .children {
   display: none;
 }
 
 .child > .tag-line:first-child .close {
   display: none;
 }
 
 .child.collapsed > .tag-line:first-child .close {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3302,21 +3302,22 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
       SetAllowImages(value);
     }
     SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
     if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
       SetAllowWindowControl(value);
     }
     SetAllowContentRetargeting(mAllowContentRetargeting &&
       parentAsDocShell->GetAllowContentRetargetingOnChildren());
+    if (parentAsDocShell->GetIsPrerendered()) {
+      SetIsPrerendered();
+    }
     if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
-      SetIsActive(value);
-    }
-    if (parentAsDocShell->GetIsPrerendered()) {
-      SetIsPrerendered(true);
+      // a prerendered docshell is not active yet
+      SetIsActive(value && !mIsPrerendered);
     }
     if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
         !customUserAgent.IsEmpty()) {
       SetCustomUserAgent(customUserAgent);
     }
     if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
       value = false;
     }
@@ -6087,16 +6088,19 @@ nsDocShell::SetIsActiveInternal(bool aIs
   // We disallow setting active on chrome docshells.
   if (mItemType == nsIDocShellTreeItem::typeChrome) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // Keep track ourselves.
   mIsActive = aIsActive;
 
+  // Clear prerender flag if necessary.
+  mIsPrerendered &= !aIsActive;
+
   // Tell the PresShell about it.
   nsCOMPtr<nsIPresShell> pshell = GetPresShell();
   if (pshell) {
     pshell->SetIsActive(aIsActive, aIsHidden);
   }
 
   // Tell the window about it
   if (mScriptGlobal) {
@@ -6152,21 +6156,22 @@ nsDocShell::SetIsActiveInternal(bool aIs
 NS_IMETHODIMP
 nsDocShell::GetIsActive(bool* aIsActive)
 {
   *aIsActive = mIsActive;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::SetIsPrerendered(bool aPrerendered)
-{
-  MOZ_ASSERT(!aPrerendered || !mIsPrerendered,
-             "SetIsPrerendered(true) called on already prerendered docshell");
-  mIsPrerendered = aPrerendered;
+nsDocShell::SetIsPrerendered()
+{
+  MOZ_ASSERT(!mIsPrerendered,
+             "SetIsPrerendered() called on already prerendered docshell");
+  SetIsActive(false);
+  mIsPrerendered = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsPrerendered(bool* aIsPrerendered)
 {
   *aIsPrerendered = mIsPrerendered;
   return NS_OK;
@@ -7756,16 +7761,26 @@ nsDocShell::EndPageLoad(nsIWebProgress* 
             bool sameURI = false;
             url->Equals(newURI, &sameURI);
             if (!sameURI) {
               // Keyword lookup made a new URI so no need to try
               // an alternate one.
               doCreateAlternate = false;
             }
           }
+
+          if (doCreateAlternate) {
+            // Skip doing this if our channel was redirected, because we
+            // shouldn't be guessing things about the post-redirect URI.
+            nsLoadFlags loadFlags = 0;
+            if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) ||
+                (loadFlags & nsIChannel::LOAD_REPLACE)) {
+              doCreateAlternate = false;
+            }
+          }
         }
         if (doCreateAlternate) {
           newURI = nullptr;
           newPostData = nullptr;
           keywordProviderName.Truncate();
           keywordAsSent.Truncate();
           sURIFixup->CreateFixupURI(oldSpec,
                                     nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
@@ -13426,16 +13441,34 @@ nsDocShell::DoCommand(const char* aComma
   rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
   if (controller) {
     rv = controller->DoCommand(aCommand);
   }
 
   return rv;
 }
 
+NS_IMETHODIMP
+nsDocShell::DoCommandWithParams(const char* aCommand, nsICommandParams* aParams)
+{
+  nsCOMPtr<nsIController> controller;
+  nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsICommandController> commandController =
+    do_QueryInterface(controller, &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return commandController->DoCommandWithParams(aCommand, aParams);
+}
+
 nsresult
 nsDocShell::EnsureCommandHandler()
 {
   if (!mCommandManager) {
     nsCOMPtr<nsPICommandUpdater> commandUpdater =
       do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
     if (!commandUpdater) {
       return NS_ERROR_OUT_OF_MEMORY;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -38,16 +38,17 @@ interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 interface nsITabChild;
 interface nsICommandManager;
+interface nsICommandParams;
 native TabChildRef(already_AddRefed<nsITabChild>);
 
 typedef unsigned long nsLoadFlags;
 
 [scriptable, builtinclass, uuid(049234fe-da10-478b-bc5d-bc6f9a1ba63d)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
@@ -642,17 +643,21 @@ interface nsIDocShell : nsIDocShellTreeI
    * not discard its layers
    */
   void setIsActiveAndForeground(in boolean aIsActive);
 
   /**
    * Puts the docshell in prerendering mode. noscript because we want only
    * native code to be able to put a docshell in prerendering.
    */
-  [noscript] void SetIsPrerendered(in boolean prerendered);
+  [noscript] void SetIsPrerendered();
+
+  /**
+   * Whether this docshell is in prerender mode.
+   */
   [infallible] readonly attribute boolean isPrerendered;
 
   /**
    * The ID of the docshell in the session history.
    */
   readonly attribute unsigned long long historyID;
 
   /**
@@ -1010,16 +1015,17 @@ interface nsIDocShell : nsIDocShellTreeI
 
   /**
     * Cherry picked parts of nsIController.
     * They are here, because we want to call these functions
     * from JS.
     */
   boolean isCommandEnabled(in string command);
   void doCommand(in string command);
+  void doCommandWithParams(in string command, in nsICommandParams aParams);
 
   /**
    * Invisible DocShell are dummy construct to simulate DOM windows
    * without any actual visual representation. They have to be marked
    * at construction time, to avoid any painting activity.
    */
   [noscript, notxpcom] bool IsInvisible();
   [noscript, notxpcom] void SetInvisible(in bool aIsInvisibleDochsell);
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -71,16 +71,19 @@ skip-if = buildapp == 'mulet'
 [browser_bug554155.js]
 [browser_bug655270.js]
 [browser_bug655273.js]
 [browser_bug670318.js]
 [browser_bug673467.js]
 [browser_bug852909.js]
 [browser_bug92473.js]
 [browser_uriFixupIntegration.js]
+[browser_uriFixupAlternateRedirects.js]
+support-files =
+  redirect_to_example.sjs
 [browser_loadDisallowInherit.js]
 [browser_loadURI.js]
 [browser_multiple_pushState.js]
 [browser_onbeforeunload_navigation.js]
 [browser_search_notification.js]
 [browser_ua_emulation.js]
 [browser_timelineMarkers-01.js]
 [browser_timelineMarkers-02.js]
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_uriFixupAlternateRedirects.js
@@ -0,0 +1,24 @@
+"use strict";
+
+const REDIRECTURL = "http://www.example.com/browser/docshell/test/browser/redirect_to_example.sjs"
+
+add_task(function* () {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+  gURLBar.value = REDIRECTURL;
+  gURLBar.select();
+  let errorPageLoaded = BrowserTestUtils.waitForErrorPage(tab.linkedBrowser);
+  EventUtils.sendKey("return");
+  yield errorPageLoaded;
+  let [contentURL, originalURL] = yield ContentTask.spawn(tab.linkedBrowser, null, () => {
+    return [
+      content.document.documentURI,
+      content.document.mozDocumentURIIfNotForErrorPages.spec,
+    ];
+  });
+  info("Page that loaded: " + contentURL);
+  ok(contentURL.startsWith("about:neterror?"), "Should be on an error page");
+  originalURL = new URL(originalURL);
+  is(originalURL.host, "example", "Should be an error for http://example, not http://www.example.com/");
+
+  yield BrowserTestUtils.removeTab(tab);
+});
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/redirect_to_example.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+  response.setStatusLine(request.httpVersion, 302, "Moved Permanently");
+  response.setHeader("Location", "http://example");
+}
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -93,21 +93,16 @@ Animation::Constructor(const GlobalObjec
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Animation> animation = new Animation(global);
 
   if (!aEffect) {
     // Bug 1049975: We do not support null effect yet.
     aRv.Throw(NS_ERROR_DOM_ANIM_NO_EFFECT_ERR);
     return nullptr;
   }
-  if (!aTimeline) {
-    // Bug 1096776: We do not support null timeline yet.
-    aRv.Throw(NS_ERROR_DOM_ANIM_NO_TIMELINE_ERR);
-    return nullptr;
-  }
 
   animation->SetTimeline(aTimeline);
   animation->SetEffect(aEffect);
 
   return animation.forget();
 }
 
 void
--- a/dom/animation/AnimationPerformanceWarning.cpp
+++ b/dom/animation/AnimationPerformanceWarning.cpp
@@ -33,42 +33,42 @@ AnimationPerformanceWarning::ToLocalized
   const char* key = nullptr;
 
   switch (mType) {
     case Type::ContentTooSmall:
       MOZ_ASSERT(mParams && mParams->Length() == 2,
                  "Parameter's length should be 2 for ContentTooSmall");
 
       return NS_SUCCEEDED(
-        ToLocalizedStringWithIntParams<2>("AnimationWarningContentTooSmall",
-                                          aLocalizedString));
+        ToLocalizedStringWithIntParams<2>(
+          "CompositorAnimationWarningContentTooSmall", aLocalizedString));
     case Type::ContentTooLarge:
       MOZ_ASSERT(mParams && mParams->Length() == 7,
                  "Parameter's length should be 7 for ContentTooLarge");
 
       return NS_SUCCEEDED(
-        ToLocalizedStringWithIntParams<7>("AnimationWarningContentTooLarge",
-                                          aLocalizedString));
+        ToLocalizedStringWithIntParams<7>(
+          "CompositorAnimationWarningContentTooLarge", aLocalizedString));
     case Type::TransformBackfaceVisibilityHidden:
-      key = "AnimationWarningTransformBackfaceVisibilityHidden";
+      key = "CompositorAnimationWarningTransformBackfaceVisibilityHidden";
       break;
     case Type::TransformPreserve3D:
-      key = "AnimationWarningTransformPreserve3D";
+      key = "CompositorAnimationWarningTransformPreserve3D";
       break;
     case Type::TransformSVG:
-      key = "AnimationWarningTransformSVG";
+      key = "CompositorAnimationWarningTransformSVG";
       break;
     case Type::TransformWithGeometricProperties:
-      key = "AnimationWarningTransformWithGeometricProperties";
+      key = "CompositorAnimationWarningTransformWithGeometricProperties";
       break;
     case Type::TransformFrameInactive:
-      key = "AnimationWarningTransformFrameInactive";
+      key = "CompositorAnimationWarningTransformFrameInactive";
       break;
     case Type::OpacityFrameInactive:
-      key = "AnimationWarningOpacityFrameInactive";
+      key = "CompositorAnimationWarningOpacityFrameInactive";
       break;
   }
 
   nsresult rv =
     nsContentUtils::GetLocalizedString(nsContentUtils::eLAYOUT_PROPERTIES,
                                        key, aLocalizedString);
   return NS_SUCCEEDED(rv);
 }
--- a/dom/animation/AnimationUtils.cpp
+++ b/dom/animation/AnimationUtils.cpp
@@ -8,16 +8,17 @@
 
 #include "nsDebug.h"
 #include "nsIAtom.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsGlobalWindow.h"
 #include "nsString.h"
 #include "xpcpublic.h" // For xpc::NativeGlobal
+#include "mozilla/Preferences.h"
 
 namespace mozilla {
 
 /* static */ void
 AnimationUtils::LogAsyncAnimationFailure(nsCString& aMessage,
                                          const nsIContent* aContent)
 {
   if (aContent) {
@@ -41,9 +42,24 @@ AnimationUtils::GetCurrentRealmDocument(
 {
   nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx);
   if (!win) {
     return nullptr;
   }
   return win->GetDoc();
 }
 
+/* static */ bool
+AnimationUtils::IsOffscreenThrottlingEnabled()
+{
+  static bool sOffscreenThrottlingEnabled;
+  static bool sPrefCached = false;
+
+  if (!sPrefCached) {
+    sPrefCached = true;
+    Preferences::AddBoolVarCache(&sOffscreenThrottlingEnabled,
+                                 "dom.animations.offscreen-throttling");
+  }
+
+  return sOffscreenThrottlingEnabled;
+}
+
 } // namespace mozilla
--- a/dom/animation/AnimationUtils.h
+++ b/dom/animation/AnimationUtils.h
@@ -49,13 +49,19 @@ public:
   static void LogAsyncAnimationFailure(nsCString& aMessage,
                                        const nsIContent* aContent = nullptr);
 
   /**
    * Get the document from the JS context to use when parsing CSS properties.
    */
   static nsIDocument*
   GetCurrentRealmDocument(JSContext* aCx);
+
+  /**
+   * Checks if offscreen animation throttling is enabled.
+   */
+  static bool
+  IsOffscreenThrottlingEnabled();
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "Layers.h" // For Layer
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
 #include "nsCSSPropertySet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
+#include "nsIPresShell.h" // For nsIPresShell
 
 namespace mozilla {
 
 // Helper functions for generating a ComputedTimingProperties dictionary
 static void
 GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
                             const Nullable<TimeDuration>& aLocalTime,
                             const TimingParams& aTiming,
@@ -86,16 +87,17 @@ KeyframeEffectReadOnly::KeyframeEffectRe
 KeyframeEffectReadOnly::KeyframeEffectReadOnly(
   nsIDocument* aDocument,
   const Maybe<OwningAnimationTarget>& aTarget,
   AnimationEffectTimingReadOnly* aTiming)
   : AnimationEffectReadOnly(aDocument)
   , mTarget(aTarget)
   , mTiming(aTiming)
   , mInEffectOnLastAnimationTimingUpdate(false)
+  , mCumulativeChangeHint(nsChangeHint(0))
 {
   MOZ_ASSERT(aTiming);
 }
 
 JSObject*
 KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto)
 {
@@ -538,16 +540,18 @@ KeyframeEffectReadOnly::UpdateProperties
 
   for (AnimationProperty& property : mProperties) {
     property.mWinsInCascade =
       winningInCascadeProperties.HasProperty(property.mProperty);
     property.mIsRunningOnCompositor =
       runningOnCompositorProperties.HasProperty(property.mProperty);
   }
 
+  CalculateCumulativeChangeHint();
+
   if (mTarget) {
     EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
                                                    mTarget->mPseudoType);
     if (effectSet) {
       effectSet->MarkCascadeNeedsUpdate();
     }
 
     RequestRestyle(EffectCompositor::RestyleType::Layer);
@@ -1057,16 +1061,26 @@ KeyframeEffectReadOnly::CanThrottle() co
     // a) No target element
     // b) The target element has no frame, e.g. because it is in a display:none
     //    subtree.
     // In either case we can throttle the animation because there is no
     // need to update on the main thread.
     return true;
   }
 
+  // We can throttle the animation if the animation is paint only and
+  // the target frame is out of view or the document is in background tabs.
+  if (CanIgnoreIfNotVisible()) {
+    nsIPresShell* presShell = GetPresShell();
+    if ((presShell && !presShell->IsActive()) ||
+        frame->IsScrolledOutOfView()) {
+      return true;
+    }
+  }
+
   // First we need to check layer generation and transform overflow
   // prior to the property.mIsRunningOnCompositor check because we should
   // occasionally unthrottle these animations even if the animations are
   // already running on compositor.
   for (const LayerAnimationInfo::Record& record :
         LayerAnimationInfo::sRecords) {
     // Skip properties that are overridden in the cascade.
     // (GetAnimationOfProperty, as called by HasAnimationOfProperty,
@@ -1187,24 +1201,30 @@ nsIDocument*
 KeyframeEffectReadOnly::GetRenderedDocument() const
 {
   if (!mTarget) {
     return nullptr;
   }
   return mTarget->mElement->GetComposedDoc();
 }
 
-nsPresContext*
-KeyframeEffectReadOnly::GetPresContext() const
+nsIPresShell*
+KeyframeEffectReadOnly::GetPresShell() const
 {
   nsIDocument* doc = GetRenderedDocument();
   if (!doc) {
     return nullptr;
   }
-  nsIPresShell* shell = doc->GetShell();
+  return doc->GetShell();
+}
+
+nsPresContext*
+KeyframeEffectReadOnly::GetPresContext() const
+{
+  nsIPresShell* shell = GetPresShell();
   if (!shell) {
     return nullptr;
   }
   return shell->GetPresContext();
 }
 
 /* static */ bool
 KeyframeEffectReadOnly::IsGeometricProperty(
@@ -1309,16 +1329,41 @@ KeyframeEffectReadOnly::SetPerformanceWa
         nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
       }
       return;
     }
   }
 }
 
+void
+KeyframeEffectReadOnly::CalculateCumulativeChangeHint()
+{
+  mCumulativeChangeHint = nsChangeHint(0);
+
+  for (const AnimationProperty& property : mProperties) {
+    for (const AnimationPropertySegment& segment : property.mSegments) {
+      mCumulativeChangeHint |= segment.mChangeHint;
+    }
+  }
+}
+
+bool
+KeyframeEffectReadOnly::CanIgnoreIfNotVisible() const
+{
+  if (!AnimationUtils::IsOffscreenThrottlingEnabled()) {
+    return false;
+  }
+
+  // FIXME: For further sophisticated optimization we need to check
+  // change hint on the segment corresponding to computedTiming.progress.
+  return NS_IsHintSubset(
+    mCumulativeChangeHint, nsChangeHint_Hints_CanIgnoreIfNotVisible);
+}
+
 //---------------------------------------------------------------------
 //
 // KeyframeEffect
 //
 //---------------------------------------------------------------------
 
 KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
                                const Maybe<OwningAnimationTarget>& aTarget,
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_KeyframeEffect_h
 #define mozilla_dom_KeyframeEffect_h
 
 #include "nsAutoPtr.h"
+#include "nsChangeHint.h"
 #include "nsCSSProperty.h"
 #include "nsCSSValue.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/Attributes.h"
@@ -31,16 +32,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Nullable.h"
 
 struct JSContext;
 class nsCSSPropertySet;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
+class nsIPresShell;
 class nsPresContext;
 
 namespace mozilla {
 
 class AnimValuesStyleRule;
 enum class CSSPseudoElementType : uint8_t;
 
 namespace dom {
@@ -113,16 +115,18 @@ struct Keyframe
 };
 
 struct AnimationPropertySegment
 {
   float mFromKey, mToKey;
   StyleAnimationValue mFromValue, mToValue;
   Maybe<ComputedTimingFunction> mTimingFunction;
 
+  nsChangeHint mChangeHint;
+
   bool operator==(const AnimationPropertySegment& aOther) const {
     return mFromKey == aOther.mFromKey &&
            mToKey == aOther.mToKey &&
            mFromValue == aOther.mFromValue &&
            mToValue == aOther.mToValue &&
            mTimingFunction == aOther.mTimingFunction;
   }
   bool operator!=(const AnimationPropertySegment& aOther) const {
@@ -324,25 +328,36 @@ public:
   // When returning true, |aPerformanceWarning| stores the reason why
   // we shouldn't run the transform animations.
   bool ShouldBlockAsyncTransformAnimations(
     const nsIFrame* aFrame,
     AnimationPerformanceWarning::Type& aPerformanceWarning) const;
 
   nsIDocument* GetRenderedDocument() const;
   nsPresContext* GetPresContext() const;
+  nsIPresShell* GetPresShell() const;
 
   // Associates a warning with the animated property on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(
     nsCSSProperty aProperty,
     const AnimationPerformanceWarning& aWarning);
 
+  // Cumulative change hint on each segment for each property.
+  // This is used for deciding the animation is paint-only.
+  void CalculateCumulativeChangeHint();
+
+  // Returns true if all of animation properties' change hints
+  // can ignore painting if the animation is not visible.
+  // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
+  // in detail which change hint can be ignored.
+  bool CanIgnoreIfNotVisible() const;
+
 protected:
   KeyframeEffectReadOnly(nsIDocument* aDocument,
                          const Maybe<OwningAnimationTarget>& aTarget,
                          AnimationEffectTimingReadOnly* aTiming);
 
   virtual ~KeyframeEffectReadOnly();
 
   template<class KeyframeEffectType, class OptionsType>
@@ -387,16 +402,18 @@ protected:
   // timing function) so we can avoid unnecessary style updates.
   Nullable<double> mProgressOnLastCompose;
 
   // We need to track when we go to or from being "in effect" since
   // we need to re-evaluate the cascade of animations when that changes.
   bool mInEffectOnLastAnimationTimingUpdate;
 
 private:
+  nsChangeHint mCumulativeChangeHint;
+
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottle() const;
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
 
   // Returns true unless Gecko limitations prevent performing transform
   // animations for |aFrame|. When returning true, the reason for the
   // limitation is stored in |aOutPerformanceWarning|.
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -368,17 +368,18 @@ AppendValueAsString(JSContext* aCx,
 static PropertyValuePair
 MakePropertyValuePair(nsCSSProperty aProperty, const nsAString& aStringValue,
                       nsCSSParser& aParser, nsIDocument* aDocument);
 
 static bool
 HasValidOffsets(const nsTArray<Keyframe>& aKeyframes);
 
 static void
-BuildSegmentsFromValueEntries(nsTArray<KeyframeValueEntry>& aEntries,
+BuildSegmentsFromValueEntries(nsStyleContext* aStyleContext,
+                              nsTArray<KeyframeValueEntry>& aEntries,
                               nsTArray<AnimationProperty>& aResult);
 
 static void
 GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
                                            JS::Handle<JS::Value> aValue,
                                            nsTArray<Keyframe>& aResult,
                                            ErrorResult& aRv);
 
@@ -545,17 +546,17 @@ KeyframeUtils::GetAnimationPropertiesFro
         entry->mTimingFunction = frame.mTimingFunction;
 
         propertiesOnThisKeyframe.AddProperty(value.mProperty);
       }
     }
   }
 
   nsTArray<AnimationProperty> result;
-  BuildSegmentsFromValueEntries(entries, result);
+  BuildSegmentsFromValueEntries(aStyleContext, entries, result);
 
   return result;
 }
 
 
 // ------------------------------------------------------------------
 //
 // Internal helpers
@@ -903,22 +904,53 @@ HasValidOffsets(const nsTArray<Keyframe>
         return false;
       }
       offset = thisOffset;
     }
   }
   return true;
 }
 
+static already_AddRefed<nsStyleContext>
+CreateStyleContextForAnimationValue(nsCSSProperty aProperty,
+                                    StyleAnimationValue aValue,
+                                    nsStyleContext* aBaseStyleContext)
+{
+  MOZ_ASSERT(aBaseStyleContext,
+             "CreateStyleContextForAnimationValue needs to be called "
+             "with a valid nsStyleContext");
+
+  RefPtr<AnimValuesStyleRule> styleRule = new AnimValuesStyleRule();
+  styleRule->AddValue(aProperty, aValue);
+
+  nsCOMArray<nsIStyleRule> rules;
+  rules.AppendObject(styleRule);
+
+  MOZ_ASSERT(aBaseStyleContext->PresContext()->StyleSet()->IsGecko(),
+             "ServoStyleSet should not use StyleAnimationValue for animations");
+  nsStyleSet* styleSet =
+    aBaseStyleContext->PresContext()->StyleSet()->AsGecko();
+
+  RefPtr<nsStyleContext> styleContext =
+    styleSet->ResolveStyleByAddingRules(aBaseStyleContext, rules);
+
+  // We need to call StyleData to generate cached data for the style context.
+  // Otherwise CalcStyleDifference returns no meaningful result.
+  styleContext->StyleData(nsCSSProps::kSIDTable[aProperty]);
+
+  return styleContext.forget();
+}
+
 /**
  * Builds an array of AnimationProperty objects to represent the keyframe
  * animation segments in aEntries.
  */
 static void
-BuildSegmentsFromValueEntries(nsTArray<KeyframeValueEntry>& aEntries,
+BuildSegmentsFromValueEntries(nsStyleContext* aStyleContext,
+                              nsTArray<KeyframeValueEntry>& aEntries,
                               nsTArray<AnimationProperty>& aResult)
 {
   if (aEntries.IsEmpty()) {
     return;
   }
 
   // Sort the KeyframeValueEntry objects so that all entries for a given
   // property are together, and the entries are sorted by offset otherwise.
@@ -999,16 +1031,32 @@ BuildSegmentsFromValueEntries(nsTArray<K
     AnimationPropertySegment* segment =
       animationProperty->mSegments.AppendElement();
     segment->mFromKey   = aEntries[i].mOffset;
     segment->mToKey     = aEntries[j].mOffset;
     segment->mFromValue = aEntries[i].mValue;
     segment->mToValue   = aEntries[j].mValue;
     segment->mTimingFunction = aEntries[i].mTimingFunction;
 
+    RefPtr<nsStyleContext> fromContext =
+      CreateStyleContextForAnimationValue(animationProperty->mProperty,
+                                          segment->mFromValue, aStyleContext);
+
+    RefPtr<nsStyleContext> toContext =
+      CreateStyleContextForAnimationValue(animationProperty->mProperty,
+                                          segment->mToValue, aStyleContext);
+
+    uint32_t equalStructs = 0;
+    uint32_t samePointerStructs = 0;
+    segment->mChangeHint =
+        fromContext->CalcStyleDifference(toContext,
+          nsChangeHint(0),
+          &equalStructs,
+          &samePointerStructs);
+
     i = j;
   }
 }
 
 /**
  * Converts a JS object representing a property-indexed keyframe into
  * an array of Keyframe objects.
  *
--- a/dom/animation/test/chrome/test_animation_performance_warning.html
+++ b/dom/animation/test/chrome/test_animation_performance_warning.html
@@ -192,17 +192,17 @@ var gAnimationWithGeometricKeyframeTests
       withGeometric: [
         {
           property: 'width',
           runningOnCompositor: false
         },
         {
           property: 'transform',
           runningOnCompositor: false,
-          warning: 'AnimationWarningTransformWithGeometricProperties'
+          warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
         }
       ]
     }
   },
   {
     desc: 'opacity and transform',
     frames: {
       opacity: [0, 1],
@@ -226,17 +226,17 @@ var gAnimationWithGeometricKeyframeTests
         },
         {
           property: 'opacity',
           runningOnCompositor: true
         },
         {
           property: 'transform',
           runningOnCompositor: false,
-          warning: 'AnimationWarningTransformWithGeometricProperties'
+          warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
         }
       ]
     }
   },
 ];
 
 var gPerformanceWarningTests = [
   {
@@ -244,31 +244,31 @@ var gPerformanceWarningTests = [
     frames: {
       transform: ['translate(0px)', 'translate(100px)']
     },
     style: 'transform-style: preserve-3d',
     expected: [
       {
         property: 'transform',
         runningOnCompositor: false,
-        warning: 'AnimationWarningTransformPreserve3D'
+        warning: 'CompositorAnimationWarningTransformPreserve3D'
       }
     ]
   },
   {
     desc: 'transform with backface-visibility:hidden',
     frames: {
       transform: ['translate(0px)', 'translate(100px)']
     },
     style: 'backface-visibility: hidden;',
     expected: [
       {
         property: 'transform',
         runningOnCompositor: false,
-        warning: 'AnimationWarningTransformBackfaceVisibilityHidden'
+        warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
       }
     ]
   },
   {
     desc: 'opacity and transform with preserve-3d',
     frames: {
       opacity: [0, 1],
       transform: ['translate(0px)', 'translate(100px)']
@@ -277,17 +277,17 @@ var gPerformanceWarningTests = [
     expected: [
       {
         property: 'opacity',
         runningOnCompositor: true
       },
       {
         property: 'transform',
         runningOnCompositor: false,
-        warning: 'AnimationWarningTransformPreserve3D'
+        warning: 'CompositorAnimationWarningTransformPreserve3D'
       }
     ]
   },
   {
     desc: 'opacity and transform with backface-visibility:hidden',
     frames: {
       opacity: [0, 1],
       transform: ['translate(0px)', 'translate(100px)']
@@ -296,17 +296,17 @@ var gPerformanceWarningTests = [
     expected: [
       {
         property: 'opacity',
         runningOnCompositor: true
       },
       {
         property: 'transform',
         runningOnCompositor: false,
-        warning: 'AnimationWarningTransformBackfaceVisibilityHidden'
+        warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
       }
     ]
   },
 ];
 
 var gMultipleAsyncAnimationsTests = [
   {
     desc: 'opacity and transform with preserve-3d',
@@ -315,17 +315,17 @@ var gMultipleAsyncAnimationsTests = [
       {
         frames: {
           transform: ['translate(0px)', 'translate(100px)']
         },
         expected: [
           {
             property: 'transform',
             runningOnCompositor: false,
-            warning: 'AnimationWarningTransformPreserve3D'
+            warning: 'CompositorAnimationWarningTransformPreserve3D'
           }
         ]
       },
       {
         frames: {
           opacity: [0, 1]
         },
         expected: [
@@ -344,17 +344,17 @@ var gMultipleAsyncAnimationsTests = [
       {
         frames: {
           transform: ['translate(0px)', 'translate(100px)']
         },
         expected: [
           {
             property: 'transform',
             runningOnCompositor: false,
-            warning: 'AnimationWarningTransformBackfaceVisibilityHidden'
+            warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
           }
         ]
       },
       {
         frames: {
           opacity: [0, 1]
         },
         expected: [
@@ -386,17 +386,17 @@ var gMultipleAsyncAnimationsWithGeometri
               property: 'transform',
               runningOnCompositor: true
             }
           ],
           withGeometric: [
             {
               property: 'transform',
               runningOnCompositor: false,
-              warning: 'AnimationWarningTransformWithGeometricProperties'
+              warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
             }
           ]
         }
       },
       {
         frames: {
           opacity: [0, 1]
         },
@@ -457,17 +457,17 @@ var gMultipleAsyncAnimationsWithGeometri
           withGeometric: [
             {
               property: 'width',
               runningOnCompositor: false,
             },
             {
               property: 'transform',
               runningOnCompositor: false,
-              warning: 'AnimationWarningTransformWithGeometricProperties'
+              warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
             }
           ]
         }
       }
     ]
   },
 ];
 
@@ -480,17 +480,17 @@ var gMultipleAsyncAnimationsWithGeometri
       {
         frames: {
           transform: ['translate(0px)', 'translate(100px)']
         },
         expected: [
           {
             property: 'transform',
             runningOnCompositor: false,
-            warning: 'AnimationWarningTransformWithGeometricProperties'
+            warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
           }
         ]
       },
     ]
   },
   {
     desc: 'opacity',
     animations: [
@@ -513,17 +513,17 @@ var gMultipleAsyncAnimationsWithGeometri
       {
         frames: {
           transform: ['translate(0px)', 'translate(100px)']
         },
         expected: [
           {
             property: 'transform',
             runningOnCompositor: false,
-            warning: 'AnimationWarningTransformWithGeometricProperties'
+            warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
           }
         ]
       },
       {
         frames: {
           opacity: [0, 1]
         },
         expected: [
@@ -869,17 +869,17 @@ function start() {
       svg.setAttribute('transform', 'translate(10, 20)');
       return waitForFrame();
     }).then(function() {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
         [ {
           property: 'transform',
           runningOnCompositor: false,
-          warning: 'AnimationWarningTransformSVG'
+          warning: 'CompositorAnimationWarningTransformSVG'
         } ]);
       svg.removeAttribute('transform');
       return waitForFrame();
     }).then(function() {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
         [ { property: 'transform', runningOnCompositor: true } ]);
     });
--- a/dom/animation/test/chrome/test_restyles.html
+++ b/dom/animation/test/chrome/test_restyles.html
@@ -63,27 +63,43 @@ function ensureElementRemoval(aElement) 
 }
 
 SimpleTest.waitForExplicitFinish();
 
 const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
 var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
                   SpecialPowers.getBoolPref(OMTAPrefKey);
 
+var isAndroid = !!navigator.userAgent.includes("Android");
+
 function add_task_if_omta_enabled(test) {
   if (!omtaEnabled) {
     info(test.name + " is skipped because OMTA is disabled");
     return;
   }
   add_task(test);
 }
 
 // We need to wait for all paints before running tests to avoid contaminations
 // from styling of this document itself.
 waitForAllPaints(function() {
+  add_task(function* restyling_for_main_thread_animations() {
+    var div = addDiv(null, { style: 'animation: background-color 100s' });
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    ok(!animation.isRunningOnCompositor);
+
+    var markers = yield observeStyling(5);
+    is(markers.length, 5,
+       'CSS animations running on the main-thread should update style ' +
+       'on the main thread');
+    yield ensureElementRemoval(div);
+  });
+
   add_task_if_omta_enabled(function* no_restyling_for_compositor_animations() {
     var div = addDiv(null, { style: 'animation: opacity 100s' });
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     ok(animation.isRunningOnCompositor);
 
     var markers = yield observeStyling(5);
@@ -186,106 +202,312 @@ waitForAllPaints(function() {
 
     is(markers.length, 0,
        'Bug 1219236: Finished animations should never cause restyles ' +
        'when mouse is moved on the animations');
     yield ensureElementRemoval(div);
   });
 
   add_task_if_omta_enabled(function* no_restyling_compositor_animations_out_of_view_element() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
     var div = addDiv(null,
       { style: 'animation: opacity 100s; transform: translateY(-400px);' });
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     ok(!animation.isRunningOnCompositor);
 
     var markers = yield observeStyling(5);
 
-    todo_is(markers.length, 0,
-            'Bug 1166500: Animations running on the compositor in out of ' +
-            'view element should never cause restyles');
+    is(markers.length, 0,
+       'Animations running on the compositor in an out-of-view element ' +
+       'should never cause restyles');
     yield ensureElementRemoval(div);
   });
 
   add_task(function* no_restyling_main_thread_animations_out_of_view_element() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
     var div = addDiv(null,
       { style: 'animation: background-color 100s; transform: translateY(-400px);' });
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     var markers = yield observeStyling(5);
 
-    todo_is(markers.length, 0,
-            'Bug 1166500: Animations running on the main-thread in out of ' +
-            'view element should never cause restyles');
+    is(markers.length, 0,
+       'Animations running on the main-thread in an out-of-view element ' +
+       'should never cause restyles');
     yield ensureElementRemoval(div);
   });
 
-  /*
-   Disabled for now since, on Android, the opacity animation runs on the
-   compositor even if it is scrolled out of view.
-   We will fix this in bug 1166500 or a follow-up bug
   add_task_if_omta_enabled(function* no_restyling_compositor_animations_in_scrolled_out_element() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    /*
+     On Android the opacity animation runs on the compositor even if it is
+     scrolled out of view.  We will fix this in bug 1247800.
+     */
+    if (isAndroid) {
+      return;
+    }
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: opacity 100s; position: relative; top: 100px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
-    ok(!animation.isRunningOnCompositor);
 
     var markers = yield observeStyling(5);
 
-    todo_is(markers.length, 0,
-            'Bug 1166500: Animations running on the compositor in elements ' +
-            'which are scrolled out should never cause restyles');
+    is(markers.length, 0,
+       'Animations running on the compositor for elements ' +
+       'which are scrolled out should never cause restyles');
+
     yield ensureElementRemoval(parentElement);
   });
-  */
 
   add_task(function* no_restyling_main_thread_animations_in_scrolled_out_element() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    /*
+     On Android throttled animations are left behind on the main thread in some
+     frames, We will fix this in bug 1247800.
+     */
+    if (isAndroid) {
+      return;
+    }
+
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s; position: relative; top: 100px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     var markers = yield observeStyling(5);
 
-    todo_is(markers.length, 0,
-            'Bug 1166500: Animations running on the main-thread in elements ' +
-            'which are scrolled out should never cause restyles');
+    is(markers.length, 0,
+       'Animations running on the main-thread for elements ' +
+       'which are scrolled out should never cause restyles');
+
     yield ensureElementRemoval(parentElement);
   });
 
-  /*
-   Disabled for now since, on Android and B2G, the opacity animation runs on the
-   compositor even if the associated element has visibility:hidden.
-   We will fix this in bug 1237454 or a follow-up bug.
+  add_task(function* no_restyling_main_thread_animations_in_nested_scrolled_out_element() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    /*
+     On Android throttled animations are left behind on the main thread in some
+     frames, We will fix this in bug 1247800.
+     */
+    if (isAndroid) {
+      return;
+    }
+
+    var grandParent = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 100px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; position: relative; top: 100px;' });
+    grandParent.appendChild(parentElement);
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+    var markers = yield observeStyling(5);
+
+    is(markers.length, 0,
+       'Animations running on the main-thread which are in nested elements ' +
+       'which are scrolled out should never cause restyles');
+
+    yield ensureElementRemoval(grandParent);
+  });
+
   add_task_if_omta_enabled(function* no_restyling_compositor_animations_in_visiblily_hidden_element() {
     var div = addDiv(null,
      { style: 'animation: opacity 100s; visibility: hidden' });
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     ok(!animation.isRunningOnCompositor);
 
     var markers = yield observeStyling(5);
 
     todo_is(markers.length, 0,
             'Bug 1237454: Animations running on the compositor in ' +
             'visibility hidden element should never cause restyles');
     yield ensureElementRemoval(div);
   });
-  */
+
+  add_task(function* restyling_main_thread_animations_moved_in_view_by_scrolling() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    /*
+     On Android throttled animations are left behind on the main thread in some
+     frames, We will fix this in bug 1247800.
+     */
+    if (isAndroid) {
+      return;
+    }
+
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; position: relative; top: 100px;' });
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    var parentRect = parentElement.getBoundingClientRect();
+    var centerX = parentRect.left + parentRect.width / 2;
+    var centerY = parentRect.top + parentRect.height / 2;
+
+    yield animation.ready;
+
+    var markers = yield observeStyling(1, function() {
+      // We can't use synthesizeWheel here since synthesizeWheel causes
+      // layout flush.
+      synthesizeWheelAtPoint(centerX, centerY,
+                             { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+                               deltaY: 100 });
+    });
+
+    is(markers.length, 1,
+       'Animations running on the main-thread which were in scrolled out ' +
+       'elements should update restyling soon after the element moved in ' +
+       'view by scrolling');
+
+    yield ensureElementRemoval(parentElement);
+  });
+
+  add_task(function* restyling_main_thread_animations_moved_in_view_by_scrolling() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    var grandParent = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 200px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; position: relative; top: 100px;' });
+    grandParent.appendChild(parentElement);
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    var parentRect = grandParent.getBoundingClientRect();
+    var centerX = parentRect.left + parentRect.width / 2;
+    var centerY = parentRect.top + parentRect.height / 2;
+
+    yield animation.ready;
+
+    var markers = yield observeStyling(1, function() {
+      // We can't use synthesizeWheel here since synthesizeWheel causes
+      // layout flush.
+      synthesizeWheelAtPoint(centerX, centerY,
+                             { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+                               deltaY: 100 });
+    });
+
+    // FIXME: We should reduce a redundant restyle here.
+    ok(markers.length >= 1,
+       'Animations running on the main-thread which were in nested scrolled ' +
+       'out elements should update restyle soon after the element moved ' +
+       'in view by scrolling');
+
+    yield ensureElementRemoval(grandParent);
+  });
+
+  add_task(function* restyling_main_thread_animations_move_out_of_view_by_scrolling() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    /*
+     On Android throttled animations are left behind on the main thread in some
+     frames, We will fix this in bug 1247800.
+     */
+    if (isAndroid) {
+      return;
+    }
+
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 200px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s;' });
+    var pad = addDiv(null,
+      { style: 'height: 400px;' });
+    parentElement.appendChild(div);
+    parentElement.appendChild(pad);
+    var animation = div.getAnimations()[0];
+
+    var parentRect = parentElement.getBoundingClientRect();
+    var centerX = parentRect.left + parentRect.width / 2;
+    var centerY = parentRect.top + parentRect.height / 2;
+
+    yield animation.ready;
+
+    // We can't use synthesizeWheel here since synthesizeWheel causes
+    // layout flush.
+    synthesizeWheelAtPoint(centerX, centerY,
+                           { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+                             deltaY: 200 });
+
+    var markers = yield observeStyling(5);
+
+    // FIXME: We should reduce a redundant restyle here.
+    ok(markers.length >= 0,
+       'Animations running on the main-thread which are in scrolled out ' +
+       'elements should throttle restyling');
+
+    yield ensureElementRemoval(parentElement);
+  });
+
+  add_task(function* restyling_main_thread_animations_moved_in_view_by_resizing() {
+    if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
+      return;
+    }
+
+    var parentElement = addDiv(null,
+      { style: 'overflow-y: scroll; height: 20px;' });
+    var div = addDiv(null,
+      { style: 'animation: background-color 100s; position: relative; top: 100px;' });
+    parentElement.appendChild(div);
+    var animation = div.getAnimations()[0];
+
+    yield animation.ready;
+
+    var markers = yield observeStyling(1, function() {
+      parentElement.style.height = '100px';
+    });
+
+    is(markers.length, 1,
+       'Animations running on the main-thread which was in scrolled out ' +
+       'elements should update restyling soon after the element moved in ' +
+       'view by resizing');
+
+    yield ensureElementRemoval(parentElement);
+  });
 
   add_task(function* no_restyling_main_thread_animations_in_visiblily_hidden_element() {
     var div = addDiv(null,
      { style: 'animation: background-color 100s; visibility: hidden' });
     var animation = div.getAnimations()[0];
 
     yield animation.ready;
     var markers = yield observeStyling(5);
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -126,22 +126,22 @@ function waitForFrame() {
  * animation frames have occured (using requestAnimationFrame callbacks).
  *
  * @param frameCount  The number of animation frames.
  * @param onFrame  An optional function to be processed in each animation frame.
  */
 function waitForAnimationFrames(frameCount, onFrame) {
   return new Promise(function(resolve, reject) {
     function handleFrame() {
+      if (onFrame && typeof onFrame === 'function') {
+        onFrame();
+      }
       if (--frameCount <= 0) {
         resolve();
       } else {
-        if (onFrame && typeof onFrame === 'function') {
-          onFrame();
-        }
         window.requestAnimationFrame(handleFrame); // wait another frame
       }
     }
     window.requestAnimationFrame(handleFrame);
   });
 }
 
 /**
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -613,30 +613,30 @@ this.AppsUtils = {
   },
 
   /**
    * Determines if an update or a factory reset occured.
    */
   isFirstRun: function isFirstRun(aPrefBranch) {
     let savedmstone = null;
     try {
-      savedmstone = aPrefBranch.getCharPref("gecko.mstone");
+      savedmstone = aPrefBranch.getCharPref("dom.apps.lastUpdate.mstone");
     } catch (e) {}
 
     let mstone = Services.appinfo.platformVersion;
 
     let savedBuildID = null;
     try {
-      savedBuildID = aPrefBranch.getCharPref("gecko.buildID");
+      savedBuildID = aPrefBranch.getCharPref("dom.apps.lastUpdate.buildID");
     } catch (e) {}
 
     let buildID = Services.appinfo.platformBuildID;
 
-    aPrefBranch.setCharPref("gecko.mstone", mstone);
-    aPrefBranch.setCharPref("gecko.buildID", buildID);
+    aPrefBranch.setCharPref("dom.apps.lastUpdate.mstone", mstone);
+    aPrefBranch.setCharPref("dom.apps.lastUpdate.buildID", buildID);
 
     if ((mstone != savedmstone) || (buildID != savedBuildID)) {
       aPrefBranch.setBoolPref("dom.apps.reset-permissions", false);
       return true;
     } else {
       return false;
     }
   },
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -490,17 +490,17 @@ Element::WrapObject(JSContext *aCx, JS::
   }
 
   if (!bindingURL) {
     // No binding, nothing left to do here.
     return obj;
   }
 
   nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
-  nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal;
+  nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal.get();
 
   // We have a binding that must be installed.
   bool dummy;
 
   nsXBLService* xblService = nsXBLService::GetInstance();
   if (!xblService) {
     dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
     return nullptr;
@@ -3072,20 +3072,16 @@ nsDOMTokenListPropertyDestructor(void *a
 {
   nsDOMTokenList* list =
     static_cast<nsDOMTokenList*>(aPropertyValue);
   NS_RELEASE(list);
 }
 
 static nsIAtom** sPropertiesToTraverseAndUnlink[] =
   {
-    &nsGkAtoms::microdataProperties,
-    &nsGkAtoms::itemtype,
-    &nsGkAtoms::itemref,
-    &nsGkAtoms::itemprop,
     &nsGkAtoms::sandbox,
     &nsGkAtoms::sizes,
     nullptr
   };
 
 // static
 nsIAtom***
 Element::HTMLSVGPropertiesToTraverseAndUnlink()
@@ -3117,36 +3113,16 @@ Element::GetTokenList(nsIAtom* aAtom,
   if (!list) {
     list = new nsDOMTokenList(this, aAtom, aSupportedTokens);
     NS_ADDREF(list);
     SetProperty(aAtom, list, nsDOMTokenListPropertyDestructor);
   }
   return list;
 }
 
-void
-Element::GetTokenList(nsIAtom* aAtom, nsIVariant** aResult)
-{
-  nsISupports* itemType = GetTokenList(aAtom);
-  nsCOMPtr<nsIWritableVariant> out = new nsVariant();
-  out->SetAsInterface(NS_GET_IID(nsISupports), itemType);
-  out.forget(aResult);
-}
-
-nsresult
-Element::SetTokenList(nsIAtom* aAtom, nsIVariant* aValue)
-{
-  nsDOMTokenList* itemType = GetTokenList(aAtom);
-  nsAutoString string;
-  aValue->GetAsAString(string);
-  ErrorResult rv;
-  itemType->SetValue(string, rv);
-  return rv.StealNSResult();
-}
-
 Element*
 Element::Closest(const nsAString& aSelector, ErrorResult& aResult)
 {
   nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult);
   if (!selectorList) {
     // Either we failed (and aResult already has the exception), or this
     // is a pseudo-element-only selector that matches nothing.
     return nullptr;
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1331,18 +1331,16 @@ protected:
    * this gets the value of the xlink:_moz_target attribute, or failing that,
    * the value of xlink:show, converted to a suitably equivalent named target
    * (e.g. _blank).
    */
   virtual void GetLinkTarget(nsAString& aTarget);
 
   nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
                                const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
-  void GetTokenList(nsIAtom* aAtom, nsIVariant** aResult);
-  nsresult SetTokenList(nsIAtom* aAtom, nsIVariant* aValue);
 
 private:
   /**
    * Get this element's client area rect in app units.
    * @return the frame's client area
    */
   nsRect GetClientAreaRect();
 
--- a/dom/base/ImportManager.cpp
+++ b/dom/base/ImportManager.cpp
@@ -142,17 +142,18 @@ ImportLoader::Updater::UpdateMainReferre
 
   // This new link means we have to execute our scripts sooner...
   // Let's make sure that unblocking a loader does not trigger a script execution.
   // So we start with placing the new blockers and only then will we remove any
   // blockers.
   if (mLoader->IsBlocking()) {
     // Our import parent is changed, let's block the new one and later unblock
     // the old one.
-    newMainReferrer->OwnerDoc()->ScriptLoader()->AddExecuteBlocker();
+    newMainReferrer->OwnerDoc()->
+      ScriptLoader()->AddParserBlockingScriptExecutionBlocker();
     newMainReferrer->OwnerDoc()->BlockDOMContentLoaded();
   }
 
   if (mLoader->mDocument) {
     // Our nearest predecessor has changed. So let's add the ScriptLoader to the
     // new one if there is any. And remove it from the old one.
     RefPtr<ImportManager> manager = mLoader->Manager();
     nsScriptLoader* loader = mLoader->mDocument->ScriptLoader();
@@ -162,17 +163,18 @@ ImportLoader::Updater::UpdateMainReferre
       if (newPred) {
         newPred->AddBlockedScriptLoader(loader);
       }
       pred->RemoveBlockedScriptLoader(loader);
     }
   }
 
   if (mLoader->IsBlocking()) {
-    mLoader->mImportParent->ScriptLoader()->RemoveExecuteBlocker();
+    mLoader->mImportParent->
+      ScriptLoader()->RemoveParserBlockingScriptExecutionBlocker();
     mLoader->mImportParent->UnblockDOMContentLoaded();
   }
 
   // Finally update mMainReferrer to point to the newly added link.
   mLoader->mMainReferrer = aNewIdx;
   mLoader->mImportParent = newMainReferrer->OwnerDoc();
 }
 
@@ -295,29 +297,29 @@ ImportLoader::ImportLoader(nsIURI* aURI,
   , mUpdater(this)
 {
 }
 
 void
 ImportLoader::BlockScripts()
 {
   MOZ_ASSERT(!mBlockingScripts);
-  mImportParent->ScriptLoader()->AddExecuteBlocker();
+  mImportParent->ScriptLoader()->AddParserBlockingScriptExecutionBlocker();
   mImportParent->BlockDOMContentLoaded();
   mBlockingScripts = true;
 }
 
 void
 ImportLoader::UnblockScripts()
 {
   MOZ_ASSERT(mBlockingScripts);
-  mImportParent->ScriptLoader()->RemoveExecuteBlocker();
+  mImportParent->ScriptLoader()->RemoveParserBlockingScriptExecutionBlocker();
   mImportParent->UnblockDOMContentLoaded();
   for (uint32_t i = 0; i < mBlockedScriptLoaders.Length(); i++) {
-    mBlockedScriptLoaders[i]->RemoveExecuteBlocker();
+    mBlockedScriptLoaders[i]->RemoveParserBlockingScriptExecutionBlocker();
   }
   mBlockedScriptLoaders.Clear();
   mBlockingScripts = false;
 }
 
 void
 ImportLoader::SetBlockingPredecessor(ImportLoader* aLoader)
 {
@@ -338,26 +340,26 @@ ImportLoader::DispatchEventIfFinished(ns
 
 void
 ImportLoader::AddBlockedScriptLoader(nsScriptLoader* aScriptLoader)
 {
   if (mBlockedScriptLoaders.Contains(aScriptLoader)) {
     return;
   }
 
-  aScriptLoader->AddExecuteBlocker();
+  aScriptLoader->AddParserBlockingScriptExecutionBlocker();
 
   // Let's keep track of the pending script loaders.
   mBlockedScriptLoaders.AppendElement(aScriptLoader);
 }
 
 bool
 ImportLoader::RemoveBlockedScriptLoader(nsScriptLoader* aScriptLoader)
 {
-  aScriptLoader->RemoveExecuteBlocker();
+  aScriptLoader->RemoveParserBlockingScriptExecutionBlocker();
   return mBlockedScriptLoaders.RemoveElement(aScriptLoader);
 }
 
 void
 ImportLoader::AddLinkElement(nsINode* aNode)
 {
   // If a new link element is added to the import tree that
   // refers to an import that is already finished loading or
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1605,16 +1605,21 @@ Navigator::GetDeprecatedBattery(ErrorRes
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
 
     mBatteryManager = new battery::BatteryManager(mWindow);
     mBatteryManager->Init();
   }
 
+  nsIDocument* doc = mWindow->GetDoc();
+  if (doc) {
+    doc->WarnOnceAbout(nsIDocument::eNavigatorBattery);
+  }
+
   return mBatteryManager;
 }
 
 already_AddRefed<Promise>
 Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
   RefPtr<Promise> p = Promise::Create(go, aRv);
@@ -2398,50 +2403,48 @@ Navigator::HasPresentationSupport(JSCont
 
   // Grant access if it has the permission.
   if (CheckPermission(inner, "presentation")) {
     return true;
   }
 
   // Grant access to browser receiving pages and their same-origin iframes. (App
   // pages should be controlled by "presentation" permission in app manifests.)
-  mozilla::dom::ContentChild* cc =
-    mozilla::dom::ContentChild::GetSingleton();
-  if (!cc || !cc->IsForBrowser()) {
+  nsCOMPtr<nsIDocShell> docshell = inner->GetDocShell();
+  if (!docshell) {
     return false;
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> win = inner->GetOuterWindow();
-  nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop();
-  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(win);
-  nsCOMPtr<nsIScriptObjectPrincipal> topSop = do_QueryInterface(top);
-  if (!sop || !topSop) {
+  if (!docshell->GetIsInMozBrowserOrApp()) {
+    return false;
+  }
+
+  nsAutoString presentationURL;
+  nsContentUtils::GetPresentationURL(docshell, presentationURL);
+
+  if (presentationURL.IsEmpty()) {
     return false;
   }
 
-  nsIPrincipal* principal = sop->GetPrincipal();
-  nsIPrincipal* topPrincipal = topSop->GetPrincipal();
-  if (!principal || !topPrincipal || !principal->Subsumes(topPrincipal)) {
-    return false;
-  }
-
-  nsCOMPtr<nsPIDOMWindowInner> topInner;
-  if (!(topInner = top->GetCurrentInnerWindow())) {
+  nsCOMPtr<nsIScriptSecurityManager> securityManager =
+    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
+  if (!securityManager) {
     return false;
   }
 
-  nsCOMPtr<nsIPresentationService> presentationService =
-    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
-  if (NS_WARN_IF(!presentationService)) {
+  nsCOMPtr<nsIURI> presentationURI;
+  nsresult rv = NS_NewURI(getter_AddRefs(presentationURI), presentationURL);
+  if (NS_FAILED(rv)) {
     return false;
   }
 
-  nsAutoString sessionId;
-  presentationService->GetExistentSessionIdAtLaunch(topInner->WindowID(), sessionId);
-  return !sessionId.IsEmpty();
+  nsCOMPtr<nsIURI> docURI = inner->GetDocumentURI();
+  return NS_SUCCEEDED(securityManager->CheckSameOriginURI(presentationURI,
+                                                          docURI,
+                                                          false));
 }
 
 /* static */
 bool
 Navigator::IsE10sEnabled(JSContext* aCx, JSObject* aGlobal)
 {
   return XRE_IsContentProcess();
 }
--- a/dom/base/domerr.msg
+++ b/dom/base/domerr.msg
@@ -113,17 +113,16 @@ DOM4_MSG_DEF(BtParmInvalidError,  "Inval
 DOM4_MSG_DEF(BtUnhandledError,    "Unhandled",  NS_ERROR_DOM_BLUETOOTH_UNHANDLED)
 DOM4_MSG_DEF(BtAuthFailureError,  "Authentication failure",  NS_ERROR_DOM_BLUETOOTH_AUTH_FAILURE)
 DOM4_MSG_DEF(BtRmtDevDownError,   "Remote device down",  NS_ERROR_DOM_BLUETOOTH_RMT_DEV_DOWN)
 DOM4_MSG_DEF(BtAuthRejectedError, "Authentication rejected",  NS_ERROR_DOM_BLUETOOTH_AUTH_REJECTED)
 
 /* Web Animations errors */
 
 DOM4_MSG_DEF(NotSupportedError, "Animation to or from an underlying value is not yet supported.", NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR)
-DOM4_MSG_DEF(NotSupportedError, "Animation with no timeline is not yet supported.", NS_ERROR_DOM_ANIM_NO_TIMELINE_ERR)
 DOM4_MSG_DEF(NotSupportedError, "Animation with no effect is not yet supported.", NS_ERROR_DOM_ANIM_NO_EFFECT_ERR)
 
 /* common global codes (from nsError.h) */
 
 DOM_MSG_DEF(NS_OK                                  , "Success")
 DOM_MSG_DEF(NS_ERROR_NOT_INITIALIZED               , "Component not initialized")
 DOM_MSG_DEF(NS_ERROR_ALREADY_INITIALIZED           , "Component already initialized")
 DOM_MSG_DEF(NS_ERROR_NOT_IMPLEMENTED               , "Method not implemented")
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -230,17 +230,17 @@ nsContentSink::StyleSheetLoaded(StyleShe
         // don't need to worry about it.
         StartLayout(false);
       }
 
       // Go ahead and try to scroll to our ref if we have one
       ScrollToRef();
     }
     
-    mScriptLoader->RemoveExecuteBlocker();
+    mScriptLoader->RemoveParserBlockingScriptExecutionBlocker();
   }
 
   return NS_OK;
 }
 
 nsresult
 nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
 {
@@ -767,17 +767,17 @@ nsContentSink::ProcessStyleLink(nsIConte
   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
                                  CORS_NONE, mDocument->GetReferrerPolicy(),
                                  integrity, mRunsToCompletion ? nullptr : this,
                                  &isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (!isAlternate && !mRunsToCompletion) {
     ++mPendingSheetCount;
-    mScriptLoader->AddExecuteBlocker();
+    mScriptLoader->AddParserBlockingScriptExecutionBlocker();
   }
 
   return NS_OK;
 }
 
 
 nsresult
 nsContentSink::ProcessMETATag(nsIContent* aContent)
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -110,16 +110,17 @@
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMEvent.h"
+#include "nsIDOMElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsIDragService.h"
@@ -198,16 +199,17 @@
 #include "xpcprivate.h" // nsXPConnect
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsContentTypeParser.h"
 #include "nsICookiePermission.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsICookieService.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/BloomFilter.h"
+#include "TabChild.h"
 
 #include "nsIBidiKeyboard.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
@@ -712,17 +714,17 @@ ShouldAddEventToStringEventTable(const E
 
 bool
 nsContentUtils::InitializeEventTable() {
   NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!");
   NS_ASSERTION(!sStringEventTable, "EventTable already initialized!");
 
   static const EventNameMapping eventArray[] = {
 #define EVENT(name_,  _message, _type, _class)          \
-    { nsGkAtoms::on##name_, _type, _message, _class },
+    { nsGkAtoms::on##name_, _type, _message, _class, false },
 #define WINDOW_ONLY_EVENT EVENT
 #define NON_IDL_EVENT EVENT
 #include "mozilla/EventNameList.h"
 #undef WINDOW_ONLY_EVENT
 #undef NON_IDL_EVENT
 #undef EVENT
     { nullptr }
   };
@@ -3682,20 +3684,61 @@ nsContentUtils::GetEventMessageAndAtom(c
 
   *aEventMessage = eUnidentifiedEvent;
   nsCOMPtr<nsIAtom> atom = NS_Atomize(NS_LITERAL_STRING("on") + aName);
   sUserDefinedEvents->AppendObject(atom);
   mapping.mAtom = atom;
   mapping.mMessage = eUnidentifiedEvent;
   mapping.mType = EventNameType_None;
   mapping.mEventClassID = eBasicEventClass;
+  // This is a slow hashtable call, but at least we cache the result for the
+  // following calls. Because GetEventMessageAndAtomForListener utilizes
+  // sStringEventTable, it needs to know in which cases sStringEventTable
+  // doesn't contain the information it needs so that it can use
+  // sAtomEventTable instead.
+  mapping.mMaybeSpecialSVGorSMILEvent =
+    GetEventMessage(atom) != eUnidentifiedEvent;
   sStringEventTable->Put(aName, mapping);
   return mapping.mAtom;
 }
 
+// static
+EventMessage
+nsContentUtils::GetEventMessageAndAtomForListener(const nsAString& aName,
+                                                  nsIAtom** aOnName)
+{
+  // Because of SVG/SMIL sStringEventTable contains a subset of the event names
+  // comparing to the sAtomEventTable. However, usually sStringEventTable
+  // contains the information we need, so in order to reduce hashtable
+  // lookups, start from it.
+  EventNameMapping mapping;
+  EventMessage msg = eUnidentifiedEvent;
+  nsCOMPtr<nsIAtom> atom;
+  if (sStringEventTable->Get(aName, &mapping)) {
+    if (mapping.mMaybeSpecialSVGorSMILEvent) {
+      // Try the atom version so that we should get the right message for
+      // SVG/SMIL.
+      atom = NS_Atomize(NS_LITERAL_STRING("on") + aName);
+      msg = GetEventMessage(atom);
+    } else {
+      atom = mapping.mAtom;
+      msg = mapping.mMessage;
+    }
+    atom.forget(aOnName);
+    return msg;
+  }
+
+  // GetEventMessageAndAtom will cache the event type for the future usage...
+  GetEventMessageAndAtom(aName, eBasicEventClass, &msg);
+
+  // ...and then call this method recursively to get the message and atom from
+  // now updated sStringEventTable.
+  return GetEventMessageAndAtomForListener(aName, aOnName);
+}
+
 static
 nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
                            const nsAString& aEventName,
                            bool aCanBubble, bool aCancelable,
                            bool aTrusted, nsIDOMEvent** aEvent,
                            EventTarget** aTargetOut)
 {
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
@@ -8831,8 +8874,36 @@ nsContentUtils::SetScrollbarsVisibility(
     }
 
     scroller->SetDefaultScrollbarPreferences(
                 nsIScrollable::ScrollOrientation_Y, prefValue);
     scroller->SetDefaultScrollbarPreferences(
                 nsIScrollable::ScrollOrientation_X, prefValue);
   }
 }
+
+/* static */ void
+nsContentUtils::GetPresentationURL(nsIDocShell* aDocShell, nsAString& aPresentationUrl)
+{
+  MOZ_ASSERT(aDocShell);
+
+  if (XRE_IsContentProcess()) {
+    nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
+    aDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+    nsCOMPtr<nsIDocShellTreeItem> root;
+    aDocShell->GetRootTreeItem(getter_AddRefs(root));
+    if (sameTypeRoot.get() == root.get()) {
+      // presentation URL is stored in TabChild for the top most
+      // <iframe mozbrowser> in content process.
+      TabChild* tabChild = TabChild::GetFrom(aDocShell);
+      if (tabChild) {
+        aPresentationUrl = tabChild->PresentationURL();
+      }
+      return;
+    }
+  }
+
+  nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(aDocShell));
+  nsCOMPtr<nsIDOMElement> topFrameElement;
+  loadContext->GetTopFrameElement(getter_AddRefs(topFrameElement));
+
+  topFrameElement->GetAttribute(NS_LITERAL_STRING("mozpresentation"), aPresentationUrl);
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -164,16 +164,19 @@ enum EventNameType {
 struct EventNameMapping
 {
   // This holds pointers to nsGkAtoms members, and is therefore safe as a
   // non-owning reference.
   nsIAtom* MOZ_NON_OWNING_REF mAtom;
   int32_t  mType;
   mozilla::EventMessage mMessage;
   mozilla::EventClassID mEventClassID;
+  // True if mAtom is possibly used by special SVG/SMIL events, but
+  // mMessage is eUnidentifiedEvent. See EventNameList.h
+  bool mMaybeSpecialSVGorSMILEvent;
 };
 
 typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
                                            void* aArg);
 
 class nsContentUtils
 {
   friend class nsAutoScriptBlockerSuppressNodeRemoved;
@@ -1167,16 +1170,23 @@ public:
    * the event name with the 'on' prefix. Returns eUnidentifiedEvent if the
    * event doesn't match a known event name.
    *
    * @param aName the event name to look up
    */
   static mozilla::EventMessage GetEventMessage(nsIAtom* aName);
 
   /**
+   * Returns the EventMessage and nsIAtom to be used for event listener
+   * registration.
+   */
+  static mozilla::EventMessage
+  GetEventMessageAndAtomForListener(const nsAString& aName, nsIAtom** aOnName);
+
+  /**
    * Return the EventClassID for the event with the given name. The name is the
    * event name *without* the 'on' prefix. Returns eBasicEventClass if the event
    * is not known to be of any particular event class.
    *
    * @param aName the event name to look up
    */
   static mozilla::EventClassID GetEventClassID(const nsAString& aName);
 
@@ -2548,16 +2558,22 @@ public:
    * the provided about: URI.
    * @param aGlobal the JSObject whose URI to check, if it is a global.
    * @param aUri the URI to match, e.g. "about:feeds"
    */
   static bool IsSpecificAboutPage(JSObject* aGlobal, const char* aUri);
 
   static void SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible);
 
+  /*
+   * Return the associated presentation URL of the presented content.
+   * Will return empty string if the docshell is not in a presented content.
+   */
+  static void GetPresentationURL(nsIDocShell* aDocShell, nsAString& aPresentationUrl);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -37,11 +37,13 @@ DEPRECATED_OPERATION(ShowModalDialog)
 DEPRECATED_OPERATION(Window_Content)
 DEPRECATED_OPERATION(SyncXMLHttpRequest)
 DEPRECATED_OPERATION(DataContainerEvent)
 DEPRECATED_OPERATION(Window_Controllers)
 DEPRECATED_OPERATION(ImportXULIntoContent)
 DEPRECATED_OPERATION(PannerNodeDoppler)
 DEPRECATED_OPERATION(NavigatorGetUserMedia)
 DEPRECATED_OPERATION(WebrtcDeprecatedPrefix)
+DEPRECATED_OPERATION(RTCPeerConnectionGetStreams)
 DEPRECATED_OPERATION(AppCache)
 DEPRECATED_OPERATION(PrefixedFullscreenAPI)
 DEPRECATED_OPERATION(LenientSetter)
+DEPRECATED_OPERATION(NavigatorBattery)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2747,17 +2747,16 @@ nsDocument::ApplySettingsFromCSP(bool aS
       NS_ENSURE_SUCCESS_VOID(rv);
     }
   }
 }
 
 nsresult
 nsDocument::InitCSP(nsIChannel* aChannel)
 {
-  nsCOMPtr<nsIContentSecurityPolicy> csp;
   if (!CSPService::sCSPEnabled) {
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
            ("CSP is disabled, skipping CSP init for document %p", this));
     return NS_OK;
   }
 
   nsAutoCString tCspHeaderValue, tCspROHeaderValue;
 
@@ -2867,16 +2866,17 @@ nsDocument::InitCSP(nsIChannel* aChannel
       MOZ_LOG(gCspPRLog, LogLevel::Debug, ("%s %s %s",
            "This document is sharing principal with another document.",
            "Since the document is an app, CSP was already set.",
            "Skipping attempt to set CSP."));
       return NS_OK;
     }
   }
 
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = principal->EnsureCSP(this, getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ----- if the doc is an app and we want a default CSP, apply it.
   if (applyAppDefaultCSP) {
     csp->AppendPolicy(appDefaultCSP, false, false);
   }
 
@@ -9760,16 +9760,19 @@ nsDocument::SuppressEventHandling(nsIDoc
       aIncrease != 0 && mPresShell && mScriptGlobalObject) {
     RevokeAnimationFrameNotifications();
   }
 
   if (aWhat == eAnimationsOnly) {
     mAnimationsPaused += aIncrease;
   } else {
     mEventsSuppressed += aIncrease;
+    for (uint32_t i = 0; i < aIncrease; ++i) {
+      ScriptLoader()->AddExecuteBlocker();
+    }
   }
 
   SuppressArgs args = { aWhat, aIncrease };
   EnumerateSubDocuments(SuppressEventHandlingInDocument, &args);
 }
 
 static void
 FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
@@ -10088,16 +10091,17 @@ struct UnsuppressArgs
 static bool
 GetAndUnsuppressSubDocuments(nsIDocument* aDocument,
                              void* aData)
 {
   UnsuppressArgs* args = static_cast<UnsuppressArgs*>(aData);
   if (args->mWhat != nsIDocument::eAnimationsOnly &&
       aDocument->EventHandlingSuppressed() > 0) {
     static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
+    aDocument->ScriptLoader()->RemoveExecuteBlocker();
   } else if (args->mWhat == nsIDocument::eAnimationsOnly &&
              aDocument->AnimationsPaused()) {
     static_cast<nsDocument*>(aDocument)->ResumeAnimations();
   }
 
   if (args->mWhat != nsIDocument::eAnimationsOnly) {
     // No need to remember documents if we only care about animation frames.
     args->mDocs.AppendElement(aDocument);
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -338,16 +338,42 @@ NS_IMETHODIMP
 nsFrameLoader::SetIsPrerendered()
 {
   MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
   mIsPrerendered = true;
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::MakePrerenderedLoaderActive()
+{
+  MOZ_ASSERT(mIsPrerendered, "This frameloader was not in prerendered mode.");
+
+  mIsPrerendered = false;
+  if (IsRemoteFrame()) {
+    if (!mRemoteBrowser) {
+      NS_WARNING("Missing remote browser.");
+      return NS_ERROR_FAILURE;
+    }
+
+    mRemoteBrowser->SetDocShellIsActive(true);
+  } else {
+    if (!mDocShell) {
+      NS_WARNING("Missing docshell.");
+      return NS_ERROR_FAILURE;
+    }
+
+    nsresult rv = mDocShell->SetIsActive(true);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   nsresult rv = ReallyStartLoadingInternal();
   if (NS_FAILED(rv)) {
     FireErrorEvent();
   }
 
@@ -931,35 +957,18 @@ nsFrameLoader::SwapWithOtherRemoteLoader
   }
 
   if (mRemoteBrowser->IsIsolatedMozBrowserElement() !=
       aOther->mRemoteBrowser->IsIsolatedMozBrowserElement() ||
       mRemoteBrowser->HasOwnApp() != aOther->mRemoteBrowser->HasOwnApp()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
-  // When we swap docShells, maybe we have to deal with a new page created just
-  // for this operation. In this case, the browser code should already have set
-  // the correct userContextId attribute value in the owning XULElement, but our
-  // docShell, that has been created way before) doesn't know that that
-  // happened.
-  // This is the reason why now we must retrieve the correct value from the
-  // usercontextid attribute before comparing our originAttributes with the
-  // other one.
-  DocShellOriginAttributes ourOriginAttributes =
-    mRemoteBrowser->OriginAttributesRef();
-  rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  DocShellOriginAttributes otherOriginAttributes =
-    aOther->mRemoteBrowser->OriginAttributesRef();
-  rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (ourOriginAttributes != otherOriginAttributes) {
+  if (mRemoteBrowser->OriginAttributesRef() !=
+      aOther->mRemoteBrowser->OriginAttributesRef()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   bool ourHasHistory =
     mIsTopLevelContent &&
     ourContent->IsXULElement(nsGkAtoms::browser) &&
     !ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory);
   bool otherHasHistory =
@@ -1329,35 +1338,18 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   }
 
   if (ourDocshell->GetIsIsolatedMozBrowserElement() !=
       otherDocshell->GetIsIsolatedMozBrowserElement() ||
       ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
-  // When we swap docShells, maybe we have to deal with a new page created just
-  // for this operation. In this case, the browser code should already have set
-  // the correct userContextId attribute value in the owning XULElement, but our
-  // docShell, that has been created way before) doesn't know that that
-  // happened.
-  // This is the reason why now we must retrieve the correct value from the
-  // usercontextid attribute before comparing our originAttributes with the
-  // other one.
-  DocShellOriginAttributes ourOriginAttributes =
-    ourDocshell->GetOriginAttributes();
-  rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  DocShellOriginAttributes otherOriginAttributes =
-    otherDocshell->GetOriginAttributes();
-  rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (ourOriginAttributes != otherOriginAttributes) {
+  if (ourDocshell->GetOriginAttributes() !=
+      otherDocshell->GetOriginAttributes()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   if (mInSwap || aOther->mInSwap) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   AutoResetInFrameSwap autoFrameSwap(this, aOther, ourDocshell, otherDocshell,
                                      ourEventTarget, otherEventTarget);
@@ -1961,17 +1953,17 @@ nsFrameLoader::MaybeCreateDocShell()
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
   NS_ENSURE_STATE(parentAsWebNav);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   if (mIsPrerendered) {
-    nsresult rv = mDocShell->SetIsPrerendered(true);
+    nsresult rv = mDocShell->SetIsPrerendered();
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
   // Apply sandbox flags even if our owner is not an iframe, as this copies
   // flags from our owning content's owning document.
   uint32_t sandboxFlags = 0;
   HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
   if (iframe) {
@@ -2110,19 +2102,23 @@ nsFrameLoader::MaybeCreateDocShell()
     }
 
     attrs.mAppId = containingAppId;
     attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
     mDocShell->SetFrameType(nsIDocShell::FRAME_TYPE_BROWSER);
   }
 
   // Grab the userContextId from owner if XUL
-  nsresult rv = PopulateUserContextIdFromAttribute(attrs);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  nsAutoString userContextIdStr;
+  if ((namespaceID == kNameSpaceID_XUL) &&
+      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid, userContextIdStr) &&
+      !userContextIdStr.IsEmpty()) {
+    nsresult rv;
+    attrs.mUserContextId = userContextIdStr.ToInteger(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsDocShell::Cast(mDocShell)->SetOriginAttributes(attrs);
 
   if (OwnerIsMozBrowserOrAppFrame()) {
     // For inproc frames, set the docshell properties.
     nsAutoString name;
     if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
@@ -3356,39 +3352,25 @@ nsFrameLoader::GetNewTabContext(MutableT
   }
   if (!userContextIdStr.IsEmpty()) {
     nsresult err;
     uint32_t userContextId = userContextIdStr.ToInteger(&err);
     NS_ENSURE_SUCCESS(err, err);
     attrs.mUserContextId = userContextId;
   }
 
+  nsAutoString presentationURLStr;
+  mOwnerContent->GetAttr(kNameSpaceID_None,
+                         nsGkAtoms::mozpresentation,
+                         presentationURLStr);
+
   bool tabContextUpdated =
     aTabContext->SetTabContext(OwnerIsMozBrowserFrame(),
+                               mIsPrerendered,
                                ownApp,
                                containingApp,
                                attrs,
-                               signedPkgOrigin);
+                               signedPkgOrigin,
+                               presentationURLStr);
   NS_ENSURE_STATE(tabContextUpdated);
 
   return NS_OK;
 }
-
-nsresult
-nsFrameLoader::PopulateUserContextIdFromAttribute(DocShellOriginAttributes& aAttr)
-{
-  if (aAttr.mUserContextId ==
-        nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID)  {
-    // Grab the userContextId from owner if XUL
-    nsAutoString userContextIdStr;
-    int32_t namespaceID = mOwnerContent->GetNameSpaceID();
-    if ((namespaceID == kNameSpaceID_XUL) &&
-        mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid,
-                               userContextIdStr) &&
-        !userContextIdStr.IsEmpty()) {
-      nsresult rv;
-      aAttr.mUserContextId = userContextIdStr.ToInteger(&rv);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  return NS_OK;
-}
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -34,19 +34,16 @@ class nsIInProcessContentFrameMessageMan
 class AutoResetInShow;
 class AutoResetInFrameSwap;
 class nsITabParent;
 class nsIDocShellTreeItem;
 class nsIDocShellTreeOwner;
 class mozIApplication;
 
 namespace mozilla {
-
-class DocShellOriginAttributes;
-
 namespace dom {
 class ContentParent;
 class PBrowserParent;
 class TabParent;
 class MutableTabContext;
 } // namespace dom
 
 namespace ipc {
@@ -338,19 +335,16 @@ private:
                             const nsACString& aPackageId = EmptyCString());
 
   enum TabParentChange {
     eTabParentRemoved,
     eTabParentChanged
   };
   void MaybeUpdatePrimaryTabParent(TabParentChange aChange);
 
-  nsresult
-  PopulateUserContextIdFromAttribute(mozilla::DocShellOriginAttributes& aAttr);
-
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   mozilla::dom::Element* mOwnerContent; // WEAK
 
   // After the frameloader has been removed from the DOM but before all of the
   // messages from the frame have been received, we keep a strong reference to
   // our <browser> element.
   RefPtr<mozilla::dom::Element> mOwnerContentStrong;
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -597,17 +597,16 @@ GK_ATOM(menulist, "menulist")
 GK_ATOM(menupopup, "menupopup")
 GK_ATOM(menuseparator, "menuseparator")
 GK_ATOM(message, "message")
 GK_ATOM(meta, "meta")
 GK_ATOM(referrer, "referrer")
 GK_ATOM(referrerpolicy, "referrerpolicy")
 GK_ATOM(meter, "meter")
 GK_ATOM(method, "method")
-GK_ATOM(microdataProperties, "microdataProperties")
 GK_ATOM(middle, "middle")
 GK_ATOM(min, "min")
 GK_ATOM(minheight, "minheight")
 GK_ATOM(minimum_scale, "minimum-scale")
 GK_ATOM(minpos, "minpos")
 GK_ATOM(minusSign, "minus-sign")
 GK_ATOM(minwidth, "minwidth")
 GK_ATOM(_mixed, "mixed")
@@ -1009,16 +1008,17 @@ GK_ATOM(position, "position")
 GK_ATOM(poster, "poster")
 GK_ATOM(pre, "pre")
 GK_ATOM(preceding, "preceding")
 GK_ATOM(precedingSibling, "preceding-sibling")
 GK_ATOM(predicate, "predicate")
 GK_ATOM(prefix, "prefix")
 GK_ATOM(preload, "preload")
 GK_ATOM(prerendered, "prerendered")
+GK_ATOM(mozpresentation, "mozpresentation")
 GK_ATOM(preserve, "preserve")
 GK_ATOM(preserveSpace, "preserve-space")
 GK_ATOM(preventdefault, "preventdefault")
 GK_ATOM(primary, "primary")
 GK_ATOM(print, "print")
 GK_ATOM(priority, "priority")
 GK_ATOM(processingInstruction, "processing-instruction")
 GK_ATOM(profile, "profile")
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -24,18 +24,22 @@
 #include "nsIDocShell.h"
 #include "nsISelectionController.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIContentViewer.h"
 #include "nsFocusManager.h"
 #include "nsCopySupport.h"
 #include "nsIClipboard.h"
+#include "ContentEventHandler.h"
+#include "nsContentUtils.h"
+#include "nsIWordBreaker.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasicEvents.h"
+#include "mozilla/TextEvents.h"
 #include "mozilla/dom/Selection.h"
 
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
 
 using namespace mozilla;
 
 const char * const sSelectAllString = "cmd_selectAll";
@@ -981,16 +985,173 @@ NS_IMETHODIMP
 nsClipboardDragDropHookCommand::GetCommandStateParams(const char *aCommandName,
                                                       nsICommandParams *aParams,
                                                       nsISupports *aCommandContext)
 {
   NS_ENSURE_ARG_POINTER(aParams);
   return aParams->SetBooleanValue("state_enabled", true);
 }
 
+class nsLookUpDictionaryCommand final : public nsIControllerCommand
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICONTROLLERCOMMAND
+
+private:
+  virtual ~nsLookUpDictionaryCommand()
+  {
+  }
+};
+
+NS_IMPL_ISUPPORTS(nsLookUpDictionaryCommand, nsIControllerCommand)
+
+NS_IMETHODIMP
+nsLookUpDictionaryCommand::IsCommandEnabled(
+                             const char* aCommandName,
+                             nsISupports* aCommandContext,
+                             bool* aRetval)
+{
+  *aRetval = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLookUpDictionaryCommand::GetCommandStateParams(const char* aCommandName,
+                                                 nsICommandParams* aParams,
+                                                 nsISupports* aCommandContext)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsLookUpDictionaryCommand::DoCommand(const char* aCommandName,
+                                     nsISupports *aCommandContext)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsLookUpDictionaryCommand::DoCommandParams(const char* aCommandName,
+                                           nsICommandParams* aParams,
+                                           nsISupports* aCommandContext)
+{
+  if (NS_WARN_IF(!nsContentUtils::IsSafeToRunScript())) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  int32_t x;
+  int32_t y;
+
+  nsresult rv = aParams->GetLongValue("x", &x);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aParams->GetLongValue("y", &y);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  LayoutDeviceIntPoint point(x, y);
+
+  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aCommandContext);
+  if (NS_WARN_IF(!window)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsIDocShell* docShell = window->GetDocShell();
+  if (NS_WARN_IF(!docShell)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
+  if (NS_WARN_IF(!presShell)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsPresContext* presContext = presShell->GetPresContext();
+  if (NS_WARN_IF(!presContext)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIWidget> widget = presContext->GetRootWidget();
+  if (NS_WARN_IF(!widget)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  WidgetQueryContentEvent charAt(true, eQueryCharacterAtPoint, widget);
+  charAt.mRefPoint.x = x;
+  charAt.mRefPoint.y = y;
+  ContentEventHandler handler(presContext);
+  handler.OnQueryCharacterAtPoint(&charAt);
+
+  if (NS_WARN_IF(!charAt.mSucceeded) ||
+      charAt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
+    return NS_ERROR_FAILURE;
+  }
+
+  WidgetQueryContentEvent textContent(true, eQueryTextContent, widget);
+  // OSX 10.7 queries 50 characters before/after current point.  So we fetch
+  // same length.
+  uint32_t offset = charAt.mReply.mOffset;
+  if (offset > 50) {
+    offset -= 50;
+  } else {
+    offset = 0;
+  }
+  textContent.InitForQueryTextContent(offset, 100);
+  handler.OnQueryTextContent(&textContent);
+  if (NS_WARN_IF(!textContent.mSucceeded ||
+                 textContent.mReply.mString.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // XXX nsIWordBreaker doesn't use contextual breaker.
+  // If OS provides it, widget should use it if contextual breaker is needed.
+  nsCOMPtr<nsIWordBreaker> wordBreaker = nsContentUtils::WordBreaker();
+  if (NS_WARN_IF(!wordBreaker)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsWordRange range =
+    wordBreaker->FindWord(textContent.mReply.mString.get(),
+                          textContent.mReply.mString.Length(),
+                          charAt.mReply.mOffset - offset);
+  if (range.mEnd == range.mBegin) {
+    return NS_ERROR_FAILURE;
+  }
+  range.mBegin += offset;
+  range.mEnd += offset;
+
+  WidgetQueryContentEvent lookUpContent(true, eQueryTextContent, widget);
+  lookUpContent.InitForQueryTextContent(range.mBegin,
+                                        range.mEnd - range.mBegin);
+  lookUpContent.RequestFontRanges();
+  handler.OnQueryTextContent(&lookUpContent);
+  if (NS_WARN_IF(!lookUpContent.mSucceeded ||
+                 lookUpContent.mReply.mString.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  WidgetQueryContentEvent charRect(true, eQueryTextRect, widget);
+  charRect.InitForQueryTextRect(range.mBegin, range.mEnd - range.mBegin);
+  handler.OnQueryTextRect(&charRect);
+  if (NS_WARN_IF(!charRect.mSucceeded)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  widget->LookUpDictionary(lookUpContent.mReply.mString,
+                           lookUpContent.mReply.mFontRanges,
+                           charRect.mReply.mWritingMode.IsVertical(),
+                           charRect.mReply.mRect.TopLeft());
+
+  return NS_OK;
+}
+
 /*---------------------------------------------------------------------------
 
   RegisterWindowCommands
 
 ----------------------------------------------------------------------------*/
 
 #define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName)                \
   {                                                                 \
@@ -1092,10 +1253,12 @@ nsWindowCommandRegistration::RegisterWin
 
 #if 0   // Remove unless needed again, bug 204777
   NS_REGISTER_ONE_COMMAND(nsGoBackCommand, "cmd_browserBack");
   NS_REGISTER_ONE_COMMAND(nsGoForwardCommand, "cmd_browserForward");
 #endif
 
   NS_REGISTER_ONE_COMMAND(nsClipboardDragDropHookCommand, "cmd_clipboardDragDropHook");
 
+  NS_REGISTER_ONE_COMMAND(nsLookUpDictionaryCommand, "cmd_lookUpDictionary");
+
   return rv;
 }
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -19,17 +19,17 @@
 #include "nsHostObjectURI.h"
 #include "nsIMemoryReporter.h"
 #include "nsIPrincipal.h"
 #include "nsIUUIDGenerator.h"
 #include "nsNetUtil.h"
 
 using mozilla::dom::BlobImpl;
 using mozilla::ErrorResult;
-using mozilla::LoadInfo;
+using mozilla::net::LoadInfo;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, DOMMediaStream, or MediaSource
   nsCOMPtr<nsISupports> mObject;
   nsCOMPtr<nsIPrincipal> mPrincipal;
@@ -715,17 +715,17 @@ nsFontTableProtocolHandler::NewURI(const
     NS_ENSURE_SUCCESS(rv, rv);
 
     uri->SetRef(aSpec);
   } else {
     // Relative URIs (other than #ref) are not meaningful within the
     // fonttable: scheme.
     // If aSpec is a relative URI -other- than a bare #ref,
     // this will leave uri empty, and we'll return a failure code below.
-    uri = new nsSimpleURI();
+    uri = new mozilla::net::nsSimpleURI();
     uri->SetSpec(aSpec);
   }
 
   bool schemeIs;
   if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) {
     NS_WARNING("Non-fonttable spec in nsFontTableProtocolHander");
     return NS_ERROR_NOT_AVAILABLE;
   }
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -13,32 +13,32 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/URIUtils.h"
 
 static NS_DEFINE_CID(kHOSTOBJECTURICID, NS_HOSTOBJECTURI_CID);
 
 static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
                      NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
 
-NS_IMPL_ADDREF_INHERITED(nsHostObjectURI, nsSimpleURI)
-NS_IMPL_RELEASE_INHERITED(nsHostObjectURI, nsSimpleURI)
+NS_IMPL_ADDREF_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
+NS_IMPL_RELEASE_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
 
 NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
   NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
   if (aIID.Equals(kHOSTOBJECTURICID))
     foundInterface = static_cast<nsIURI*>(this);
   else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
     // Need to return explicitly here, because if we just set foundInterface
     // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
     // nsSimplURI::QueryInterface and finding something for this CID.
     *aInstancePtr = nullptr;
     return NS_NOINTERFACE;
   }
   else
-NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
 
 // nsIURIWithPrincipal methods:
 
 NS_IMETHODIMP
 nsHostObjectURI::GetPrincipal(nsIPrincipal** aPrincipal)
 {
   NS_IF_ADDREF(*aPrincipal = mPrincipal);
 
@@ -58,48 +58,48 @@ nsHostObjectURI::GetPrincipalUri(nsIURI*
   return NS_OK;
 }
 
 // nsISerializable methods:
 
 NS_IMETHODIMP
 nsHostObjectURI::Read(nsIObjectInputStream* aStream)
 {
-  nsresult rv = nsSimpleURI::Read(aStream);
+  nsresult rv = mozilla::net::nsSimpleURI::Read(aStream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupports> supports;
   rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mPrincipal = do_QueryInterface(supports, &rv);
   return rv;
 }
 
 NS_IMETHODIMP
 nsHostObjectURI::Write(nsIObjectOutputStream* aStream)
 {
-  nsresult rv = nsSimpleURI::Write(aStream);
+  nsresult rv = mozilla::net::nsSimpleURI::Write(aStream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
                                         NS_GET_IID(nsIPrincipal),
                                         true);
 }
 
 // nsIIPCSerializableURI methods:
 void
 nsHostObjectURI::Serialize(mozilla::ipc::URIParams& aParams)
 {
   using namespace mozilla::ipc;
 
   HostObjectURIParams hostParams;
   URIParams simpleParams;
 
-  nsSimpleURI::Serialize(simpleParams);
+  mozilla::net::nsSimpleURI::Serialize(simpleParams);
   hostParams.simpleParams() = simpleParams;
 
   if (mPrincipal) {
     PrincipalInfo info;
     nsresult rv = PrincipalToPrincipalInfo(mPrincipal, &info);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
@@ -119,17 +119,17 @@ nsHostObjectURI::Deserialize(const mozil
 
   if (aParams.type() != URIParams::THostObjectURIParams) {
       NS_ERROR("Received unknown parameters from the other process!");
       return false;
   }
 
   const HostObjectURIParams& hostParams = aParams.get_HostObjectURIParams();
 
-  if (!nsSimpleURI::Deserialize(hostParams.simpleParams())) {
+  if (!mozilla::net::nsSimpleURI::Deserialize(hostParams.simpleParams())) {
     return false;
   }
   if (hostParams.principal().type() == OptionalPrincipalInfo::Tvoid_t) {
     return true;
   }
 
   mPrincipal = PrincipalInfoToPrincipal(hostParams.principal().get_PrincipalInfo());
   return mPrincipal != nullptr;
@@ -141,22 +141,22 @@ nsHostObjectURI::SetScheme(const nsACStr
   // Disallow setting the scheme, since that could cause us to be associated
   // with a different protocol handler that doesn't expect us to be carrying
   // around a principal with nsIURIWithPrincipal.
   return NS_ERROR_FAILURE;
 }
 
 // nsIURI methods:
 nsresult
-nsHostObjectURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
                                nsIURI** aClone)
 {
   nsCOMPtr<nsIURI> simpleClone;
   nsresult rv =
-    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
+    mozilla::net::nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   RefPtr<nsHostObjectURI> uriCheck;
   rv = simpleClone->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(uriCheck));
   MOZ_ASSERT(NS_SUCCEEDED(rv) && uriCheck);
 #endif
 
@@ -165,33 +165,33 @@ nsHostObjectURI::CloneInternal(nsSimpleU
   u->mPrincipal = mPrincipal;
 
   simpleClone.forget(aClone);
   return NS_OK;
 }
 
 /* virtual */ nsresult
 nsHostObjectURI::EqualsInternal(nsIURI* aOther,
-                                nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                                mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
                                 bool* aResult)
 {
   if (!aOther) {
     *aResult = false;
     return NS_OK;
   }
   
   RefPtr<nsHostObjectURI> otherUri;
   aOther->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(otherUri));
   if (!otherUri) {
     *aResult = false;
     return NS_OK;
   }
 
   // Compare the member data that our base class knows about.
-  if (!nsSimpleURI::EqualsInternal(otherUri, aRefHandlingMode)) {
+  if (!mozilla::net::nsSimpleURI::EqualsInternal(otherUri, aRefHandlingMode)) {
     *aResult = false;
     return NS_OK;
   }
 
   // Compare the piece of additional member data that we add to base class.
   if (mPrincipal && otherUri->mPrincipal) {
     // Both of us have mPrincipals. Compare them.
     return mPrincipal->Equals(otherUri->mPrincipal, aResult);
--- a/dom/base/nsHostObjectURI.h
+++ b/dom/base/nsHostObjectURI.h
@@ -16,26 +16,26 @@
 #include "nsSimpleURI.h"
 #include "nsIIPCSerializableURI.h"
 
 /**
  * These URIs refer to host objects: Blobs, with scheme "blob",
  * MediaStreams, with scheme "mediastream", and MediaSources, with scheme
  * "mediasource".
  */
-class nsHostObjectURI : public nsSimpleURI,
+class nsHostObjectURI : public mozilla::net::nsSimpleURI,
                         public nsIURIWithPrincipal
 {
 public:
   explicit nsHostObjectURI(nsIPrincipal* aPrincipal) :
-      nsSimpleURI(), mPrincipal(aPrincipal)
+      mozilla::net::nsSimpleURI(), mPrincipal(aPrincipal)
   {}
 
   // For use only from deserialization
-  nsHostObjectURI() : nsSimpleURI() {}
+  nsHostObjectURI() : mozilla::net::nsSimpleURI() {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIURIWITHPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
   NS_DECL_NSIIPCSERIALIZABLEURI
 
   NS_IMETHOD SetScheme(const nsACString &aProtocol) override;
@@ -43,17 +43,17 @@ public:
   // Override CloneInternal() and EqualsInternal()
   virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
                                  nsIURI** aClone) override;
   virtual nsresult EqualsInternal(nsIURI* aOther,
                                   RefHandlingEnum aRefHandlingMode,
                                   bool* aResult) override;
 
   // Override StartClone to hand back a nsHostObjectURI
-  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */) override
+  virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum /* unused */) override
   { return new nsHostObjectURI(); }
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
 protected:
   virtual ~nsHostObjectURI() {}
 };
 
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -62,16 +62,21 @@ interface nsIFrameLoader : nsISupports
   void switchProcessAndLoadURI(in nsIURI aURI, in ACString aPackageId);
 
   /**
    * Puts the frameloader in prerendering mode.
    */
   void setIsPrerendered();
 
   /**
+   * Make the prerendered frameloader being active (and clear isPrerendered flag).
+   */
+  void makePrerenderedLoaderActive();
+
+  /**
    * Destroy the frame loader and everything inside it. This will
    * clear the weak owner content reference.
    */
   void destroy();
 
   /**
    * Find out whether the loader's frame is at too great a depth in
    * the frame tree.  This can be used to decide what operations may
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -107,16 +107,17 @@
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 static const char *kPrefJavaMIME = "plugin.java.mime";
 static const char *kPrefYoutubeRewrite = "plugins.rewrite_youtube_embeds";
 static const char *kPrefBlockURIs = "browser.safebrowsing.blockedURIs.enabled";
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::net;
 
 static LogModule*
 GetObjectLog()
 {
   static LazyLogModule sLog("objlc");
   return sLog;
 }
 
@@ -3115,26 +3116,28 @@ nsObjectLoadingContent::LoadFallback(Fal
 
   // Do a breadth-first traverse of node tree with the current element as root,
   // looking for the first embed we can find.
   nsTArray<nsINodeList*> childNodes;
   if ((thisContent->IsHTMLElement(nsGkAtoms::object) ||
        thisContent->IsHTMLElement(nsGkAtoms::applet)) &&
       (aType == eFallbackUnsupported ||
        aType == eFallbackDisabled ||
-       aType == eFallbackBlocklisted))
+       aType == eFallbackBlocklisted ||
+       aType == eFallbackAlternate))
   {
     for (nsIContent* child = thisContent->GetFirstChild(); child;
          child = child->GetNextNode(thisContent)) {
       if (aType != eFallbackAlternate &&
           !child->IsHTMLElement(nsGkAtoms::param) &&
           nsStyleUtil::IsSignificantChild(child, true, false)) {
         aType = eFallbackAlternate;
       }
-      if (child->IsHTMLElement(nsGkAtoms::embed)) {
+      if (child->IsHTMLElement(nsGkAtoms::embed) &&
+          thisContent->IsHTMLElement(nsGkAtoms::object)) {
         HTMLSharedObjectElement* object = static_cast<HTMLSharedObjectElement*>(child);
         if (object) {
           object->StartObjectLoad(true, true);
         }
       }
     }
   }
 
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -1314,26 +1314,30 @@ nsPlainTextSerializer::AddToLine(const c
                                     mCurrentLine.Length(), goodSpace);
         if (goodSpace != NS_LINEBREAKER_NEED_MORE_TEXT &&
             nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace-1))) {
           --goodSpace;    // adjust the position since line breaker returns a position next to space
         }
       }
       // fallback if the line breaker is unavailable or failed
       if (!mLineBreaker) {
-        goodSpace = mWrapColumn-prefixwidth;
-        while (goodSpace >= 0 &&
-               !nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
-          goodSpace--;
+        if (mCurrentLine.IsEmpty() || mWrapColumn < prefixwidth) {
+          goodSpace = NS_LINEBREAKER_NEED_MORE_TEXT;
+        } else {
+          goodSpace = std::min(mWrapColumn - prefixwidth, mCurrentLine.Length() - 1);
+          while (goodSpace >= 0 &&
+                 !nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
+            goodSpace--;
+          }
         }
       }
       
       nsAutoString restOfLine;
       if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) {
-        // If we don't found a good place to break, accept long line and
+        // If we didn't find a good place to break, accept long line and
         // try to find another place to break
         goodSpace=(prefixwidth>mWrapColumn+1)?1:mWrapColumn-prefixwidth+1;
         if (mLineBreaker) {
           if ((uint32_t)goodSpace < mCurrentLine.Length())
             goodSpace = mLineBreaker->Next(mCurrentLine.get(), 
                                            mCurrentLine.Length(), goodSpace);
           if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT)
             goodSpace = mCurrentLine.Length();
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -428,16 +428,17 @@ NS_IMPL_CYCLE_COLLECTION(nsScriptLoader,
                          mPendingChildLoaders,
                          mFetchedModules)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptLoader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptLoader)
 
 nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
   : mDocument(aDocument),
+    mParserBlockingBlockerCount(0),
     mBlockerCount(0),
     mNumberOfProcessors(0),
     mEnabled(true),
     mDeferEnabled(false),
     mDocumentParsingDone(false),
     mBlockingDOMContentLoaded(false)
 {
 }
@@ -474,17 +475,17 @@ nsScriptLoader::~nsScriptLoader()
       req;
       req = req->getNext()) {
     req->FireScriptAvailable(NS_ERROR_ABORT);
   }
 
   // Unblock the kids, in case any of them moved to a different document
   // subtree in the meantime and therefore aren't actually going away.
   for (uint32_t j = 0; j < mPendingChildLoaders.Length(); ++j) {
-    mPendingChildLoaders[j]->RemoveExecuteBlocker();
+    mPendingChildLoaders[j]->RemoveParserBlockingScriptExecutionBlocker();
   }
 }
 
 // Helper method for checking if the script element is an event-handler
 // This means that it has both a for-attribute and a event-attribute.
 // Also, if the for-attribute has a value that matches "\s*window\s*",
 // and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an
 // eventhandler. (both matches are case insensitive).
@@ -1454,17 +1455,17 @@ nsScriptLoader::ProcessScriptElement(nsI
       if (request->IsReadyToRun()) {
         // The script is available already. Run it ASAP when the event
         // loop gets a chance to spin.
         ProcessPendingRequestsAsync();
       }
       return true;
     }
 
-    if (request->IsReadyToRun() && ReadyToExecuteScripts()) {
+    if (request->IsReadyToRun() && ReadyToExecuteParserBlockingScripts()) {
       // The request has already been loaded and there are no pending style
       // sheets. If the script comes from the network stream, cheat for
       // performance reasons and avoid a trip through the event loop.
       if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) {
         return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
       }
       // Otherwise, we've got a document.written script, make a trip through
       // the event loop to hide the preload effects from the scripts on the
@@ -1517,32 +1518,32 @@ nsScriptLoader::ProcessScriptElement(nsI
       mLoadingAsyncRequests.AppendElement(request);
     } else {
       AddDeferRequest(request);
     }
     return false;
   }
   request->mProgress = nsScriptLoadRequest::Progress::Ready;
   if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
-      (!ReadyToExecuteScripts() || !mXSLTRequests.isEmpty())) {
+      (!ReadyToExecuteParserBlockingScripts() || !mXSLTRequests.isEmpty())) {
     // Need to maintain order for XSLT-inserted scripts
     NS_ASSERTION(!mParserBlockingRequest,
         "Parser-blocking scripts and XSLT scripts in the same doc!");
     mXSLTRequests.AppendElement(request);
     return true;
   }
   if (aElement->GetParserCreated() == NOT_FROM_PARSER) {
     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
         "A script-inserted script is inserted without an update batch?");
     nsContentUtils::AddScriptRunner(new nsScriptRequestProcessor(this,
                                                                  request));
     return false;
   }
   if (aElement->GetParserCreated() == FROM_PARSER_NETWORK &&
-      !ReadyToExecuteScripts()) {
+      !ReadyToExecuteParserBlockingScripts()) {
     NS_ASSERTION(!mParserBlockingRequest,
         "There can be only one parser-blocking script at a time");
     mParserBlockingRequest = request;
     NS_ASSERTION(mXSLTRequests.isEmpty(),
         "Parser-blocking scripts and XSLT scripts in the same doc!");
     return true;
   }
   // We now have a document.written inline script or we have an inline script
@@ -1600,17 +1601,17 @@ nsScriptLoader::ProcessOffThreadRequest(
       request->LoadFailed();
     }
     return rv;
   }
 
   aRequest->SetReady();
 
   if (aRequest == mParserBlockingRequest) {
-    if (!ReadyToExecuteScripts()) {
+    if (!ReadyToExecuteParserBlockingScripts()) {
       // If not ready to execute scripts, schedule an async call to
       // ProcessPendingRequests to handle it.
       ProcessPendingRequestsAsync();
       return NS_OK;
     }
 
     // Same logic as in top of ProcessPendingRequests.
     mParserBlockingRequest = nullptr;
@@ -2040,63 +2041,67 @@ nsScriptLoader::ProcessPendingRequestsAs
 
 void
 nsScriptLoader::ProcessPendingRequests()
 {
   RefPtr<nsScriptLoadRequest> request;
 
   if (mParserBlockingRequest &&
       mParserBlockingRequest->IsReadyToRun() &&
-      ReadyToExecuteScripts()) {
+      ReadyToExecuteParserBlockingScripts()) {
     request.swap(mParserBlockingRequest);
     UnblockParser(request);
     ProcessRequest(request);
     if (request->mWasCompiledOMT) {
       mDocument->UnblockOnload(false);
     }
     ContinueParserAsync(request);
   }
 
-  while (ReadyToExecuteScripts() &&
+  while (ReadyToExecuteParserBlockingScripts() &&
          !mXSLTRequests.isEmpty() &&
          mXSLTRequests.getFirst()->IsReadyToRun()) {
     request = mXSLTRequests.StealFirst();
     ProcessRequest(request);
   }
 
-  while (mEnabled && !mLoadedAsyncRequests.isEmpty()) {
+  while (ReadyToExecuteScripts() && !mLoadedAsyncRequests.isEmpty()) {
     request = mLoadedAsyncRequests.StealFirst();
     if (request->IsModuleRequest()) {
       ProcessRequest(request);
     } else {
       CompileOffThreadOrProcessRequest(request);
     }
   }
 
-  while (mEnabled && !mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
+  while (ReadyToExecuteScripts() &&
+         !mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
          mNonAsyncExternalScriptInsertedRequests.getFirst()->IsReadyToRun()) {
     // Violate the HTML5 spec and execute these in the insertion order in
     // order to make LABjs and the "order" plug-in for RequireJS work with
     // their Gecko-sniffed code path. See
     // http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
     request = mNonAsyncExternalScriptInsertedRequests.StealFirst();
     ProcessRequest(request);
   }
 
   if (mDocumentParsingDone && mXSLTRequests.isEmpty()) {
-    while (!mDeferRequests.isEmpty() && mDeferRequests.getFirst()->IsReadyToRun()) {
+    while (ReadyToExecuteScripts() &&
+           !mDeferRequests.isEmpty() &&
+           mDeferRequests.getFirst()->IsReadyToRun()) {
       request = mDeferRequests.StealFirst();
       ProcessRequest(request);
     }
   }
 
-  while (!mPendingChildLoaders.IsEmpty() && ReadyToExecuteScripts()) {
+  while (!mPendingChildLoaders.IsEmpty() &&
+         ReadyToExecuteParserBlockingScripts()) {
     RefPtr<nsScriptLoader> child = mPendingChildLoaders[0];
     mPendingChildLoaders.RemoveElementAt(0);
-    child->RemoveExecuteBlocker();
+    child->RemoveParserBlockingScriptExecutionBlocker();
   }
 
   if (mDocumentParsingDone && mDocument && !mParserBlockingRequest &&
       mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
       mXSLTRequests.isEmpty() && mDeferRequests.isEmpty() &&
       MaybeRemovedDeferRequests()) {
     return ProcessPendingRequests();
   }
@@ -2110,29 +2115,29 @@ nsScriptLoader::ProcessPendingRequests()
     // OK to unblock onload synchronously here, since callers must be
     // prepared for the world changing anyway.
     mDocumentParsingDone = false;
     mDocument->UnblockOnload(true);
   }
 }
 
 bool
-nsScriptLoader::ReadyToExecuteScripts()
+nsScriptLoader::ReadyToExecuteParserBlockingScripts()
 {
-  // Make sure the SelfReadyToExecuteScripts check is first, so that
-  // we don't block twice on an ancestor.
-  if (!SelfReadyToExecuteScripts()) {
+  // Make sure the SelfReadyToExecuteParserBlockingScripts check is first, so
+  // that we don't block twice on an ancestor.
+  if (!SelfReadyToExecuteParserBlockingScripts()) {
     return false;
   }
 
   for (nsIDocument* doc = mDocument; doc; doc = doc->GetParentDocument()) {
     nsScriptLoader* ancestor = doc->ScriptLoader();
-    if (!ancestor->SelfReadyToExecuteScripts() &&
+    if (!ancestor->SelfReadyToExecuteParserBlockingScripts() &&
         ancestor->AddPendingChildLoader(this)) {
-      AddExecuteBlocker();
+      AddParserBlockingScriptExecutionBlocker();
       return false;
     }
   }
 
   if (mDocument && !mDocument->IsMasterDocument()) {
     RefPtr<ImportManager> im = mDocument->ImportManager();
     RefPtr<ImportLoader> loader = im->Find(mDocument);
     MOZ_ASSERT(loader, "How can we have an import document without a loader?");
@@ -2148,17 +2153,18 @@ nsScriptLoader::ReadyToExecuteScripts()
     // which is the neares one to us in the order.
     RefPtr<ImportLoader> lastPred = im->GetNearestPredecessor(referrer);
     if (!lastPred) {
       // If there is no predecessor we can run.
       return true;
     }
 
     nsCOMPtr<nsIDocument> doc = lastPred->GetDocument();
-    if (lastPred->IsBlocking() || !doc || (doc && !doc->ScriptLoader()->SelfReadyToExecuteScripts())) {
+    if (lastPred->IsBlocking() || !doc ||
+        !doc->ScriptLoader()->SelfReadyToExecuteParserBlockingScripts()) {
       // Document has not been created yet or it was created but not ready.
       // Either case we are blocked by it. The ImportLoader will take care
       // of blocking us, and adding the pending child loader to the blocking
       // ScriptLoader when it's possible (at this point the blocking loader
       // might not have created the document/ScriptLoader)
       lastPred->AddBlockedScriptLoader(this);
       // As more imports are parsed, this can change, let's cache what we
       // blocked, so it can be later updated if needed (see: ImportLoader::Updater).
--- a/dom/base/nsScriptLoader.h
+++ b/dom/base/nsScriptLoader.h
@@ -337,25 +337,42 @@ public:
   {
     if (!mEnabled && aEnabled) {
       ProcessPendingRequestsAsync();
     }
     mEnabled = aEnabled;
   }
 
   /**
-   * Add/remove blocker. Blockers will stop scripts from executing, but not
-   * from loading.
+   * Add/remove a blocker for parser-blocking scripts (and XSLT
+   * scripts). Blockers will stop such scripts from executing, but not from
+   * loading.
+   */
+  void AddParserBlockingScriptExecutionBlocker()
+  {
+    ++mParserBlockingBlockerCount;
+  }
+  void RemoveParserBlockingScriptExecutionBlocker()
+  {
+    if (!--mParserBlockingBlockerCount && ReadyToExecuteScripts()) {
+      ProcessPendingRequestsAsync();
+    }
+  }
+
+  /**
+   * Add/remove a blocker for execution of all scripts.  Blockers will stop
+   * scripts from executing, but not from loading.
    */
   void AddExecuteBlocker()
   {
     ++mBlockerCount;
   }
   void RemoveExecuteBlocker()
   {
+    MOZ_ASSERT(mBlockerCount);
     if (!--mBlockerCount) {
       ProcessPendingRequestsAsync();
     }
   }
 
   /**
    * Convert the given buffer to a UTF-16 string.
    * @param aChannel     Channel corresponding to the data. May be null.
@@ -494,27 +511,36 @@ private:
    * are any. Note that this is a no-op if there aren't any currently pending
    * requests.
    *
    * This function is virtual to allow cross-library calls to SetEnabled()
    */
   virtual void ProcessPendingRequestsAsync();
 
   /**
-   * If true, the loader is ready to execute scripts, and so are all its
-   * ancestors.  If the loader itself is ready but some ancestor is not, this
-   * function will add an execute blocker and ask the ancestor to remove it
+   * If true, the loader is ready to execute parser-blocking scripts, and so are
+   * all its ancestors.  If the loader itself is ready but some ancestor is not,
+   * this function will add an execute blocker and ask the ancestor to remove it
    * once it becomes ready.
    */
-  bool ReadyToExecuteScripts();
+  bool ReadyToExecuteParserBlockingScripts();
 
   /**
-   * Return whether just this loader is ready to execute scripts.
+   * Return whether just this loader is ready to execute parser-blocking
+   * scripts.
    */
-  bool SelfReadyToExecuteScripts()
+  bool SelfReadyToExecuteParserBlockingScripts()
+  {
+    return ReadyToExecuteScripts() && !mParserBlockingBlockerCount;
+  }
+
+  /**
+   * Return whether this loader is ready to execute scripts in general.
+   */
+  bool ReadyToExecuteScripts()
   {
     return mEnabled && !mBlockerCount;
   }
 
   nsresult AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest);
   nsresult ProcessRequest(nsScriptLoadRequest* aRequest);
   nsresult CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest);
   void FireScriptAvailable(nsresult aResult,
@@ -596,16 +622,17 @@ private:
   struct PreloadURIComparator {
     bool Equals(const PreloadInfo &aPi, nsIURI * const &aURI) const;
   };
   nsTArray<PreloadInfo> mPreloads;
 
   nsCOMPtr<nsIScriptElement> mCurrentScript;
   nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
   nsTArray< RefPtr<nsScriptLoader> > mPendingChildLoaders;
+  uint32_t mParserBlockingBlockerCount;
   uint32_t mBlockerCount;
   uint32_t mNumberOfProcessors;
   bool mEnabled;
   bool mDeferEnabled;
   bool mDocumentParsingDone;
   bool mBlockingDOMContentLoaded;
 
   // Module map
--- a/dom/battery/test/marionette/manifest.ini
+++ b/dom/battery/test/marionette/manifest.ini
@@ -1,12 +1,10 @@
 [DEFAULT]
-b2g = true
-browser = false
-qemu = true
+run-if = buildapp == 'b2g'
 
 [test_battery_level.js]
 [test_battery_status_charging.js]
 [test_battery_status_discharging.js]
 [test_battery_status_full.js]
 [test_battery_status_not_charging.js]
 [test_battery_status_unknown.js]
 [test_deprecated_battery_level.js]
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -12,21 +12,21 @@
  */
 #ifndef mozilla_dom_BindingDeclarations_h__
 #define mozilla_dom_BindingDeclarations_h__
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 #include "mozilla/Maybe.h"
-#include "mozilla/OwningNonNull.h"
+#include "mozilla/RootedOwningNonNull.h"
+#include "mozilla/RootedRefPtr.h"
 
 #include "mozilla/dom/DOMString.h"
 
-#include "nsAutoPtr.h" // for nsRefPtr member variables
 #include "nsCOMPtr.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 class nsWrapperCache;
 
 namespace mozilla {
 namespace dom {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -569,20 +569,16 @@ DOMInterfaces = {
 'HTMLOListElement': {
     'nativeType' : 'mozilla::dom::HTMLSharedListElement'
 },
 
 'HTMLParamElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLPropertiesCollection': {
-    'headerFile': 'HTMLPropertiesCollection.h',
-},
-
 'HTMLQuoteElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
 'HTMLTextAreaElement': {
     'binaryNames': {
         'textLength': 'getTextLength'
     }
@@ -924,20 +920,16 @@ DOMInterfaces = {
 'PromiseDebugging': {
     'concrete': False,
 },
 
 'PromiseNativeHandler': {
     'wrapperCache': False,
 },
 
-'PropertyNodeList': {
-    'headerFile': 'HTMLPropertiesCollection.h',
-},
-
 'PushEvent': {
     'headerFile': 'ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::PushEvent',
 },
 
 'PushMessageData': {
     'headerFile': 'ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::PushMessageData',
--- a/dom/bindings/CallbackFunction.h
+++ b/dom/bindings/CallbackFunction.h
@@ -51,14 +51,23 @@ public:
     return mCallback && JS::ObjectIsMarkedGray(mCallback);
   }
 
 protected:
   explicit CallbackFunction(CallbackFunction* aCallbackFunction)
     : CallbackObject(aCallbackFunction)
   {
   }
+
+  // See CallbackObject for an explanation of the arguments.
+  CallbackFunction(JSContext* aCx, JS::Handle<JSObject*> aCallable,
+                   nsIGlobalObject* aIncumbentGlobal,
+                   const FastCallbackConstructor&)
+    : CallbackObject(aCx, aCallable, aIncumbentGlobal,
+                     FastCallbackConstructor())
+  {
+  }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackFunction_h
--- a/dom/bindings/CallbackInterface.h
+++ b/dom/bindings/CallbackInterface.h
@@ -21,31 +21,39 @@
 namespace mozilla {
 namespace dom {
 
 class CallbackInterface : public CallbackObject
 {
 public:
   // See CallbackObject for an explanation of the arguments.
   explicit CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallback,
-                             nsIGlobalObject *aIncumbentGlobal)
+                             nsIGlobalObject* aIncumbentGlobal)
     : CallbackObject(aCx, aCallback, aIncumbentGlobal)
   {
   }
 
   // See CallbackObject for an explanation of the arguments.
   explicit CallbackInterface(JS::Handle<JSObject*> aCallback,
                              JS::Handle<JSObject*> aAsyncStack,
                              nsIGlobalObject* aIncumbentGlobal)
     : CallbackObject(aCallback, aAsyncStack, aIncumbentGlobal)
   {
   }
 
 protected:
   bool GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                            JS::MutableHandle<JS::Value> aCallable);
 
+  // See CallbackObject for an explanation of the arguments.
+  CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallable,
+                    nsIGlobalObject* aIncumbentGlobal,
+                    const FastCallbackConstructor&)
+    : CallbackObject(aCx, aCallable, aIncumbentGlobal,
+                     FastCallbackConstructor())
+  {
+  }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackFunction_h
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -42,16 +42,37 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCreationStack)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIncumbentJSGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
+void
+CallbackObject::Trace(JSTracer* aTracer)
+{
+  JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
+  JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
+  JS::TraceEdge(aTracer, &mIncumbentJSGlobal,
+                "CallbackObject.mIncumbentJSGlobal");
+}
+
+void
+CallbackObject::HoldJSObjectsIfMoreThanOneOwner()
+{
+  MOZ_ASSERT(mRefCnt.get() > 0);
+  if (mRefCnt.get() > 1) {
+    mozilla::HoldJSObjects(this);
+  } else {
+    // We can just forget all our stuff.
+    ClearJSReferences();
+  }
+}
+
 CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
                                      ErrorResult& aRv,
                                      const char* aExecutionReason,
                                      ExceptionHandling aExceptionHandling,
                                      JSCompartment* aCompartment,
                                      bool aIsJSImplementedWebIDL)
   : mCx(nullptr)
   , mCompartment(aCompartment)
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -20,21 +20,23 @@
 #include "nsISupports.h"
 #include "nsISupportsImpl.h"
 #include "nsCycleCollectionParticipant.h"
 #include "jswrapper.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsWrapperCache.h"
 #include "nsJSEnvironment.h"
 #include "xpcpublic.h"
 #include "jsapi.h"
+#include "js/TracingAPI.h"
 
 namespace mozilla {
 namespace dom {
 
 #define DOM_CALLBACKOBJECT_IID \
 { 0xbe74c190, 0x6d76, 0x4991, \
  { 0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b } }
 
@@ -49,17 +51,17 @@ public:
   // The caller may pass a global object which will act as an override for the
   // incumbent script settings object when the callback is invoked (overriding
   // the entry point computed from aCallback). If no override is required, the
   // caller should pass null.  |aCx| is used to capture the current
   // stack, which is later used as an async parent when the callback
   // is invoked.  aCx can be nullptr, in which case no stack is
   // captured.
   explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
-                          nsIGlobalObject *aIncumbentGlobal)
+                          nsIGlobalObject* aIncumbentGlobal)
   {
     if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
       JS::RootedObject stack(aCx);
       if (!JS::CaptureCurrentStack(aCx, &stack)) {
         JS_ClearPendingException(aCx);
       }
       Init(aCallback, stack, aIncumbentGlobal);
     } else {
@@ -67,17 +69,17 @@ public:
     }
   }
 
   // Instead of capturing the current stack to use as an async parent when the
   // callback is invoked, the caller can use this overload to pass in a stack
   // for that purpose.
   explicit CallbackObject(JS::Handle<JSObject*> aCallback,
                           JS::Handle<JSObject*> aAsyncStack,
-                          nsIGlobalObject *aIncumbentGlobal)
+                          nsIGlobalObject* aIncumbentGlobal)
   {
     Init(aCallback, aAsyncStack, aIncumbentGlobal);
   }
 
   JS::Handle<JSObject*> Callback() const
   {
     JS::ExposeObjectToActiveJS(mCallback);
     return CallbackPreserveColor();
@@ -158,46 +160,92 @@ protected:
     JSObject* thisObj =
       js::UncheckedUnwrap(CallbackPreserveColor());
     JSObject* otherObj =
       js::UncheckedUnwrap(aOther.CallbackPreserveColor());
     return thisObj == otherObj;
   }
 
 private:
-  inline void Init(JSObject* aCallback, JSObject* aCreationStack,
-                   nsIGlobalObject* aIncumbentGlobal)
+  inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
+                         nsIGlobalObject* aIncumbentGlobal)
   {
     MOZ_ASSERT(aCallback && !mCallback);
     // Set script objects before we hold, on the off chance that a GC could
     // somehow happen in there... (which would be pretty odd, granted).
     mCallback = aCallback;
     mCreationStack = aCreationStack;
     if (aIncumbentGlobal) {
       mIncumbentGlobal = aIncumbentGlobal;
       mIncumbentJSGlobal = aIncumbentGlobal->GetGlobalJSObject();
     }
+  }
+
+  inline void Init(JSObject* aCallback, JSObject* aCreationStack,
+                   nsIGlobalObject* aIncumbentGlobal)
+  {
+    InitNoHold(aCallback, aCreationStack, aIncumbentGlobal);
     mozilla::HoldJSObjects(this);
   }
 
+  inline void ClearJSReferences()
+  {
+    mCallback = nullptr;
+    mCreationStack = nullptr;
+    mIncumbentJSGlobal = nullptr;
+  }
+
   CallbackObject(const CallbackObject&) = delete;
   CallbackObject& operator =(const CallbackObject&) = delete;
 
 protected:
   void DropJSObjects()
   {
     MOZ_ASSERT_IF(mIncumbentJSGlobal, mCallback);
     if (mCallback) {
-      mCallback = nullptr;
-      mCreationStack = nullptr;
-      mIncumbentJSGlobal = nullptr;
+      ClearJSReferences();
       mozilla::DropJSObjects(this);
     }
   }
 
+  // For use from subclasses that want to be usable with Rooted.
+  void Trace(JSTracer* aTracer);
+
+  // For use from subclasses that want to be traced for a bit then possibly
+  // switch to HoldJSObjects.  If we have more than one owner, this will
+  // HoldJSObjects; otherwise it will just forget all our JS references.
+  void HoldJSObjectsIfMoreThanOneOwner();
+
+  // Struct used as a way to force a CallbackObject constructor to not call
+  // HoldJSObjects. We're putting it here so that CallbackObject subclasses will
+  // have access to it, but outside code will not.
+  //
+  // Places that use this need to ensure that the callback is traced (e.g. via a
+  // Rooted) until the HoldJSObjects call happens.
+  struct FastCallbackConstructor {
+  };
+
+  // Just like the public version without the FastCallbackConstructor argument,
+  // except for not calling HoldJSObjects.  If you use this, you MUST ensure
+  // that the object is traced until the HoldJSObjects happens!
+  CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
+                 nsIGlobalObject* aIncumbentGlobal,
+                 const FastCallbackConstructor&)
+  {
+    if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
+      JS::RootedObject stack(aCx);
+      if (!JS::CaptureCurrentStack(aCx, &stack)) {
+        JS_ClearPendingException(aCx);
+      }
+      InitNoHold(aCallback, stack, aIncumbentGlobal);
+    } else {
+      InitNoHold(aCallback, nullptr, aIncumbentGlobal);
+    }
+  }
+
   // mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
   // This is done to ensure that, if JS code can't call a callback f(), or get
   // its members, directly itself, this code won't call f(), or get its members,
   // on the code's behalf.
   JS::Heap<JSObject*> mCallback;
   JS::Heap<JSObject*> mCreationStack;
   // Ideally, we'd just hold a reference to the nsIGlobalObject, since that's
   // what we need to pass to AutoIncumbentScript. Unfortunately, that doesn't
@@ -468,12 +516,73 @@ ImplCycleCollectionTraverse(nsCycleColle
 
 template<class T, class U>
 void
 ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField)
 {
   aField.UnlinkSelf();
 }
 
+// T is expected to be a RefPtr or OwningNonNull around a CallbackObject
+// subclass.  This class is used in bindings to safely handle Fast* callbacks;
+// it ensures that the callback is traced, and that if something is holding onto
+// the callback when we're done with it HoldJSObjects is called.
+template<typename T>
+class RootedCallback : public JS::Rooted<T>
+{
+public:
+  explicit RootedCallback(JSContext* cx)
+    : JS::Rooted<T>(cx)
+  {}
+
+  // We need a way to make assignment from pointers (how we're normally used)
+  // work.
+  template<typename S>
+  void operator=(S* arg)
+  {
+    this->get().operator=(arg);
+  }
+
+  // But nullptr can't use the above template, because it doesn't know which S
+  // to select.  So we need a special overload for nullptr.
+  void operator=(decltype(nullptr) arg)
+  {
+    this->get().operator=(arg);
+  }
+
+  // Codegen relies on being able to do Callback() on us.
+  JS::Handle<JSObject*> Callback() const
+  {
+    return this->get()->Callback();
+  }
+
+  ~RootedCallback()
+  {
+    // Ensure that our callback starts holding on to its own JS objects as
+    // needed.  Having to null-check here when T is OwningNonNull is a bit
+    // silly, but it's simpler than creating two separate RootedCallback
+    // instantiations for OwningNonNull and RefPtr.
+    if (IsInitialized(this->get())) {
+      this->get()->HoldJSObjectsIfMoreThanOneOwner();
+    }
+  }
+
+private:
+  template<typename U>
+  static bool IsInitialized(U& aArg); // Not implemented
+
+  template<typename U>
+  static bool IsInitialized(RefPtr<U>& aRefPtr)
+  {
+    return aRefPtr;
+  }
+
+  template<typename U>
+  static bool IsInitialized(OwningNonNull<U>& aOwningNonNull)
+  {
+    return aOwningNonNull.isInitialized();
+  }
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackObject_h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4181,16 +4181,47 @@ class CGCallbackTempRoot(CGGeneric):
             { // Scope for tempRoot
               JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
               ${declName} = new %s(cx, tempRoot, mozilla::dom::GetIncumbentGlobal());
             }
             """) % name
         CGGeneric.__init__(self, define=define)
 
 
+def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
+                              isOptional):
+    """
+    Returns a tuple containing the declType, declArgs, and basic
+    conversion for the given callback type, with the given callback
+    idl object in the given context (isMember/isCallbackReturnValue/isOptional).
+    """
+    name = idlObject.identifier.name
+
+    # We can't use fast callbacks if isOptional because then we get an
+    # Optional<RootedCallback> thing, which is not transparent to consumers.
+    useFastCallback = (not isMember and not isCallbackReturnValue and
+                       not isOptional)
+    if useFastCallback:
+        name = "binding_detail::Fast%s" % name
+
+    if type.nullable() or isCallbackReturnValue:
+        declType = CGGeneric("RefPtr<%s>" % name)
+    else:
+        declType = CGGeneric("OwningNonNull<%s>" % name)
+
+    if useFastCallback:
+        declType = CGTemplatedType("RootedCallback", declType)
+        declArgs = "cx"
+    else:
+        declArgs = None
+
+    conversion = indent(CGCallbackTempRoot(name).define())
+    return (declType, declArgs, conversion)
+
+
 class JSToNativeConversionInfo():
     """
     An object representing information about a JS-to-native conversion.
     """
     def __init__(self, template, declType=None, holderType=None,
                  dealWithOptional=False, declArgs=None,
                  holderArgs=None):
         """
@@ -5083,27 +5114,26 @@ def getJSToNativeConversionInfo(type, de
         assert not isEnforceRange and not isClamp
 
         descriptor = descriptorProvider.getDescriptor(
             type.unroll().inner.identifier.name)
 
         assert descriptor.nativeType != 'JSObject'
 
         if descriptor.interface.isCallback():
-            name = descriptor.interface.identifier.name
-            if type.nullable() or isCallbackReturnValue:
-                declType = CGGeneric("RefPtr<%s>" % name)
-            else:
-                declType = CGGeneric("OwningNonNull<%s>" % name)
-            conversion = indent(CGCallbackTempRoot(name).define())
-
+            (declType, declArgs,
+             conversion) = getCallbackConversionInfo(type, descriptor.interface,
+                                                     isMember,
+                                                     isCallbackReturnValue,
+                                                     isOptional)
             template = wrapObjectTemplate(conversion, type,
                                           "${declName} = nullptr;\n",
                                           failureCode)
             return JSToNativeConversionInfo(template, declType=declType,
+                                            declArgs=declArgs,
                                             dealWithOptional=isOptional)
 
         # This is an interface that we implement as a concrete class
         # or an XPCOM interface.
 
         # Allow null pointers for nullable types and old-binding classes, and
         # use an RefPtr or raw pointer for callback return values to make
         # them easier to return.
@@ -5573,21 +5603,20 @@ def getJSToNativeConversionInfo(type, de
     if type.isCallback():
         assert not isEnforceRange and not isClamp
         assert not type.treatNonCallableAsNull() or type.nullable()
         assert not type.treatNonObjectAsNull() or type.nullable()
         assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
 
         callback = type.unroll().callback
         name = callback.identifier.name
-        if type.nullable():
-            declType = CGGeneric("RefPtr<%s>" % name)
-        else:
-            declType = CGGeneric("OwningNonNull<%s>" % name)
-        conversion = indent(CGCallbackTempRoot(name).define())
+        (declType, declArgs,
+         conversion) = getCallbackConversionInfo(type, callback, isMember,
+                                                 isCallbackReturnValue,
+                                                 isOptional)
 
         if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
             haveCallable = "JS::IsCallable(&${val}.toObject())"
             if not isDefinitelyObject:
                 haveCallable = "${val}.isObject() && " + haveCallable
             if defaultValue is not None:
                 assert(isinstance(defaultValue, IDLNullValue))
                 haveCallable = "${haveValue} && " + haveCallable
@@ -5614,16 +5643,17 @@ def getJSToNativeConversionInfo(type, de
                 conversion +
                 "} else {\n" +
                 indent(onFailureNotCallable(failureCode).define()) +
                 "}\n",
                 type,
                 "${declName} = nullptr;\n",
                 failureCode)
         return JSToNativeConversionInfo(template, declType=declType,
+                                        declArgs=declArgs,
                                         dealWithOptional=isOptional)
 
     if type.isAny():
         assert not isEnforceRange and not isClamp
 
         declArgs = None
         if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
             # Rooting is handled by the sequence and dictionary tracers.
@@ -13531,26 +13561,36 @@ class CGBindingRoot(CGThing):
                 # FIXME: Unions are broken in workers.  See bug 809899.
                 cgthings.append(CGUnionStruct(t, config.getDescriptorProvider(False)))
                 cgthings.append(CGUnionStruct(t, config.getDescriptorProvider(False), True))
 
         # Do codegen for all the callbacks.
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
                         for c in mainCallbacks)
 
+        cgthings.extend([CGNamespace('binding_detail', CGFastCallback(c))
+                         for c in mainCallbacks])
+
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(True))
                         for c in workerCallbacks if c not in mainCallbacks)
 
+        cgthings.extend([CGNamespace('binding_detail', CGFastCallback(c))
+                         for c in workerCallbacks if c not in mainCallbacks])
+
         # Do codegen for all the descriptors
         cgthings.extend([CGDescriptor(x) for x in descriptors])
 
         # Do codegen for all the callback interfaces.  Skip worker callbacks.
         cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors if
                          not x.workers])
 
+        cgthings.extend([CGNamespace('binding_detail',
+                                     CGFastCallback(x.interface))
+                         for x in callbackDescriptors if not x.workers])
+
         # Do codegen for JS implemented classes
         def getParentDescriptor(desc):
             if not desc.interface.parent:
                 return set()
             return {desc.getDescriptor(desc.interface.parent.identifier.name)}
         for x in dependencySortObjects(jsImplemented, getParentDescriptor,
                                        lambda d: d.interface.identifier.name):
             cgthings.append(CGCallbackInterface(x, typedArraysAreStructs=True))
@@ -14815,16 +14855,28 @@ class CGCallback(CGClass):
                 bodyInHeader=True,
                 visibility="public",
                 explicit=True,
                 baseConstructors=[
                     "%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
                 ],
                 body=body),
             ClassConstructor(
+                [Argument("JSContext*", "aCx"),
+                 Argument("JS::Handle<JSObject*>", "aCallback"),
+                 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
+                 Argument("const FastCallbackConstructor&", "")],
+                bodyInHeader=True,
+                visibility="public",
+                explicit=True,
+                baseConstructors=[
+                    "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" % self.baseName,
+                ],
+                body=body),
+            ClassConstructor(
                 [Argument("JS::Handle<JSObject*>", "aCallback"),
                  Argument("JS::Handle<JSObject*>", "aAsyncStack"),
                  Argument("nsIGlobalObject*", "aIncumbentGlobal")],
                 bodyInHeader=True,
                 visibility="public",
                 explicit=True,
                 baseConstructors=[
                     "%s(aCallback, aAsyncStack, aIncumbentGlobal)" % self.baseName,
@@ -14979,16 +15031,57 @@ class CGCallbackFunction(CGCallback):
             ClassConstructor(
                 [Argument("CallbackFunction*", "aOther")],
                 bodyInHeader=True,
                 visibility="public",
                 explicit=True,
                 baseConstructors=["CallbackFunction(aOther)"])]
 
 
+class CGFastCallback(CGClass):
+    def __init__(self, idlObject):
+        self._deps = idlObject.getDeps()
+        baseName = idlObject.identifier.name
+        constructor = ClassConstructor(
+            [Argument("JSContext*", "aCx"),
+             Argument("JS::Handle<JSObject*>", "aCallback"),
+             Argument("nsIGlobalObject*", "aIncumbentGlobal")],
+            bodyInHeader=True,
+            visibility="public",
+            explicit=True,
+            baseConstructors=[
+                "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" %
+                baseName,
+            ],
+            body="")
+
+        traceMethod = ClassMethod("Trace", "void",
+                                  [Argument("JSTracer*", "aTracer")],
+                                  inline=True,
+                                  bodyInHeader=True,
+                                  visibility="public",
+                                  body="%s::Trace(aTracer);\n" % baseName)
+        holdMethod = ClassMethod("HoldJSObjectsIfMoreThanOneOwner", "void",
+                                 [],
+                                 inline=True,
+                                 bodyInHeader=True,
+                                 visibility="public",
+                                 body=(
+                                     "%s::HoldJSObjectsIfMoreThanOneOwner();\n" %
+                                     baseName))
+
+        CGClass.__init__(self, "Fast%s" % baseName,
+                         bases=[ClassBase(baseName)],
+                         constructors=[constructor],
+                         methods=[traceMethod, holdMethod])
+
+    def deps(self):
+        return self._deps
+
+
 class CGCallbackInterface(CGCallback):
     def __init__(self, descriptor, typedArraysAreStructs=False):
         iface = descriptor.interface
         attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
         getters = [CallbackGetter(a, descriptor, typedArraysAreStructs)
                    for a in attrs]
         setters = [CallbackSetter(a, descriptor, typedArraysAreStructs)
                    for a in attrs if not a.readonly]
new file mode 100644
--- /dev/null
+++ b/dom/bindings/RootedOwningNonNull.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * An implementation of Rooted for OwningNonNull<T>.  This works by assuming
+ * that T has a Trace() method defined on it which will trace whatever things
+ * inside the T instance need tracing.
+ *
+ * This implementation has one serious drawback: operator= doesn't work right
+ * because it's declared on Rooted directly and expects the type Rooted is
+ * templated over.
+ */
+
+#ifndef mozilla_RootedOwningNonNull_h__
+#define mozilla_RootedOwningNonNull_h__
+
+#include "mozilla/OwningNonNull.h"
+#include "js/GCPolicyAPI.h"
+#include "js/RootingAPI.h"
+
+namespace JS {
+template<typename T>
+struct GCPolicy<mozilla::OwningNonNull<T>>
+{
+  typedef mozilla::OwningNonNull<T> SmartPtrType;
+
+  static SmartPtrType initial()
+  {
+    return SmartPtrType();
+  }
+
+  static void trace(JSTracer* trc, SmartPtrType* tp,
+                    const char* name)
+  {
+    // We have to be very careful here.  Normally, OwningNonNull can't be null.
+    // But binding code can end up in a situation where it sets up a
+    // Rooted<OwningNonNull> and then before it gets a chance to assign to it
+    // (e.g. from the constructor of the thing being assigned) a GC happens.  So
+    // we can land here when *tp stores a null pointer because it's not
+    // initialized.
+    //
+    // So we need to check for that before jumping.
+    if ((*tp).isInitialized()) {
+      (*tp)->Trace(trc);
+    }
+  }
+};
+} // namespace JS
+
+namespace js {
+template<typename T>
+struct RootedBase<mozilla::OwningNonNull<T>>
+{
+  typedef mozilla::OwningNonNull<T> SmartPtrType;
+
+  operator SmartPtrType& () const
+  {
+    auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
+    return self.get();
+  }
+
+  operator T& () const
+  {
+    auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
+    return self.get();
+  }
+};
+} // namespace js
+
+#endif /* mozilla_RootedOwningNonNull_h__ */
new file mode 100644
--- /dev/null
+++ b/dom/bindings/RootedRefPtr.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * An implementation of Rooted for RefPtr<T>.  This works by assuming that T has
+ * a Trace() method defined on it which will trace whatever things inside the T
+ * instance need tracing.
+ *
+ * This implementation has one serious drawback: operator= doesn't work right
+ * because it's declared on Rooted directly and expects the type Rooted is
+ * templated over.
+ */
+
+#ifndef mozilla_RootedRefPtr_h__
+#define mozilla_RootedRefPtr_h__
+
+#include "mozilla/RefPtr.h"
+#include "js/GCPolicyAPI.h"
+#include "js/RootingAPI.h"
+
+namespace JS {
+template<typename T>
+struct GCPolicy<RefPtr<T>>
+{
+  static RefPtr<T> initial() {
+    return RefPtr<T>();
+  }
+
+  static void trace(JSTracer* trc, RefPtr<T>* tp, const char* name)
+  {
+    if (*tp) {
+      (*tp)->Trace(trc);
+    }
+  }
+};
+} // namespace JS
+
+namespace js {
+template<typename T>
+struct RootedBase<RefPtr<T>>
+{
+  operator RefPtr<T>& () const
+  {
+    auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
+    return self.get();
+  }
+
+  operator T*() const
+  {
+    auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
+    return self.get();
+  }
+};
+} // namespace js
+
+#endif /* mozilla_RootedRefPtr_h__ */
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -51,16 +51,20 @@ struct MOZ_STACK_CLASS WebIDLNameTableKe
 };
 
 struct WebIDLNameTableEntry : public PLDHashEntryHdr
 {
   typedef const WebIDLNameTableKey& KeyType;
   typedef const WebIDLNameTableKey* KeyTypePointer;
 
   explicit WebIDLNameTableEntry(KeyTypePointer aKey)
+    : mNameOffset(0),
+      mNameLength(0),
+      mDefine(nullptr),
+      mEnabled(nullptr)
   {}
   WebIDLNameTableEntry(WebIDLNameTableEntry&& aEntry)
     : mNameOffset(aEntry.mNameOffset),
       mNameLength(aEntry.mNameLength),
       mDefine(aEntry.mDefine),
       mEnabled(aEntry.mEnabled)
   {}
   ~WebIDLNameTableEntry()
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -7,16 +7,18 @@
 TEST_DIRS += ['test']
 
 EXPORTS.ipc += [
     'ErrorIPCUtils.h',
 ]
 
 EXPORTS.mozilla += [
     'ErrorResult.h',
+    'RootedOwningNonNull.h',
+    'RootedRefPtr.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'AtomList.h',
     'BindingDeclarations.h',
     'BindingUtils.h',
     'CallbackFunction.h',
     'CallbackInterface.h',
--- a/dom/bluetooth/tests/marionette/manifest.ini
+++ b/dom/bluetooth/tests/marionette/manifest.ini
@@ -1,23 +1,18 @@
 [DEFAULT]
-b2g = true
-browser = false
-qemu = false
-
-# Hint: "disabled = xxxxx" statement should be added *below* the test that
-# we want to disable.
+run-if = buildapp == 'b2g'
 
 [test_dom_BluetoothManager.js]
 skip-if = android_version < '19'
 [test_dom_BluetoothAdapter_enable.js]
 skip-if = android_version < '19'
 [test_dom_BluetoothAdapter_setters.js]
 skip-if = android_version < '19'
 [test_dom_BluetoothDevice.js]
-disabled = Bug 1175389
+skip-if = true # Bug 1175389
 
 [test_dom_BluetoothAdapter_discovery.js]
-disabled = Bug 1175389
+skip-if = true # Bug 1175389
 
 [test_dom_BluetoothAdapter_pair.js]
-disabled = Bug 1175389
+skip-if = true # Bug 1175389
 
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -436,17 +436,17 @@ BroadcastChannel::Constructor(const Glob
   return bc.forget();
 }
 
 void
 BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                               ErrorResult& aRv)
 {
   if (mState != StateActive) {
-    aRv.Throw(NS_ERROR_FAILURE);
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   PostMessageInternal(aCx, aMessage, aRv);
 }
 
 void
 BroadcastChannel::PostMessageInternal(JSContext* aCx,
--- a/dom/broadcastchannel/tests/mochitest.ini
+++ b/dom/broadcastchannel/tests/mochitest.ini
@@ -19,8 +19,9 @@ support-files =
 [test_broadcastchannel_sharedWorker.html]
 [test_broadcastchannel_worker.html]
 [test_broadcastchannel_worker_alive.html]
 [test_broadcastchannel_mozbrowser.html]
 skip-if = buildapp != 'mulet'
 [test_broadcastchannel_mozbrowser2.html]
 skip-if = buildapp != 'mulet'
 [test_bfcache.html]
+[test_invalidState.html]
new file mode 100644
--- /dev/null
+++ b/dom/broadcastchannel/tests/test_invalidState.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for BroadcastChannel.postMessage invalid State</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<div id="content"></div>
+
+<script type="application/javascript">
+
+var c = new BroadcastChannel("foo");
+c.close();
+
+try  {
+  c.postMessage("bar");
+  ok(false, "This should throw!");
+} catch(e) {
+  ok(true, "This should throw!");
+  is(e.name, "InvalidStateError", "Correct invalid-state exception thrown");
+}
+
+</script>
+</body>
+</html>
+
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -91,26 +91,27 @@ static const gl::GLFeature kRequiredFeat
     gl::GLFeature::texture_storage,
     gl::GLFeature::transform_feedback2,
     gl::GLFeature::uniform_buffer_object,
     gl::GLFeature::uniform_matrix_nonsquare,
     gl::GLFeature::vertex_array_object
 };
 
 bool
-WebGLContext::InitWebGL2(nsACString* const out_failReason)
+WebGLContext::InitWebGL2(nsACString* const out_failReason, nsACString* const out_failureId)
 {
     MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");
 
     // check OpenGL features
     if (!gl->IsSupported(gl::GLFeature::occlusion_query) &&
         !gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
     {
         // On desktop, we fake occlusion_query_boolean with occlusion_query if
         // necessary. (See WebGL2ContextQueries.cpp)
+        *out_failureId = "FEATURE_FAILURE_WEBGL2_OCCL";
         out_failReason->AssignASCII("WebGL 2 requires occlusion query support.");
         return false;
     }
 
     std::vector<gl::GLFeature> missingList;
 
     for (size_t i = 0; i < ArrayLength(kRequiredFeatures); i++) {
         if (!gl->IsSupported(kRequiredFeatures[i])) {
@@ -129,16 +130,17 @@ WebGLContext::InitWebGL2(nsACString* con
 
     if (missingList.size()) {
         nsAutoCString exts;
         for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) {
             exts.AppendLiteral("\n  ");
             exts.Append(gl::GLContext::GetFeatureName(*itr));
         }
 
+        *out_failureId = "FEATURE_FAILURE_WEBGL2_FEATURE";
         const nsPrintfCString reason("WebGL 2 requires support for the following"
                                      " features: %s",
                                      exts.BeginReading());
         out_failReason->Assign(reason);
         return false;
     }
 
     // we initialise WebGL 2 related stuff.
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -426,22 +426,21 @@ WebGLContext::GetHeight() const
  *
  * That is, try to create headless contexts based on the platform API.
  * Next, create dummy-sized backbuffers for the contexts with the right
  * caps. Finally, resize the backbuffer to an acceptable size given the
  * requested size.
  */
 
 static bool
-IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
+IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature, nsACString* const out_failureId)
 {
     int32_t status;
-    nsCString discardFailureId;
     if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
-                                                           discardFailureId, &status)))
+                                                           *out_failureId, &status)))
         return false;
 
     return status != nsIGfxInfo::FEATURE_STATUS_OK;
 }
 
 static bool
 HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
 {
@@ -557,81 +556,87 @@ BaseCaps(const WebGLContextOptions& opti
         baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
     } while (false);
 #endif
 
     // Done with baseCaps construction.
 
     bool forceAllowAA = gfxPrefs::WebGLForceMSAA();
     nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+    nsCString discardFailureId;
     if (!forceAllowAA &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
+        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &discardFailureId))
     {
         webgl->GenerateWarning("Disallowing antialiased backbuffers due"
                                " to blacklisting.");
         baseCaps.antialias = false;
     }
 
     return baseCaps;
 }
 
 ////////////////////////////////////////
 
 static already_AddRefed<gl::GLContext>
 CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                WebGLContext* webgl, nsACString* const out_failReason)
+                WebGLContext* webgl, nsACString* const out_failReason,
+                nsACString* const out_failureId)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags);
     if (gl && gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
         if (out_failReason->Length()) {
             out_failReason->AppendLiteral("\n");
         }
         out_failReason->AppendLiteral("Error during EGL OpenGL init.");
+        *out_failureId = "FEATURE_FAILURE_WEBGL_EGL_INIT";
         return nullptr;
     }
 
     return gl.forget();
 }
 
 static already_AddRefed<GLContext>
 CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                  WebGLContext* webgl, nsACString* const out_failReason)
+                  WebGLContext* webgl, nsACString* const out_failReason,
+                  nsACString* const out_failureId)
 {
     const gfx::IntSize dummySize(16, 16);
     RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
                                                                      flags);
     if (gl && !gl->IsANGLE()) {
         gl = nullptr;
     }
 
     if (!gl) {
         if (out_failReason->Length()) {
             out_failReason->AppendLiteral("\n");
         }
         out_failReason->AppendLiteral("Error during ANGLE OpenGL init.");
+        *out_failureId = "FEATURE_FAILURE_WEBGL_ANGLE_INIT";
         return nullptr;
     }
 
     return gl.forget();
 }
 
 static already_AddRefed<gl::GLContext>
 CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
-                    WebGLContext* webgl, nsACString* const out_failReason)
+                    WebGLContext* webgl, nsACString* const out_failReason,
+                    nsACString* const out_failureId)
 {
     nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
 
     if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
+        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL, out_failureId))
     {
         if (out_failReason->Length()) {
             out_failReason->AppendASCII("\n");
         }
         out_failReason->AppendASCII("Refused to create native OpenGL context because of"
                                     " blacklisting.");
         return nullptr;
     }
@@ -643,57 +648,60 @@ CreateGLWithDefault(const gl::SurfaceCap
         gl = nullptr;
     }
 
     if (!gl) {
         if (out_failReason->Length()) {
             out_failReason->AppendASCII("\n");
         }
         out_failReason->AppendASCII("Error during native OpenGL init.");
+        *out_failureId = "FEATURE_FAILURE_WEBGL_DEFAULT_INIT";
         return nullptr;
     }
 
     return gl.forget();
 }
 
 ////////////////////////////////////////
 
 bool
 WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
                                   const gl::SurfaceCaps& baseCaps,
                                   gl::CreateContextFlags flags,
-                                  nsACString* const out_failReason)
+                                  nsACString* const out_failReason,
+                                  nsACString* const out_failureId)
 {
     std::queue<gl::SurfaceCaps> fallbackCaps;
     PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
 
     MOZ_RELEASE_ASSERT(!gl);
     gl = nullptr;
     while (!fallbackCaps.empty()) {
         gl::SurfaceCaps& caps = fallbackCaps.front();
 
-        gl = fnCreateGL(caps, flags, this, out_failReason);
+        gl = fnCreateGL(caps, flags, this, out_failReason, out_failureId);
         if (gl)
             break;
 
         fallbackCaps.pop();
     }
     if (!gl)
         return false;
 
-    if (!InitAndValidateGL(out_failReason)) {
+    if (!InitAndValidateGL(out_failReason, out_failureId)) {
+        // The fail reason here should be specific enough for now.
         gl = nullptr;
         return false;
     }
 
     return true;
 }
 
 bool
-WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason)
+WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId)
 {
     const bool useEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
 
     bool useANGLE = false;
 #ifdef XP_WIN
     const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() ||
                                PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"));
     useANGLE = !disableANGLE;
@@ -702,22 +710,22 @@ WebGLContext::CreateAndInitGL(bool force
     gl::CreateContextFlags flags = gl::CreateContextFlags::NONE;
     if (forceEnabled) flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
     if (!IsWebGL2())  flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
     if (IsWebGL2())   flags |= gl::CreateContextFlags::PREFER_ES3;
 
     const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
 
     if (useEGL)
-        return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason);
+        return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason, out_failureId);
 
     if (useANGLE)
-        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReason);
+        return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReason, out_failureId);
 
-    return CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReason);
+    return CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReason, out_failureId);
 }
 
 // Fallback for resizes:
 bool
 WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
                                uint32_t requestedHeight)
 {
     uint32_t width = requestedWidth;
@@ -859,68 +867,78 @@ WebGLContext::SetDimensions(int32_t sign
     // context we're creating), we may have to dispatch a context lost
     // event.
 
     // If incrementing the generation would cause overflow,
     // don't allow it.  Allowing this would allow us to use
     // resource handles created from older context generations.
     if (!(mGeneration + 1).isValid()) {
         // exit without changing the value of mGeneration
+        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY"));
         const nsLiteralCString text("Too many WebGL contexts created this run.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
     // increment the generation number - Do this early because later
     // in CreateOffscreenGL(), "default" objects are created that will
     // pick up the old generation.
     ++mGeneration;
 
     bool disabled = gfxPrefs::WebGLDisabled();
 
     // TODO: When we have software webgl support we should use that instead.
     disabled |= gfxPlatform::InSafeMode();
 
     if (disabled) {
+        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED"));
         const nsLiteralCString text("WebGL is currently disabled.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
     bool failIfPerfCaveat = mOptions.failIfMajorPerformanceCaveat;
     if (gfxPrefs::WebGLDisableFailIfMajorPerformanceCaveat())
         failIfPerfCaveat = false;
 
     if (failIfPerfCaveat) {
         nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
         if (!HasAcceleratedLayers(gfxInfo)) {
+            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                                  NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT"));
             const nsLiteralCString text("failIfMajorPerformanceCaveat: Compositor is not"
                                         " hardware-accelerated.");
             ThrowEvent_WebGLContextCreationError(text);
             return NS_ERROR_FAILURE;
         }
     }
 
     // Alright, now let's start trying.
     bool forceEnabled = gfxPrefs::WebGLForceEnabled();
     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
 
     MOZ_ASSERT(!gl);
     nsCString failReason;
-    if (!CreateAndInitGL(forceEnabled, &failReason)) {
+    nsCString failureId;
+    if (!CreateAndInitGL(forceEnabled, &failReason, &failureId)) {
+        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, failureId);
         const nsPrintfCString text("WebGL creation failed: %s",
                                    failReason.BeginReading());
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(gl);
 
     MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
 
     if (!ResizeBackbuffer(width, height)) {
+        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_RESIZE"));
         const nsLiteralCString text("Initializing WebGL backbuffer failed.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
 #ifdef DEBUG
     if (gl->DebugMode())
         printf_stderr("--- WebGL context created: %p\n", gl.get());
@@ -993,16 +1011,19 @@ WebGLContext::SetDimensions(int32_t sign
 
     MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
     MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
 
     AssertCachedBindings();
     AssertCachedState();
 
     reporter.SetSuccessful();
+
+    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                          NS_LITERAL_CSTRING("SUCCESS"));
     return NS_OK;
 }
 
 void
 WebGLContext::ClearBackbufferIfNeeded()
 {
     if (!mBackbufferNeedsClear)
         return;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1196,34 +1196,36 @@ protected:
     nsTArray<GLenum> mCompressedTextureFormats;
 
     // -------------------------------------------------------------------------
     // WebGL 2 specifics (implemented in WebGL2Context.cpp)
 public:
     virtual bool IsWebGL2() const = 0;
 
 protected:
-    bool InitWebGL2(nsACString* const out_failReason);
+    bool InitWebGL2(nsACString* const out_failReason, nsACString* const out_failureId);
 
-    bool CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason);
+    bool CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId);
     bool ResizeBackbuffer(uint32_t width, uint32_t height);
 
     typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
                                                          gl::CreateContextFlags flags,
                                                          WebGLContext* webgl,
-                                                         nsACString* const out_failReason);
+                                                         nsACString* const out_failReason,
+                                                         nsACString* const out_failureId);
 
     bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
                              gl::CreateContextFlags flags,
-                             nsACString* const out_failReason);
+                             nsACString* const out_failReason,
+                             nsACString* const out_failureId);
     void ThrowEvent_WebGLContextCreationError(const nsACString& text);
 
     // -------------------------------------------------------------------------
     // Validation functions (implemented in WebGLContextValidate.cpp)
-    bool InitAndValidateGL(nsACString* const out_failReason);
+    bool InitAndValidateGL(nsACString* const out_failReason, nsACString* const out_failureId);
     bool ValidateBlendEquationEnum(GLenum cap, const char* info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
                                              const char* info);
     bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
     bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
     bool ValidateTextureTargetEnum(GLenum target, const char* info);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -640,31 +640,33 @@ FloorPOT(int32_t x)
         if (x < pot*2)
             break;
         pot *= 2;
     }
     return pot;
 }
 
 bool
-WebGLContext::InitAndValidateGL(nsACString* const out_failReason)
+WebGLContext::InitAndValidateGL(nsACString* const out_failReason, nsACString* const out_failureId)
 {
     MOZ_RELEASE_ASSERT(gl);
 
     // Unconditionally create a new format usage authority. This is
     // important when restoring contexts and extensions need to add
     // formats back into the authority.
     mFormatUsage = CreateFormatUsage(gl);
     if (!mFormatUsage) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_FORMAT";
         out_failReason->AssignLiteral("Failed to create mFormatUsage.");
         return false;
     }
 
     GLenum error = gl->fGetError();
     if (error != LOCAL_GL_NO_ERROR) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_GLERR_1";
         const nsPrintfCString reason("GL error 0x%x occurred during OpenGL context"
                                      " initialization, before WebGL initialization!",
                                      error);
         out_failReason->Assign(reason);
         return false;
     }
 
     mMinCapability = gfxPrefs::WebGLMinCapabilityMode();
@@ -747,31 +749,33 @@ WebGLContext::InitAndValidateGL(nsACStri
         gl->fEnableVertexAttribArray(0);
 
     if (MinCapabilityMode())
         mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
     else
         gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
 
     if (mGLMaxVertexAttribs < 8) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_V_ATRB";
         const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
                                      mGLMaxVertexAttribs);
         out_failReason->Assign(reason);
         return false;
     }
 
     // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
     // even though the hardware supports much more.  The
     // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
     if (MinCapabilityMode())
         mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
     else
         gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
 
     if (mGLMaxTextureUnits < 8) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_T_UNIT";
         const nsPrintfCString reason("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!",
                                      mGLMaxTextureUnits);
         out_failReason->Assign(reason);
         return false;
     }
 
     mBound2DTextures.SetLength(mGLMaxTextureUnits);
     mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
@@ -920,39 +924,41 @@ WebGLContext::InitAndValidateGL(nsACStri
         gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
     }
 
     // Check the shader validator pref
     mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator();
 
     // initialize shader translator
     if (!ShInitialize()) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_GLSL";
         out_failReason->AssignLiteral("GLSL translator initialization failed!");
         return false;
     }
 
     // Mesa can only be detected with the GL_VERSION string, of the form
     // "2.1 Mesa 7.11.0"
     const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
     mIsMesa = strstr(versionStr, "Mesa");
 
     // Notice that the point of calling fGetError here is not only to check for
     // errors, but also to reset the error flags so that a subsequent WebGL
     // getError call will give the correct result.
     error = gl->fGetError();
     if (error != LOCAL_GL_NO_ERROR) {
+        *out_failureId = "FEATURE_FAILURE_WEBGL_GLERR_2";
         const nsPrintfCString reason("GL error 0x%x occurred during WebGL context"
                                      " initialization!",
                                      error);
         out_failReason->Assign(reason);
         return false;
     }
 
     if (IsWebGL2() &&
-        !InitWebGL2(out_failReason))
+        !InitWebGL2(out_failReason, out_failureId))
     {
         // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
         return false;
     }
 
     // Default value for all disabled vertex attributes is [0, 0, 0, 1]
     mVertexAttribType = MakeUnique<GLenum[]>(mGLMaxVertexAttribs);
     for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
--- a/dom/cellbroadcast/tests/marionette/manifest.ini
+++ b/dom/cellbroadcast/tests/marionette/manifest.ini
@@ -1,13 +1,11 @@
 [DEFAULT]
-b2g = true
-browser = false
-qemu = true
+run-if = buildapp == 'b2g'
 
 [test_cellbroadcast_etws.js]
 [test_cellbroadcast_gsm.js]
 [test_cellbroadcast_gsm_language_and_body.js]
-disabled = Bug 1231462
+skip-if = true # Bug 1231462
 [test_cellbroadcast_multi_sim.js]
 [test_cellbroadcast_umts.js]
 [test_cellbroadcast_umts_language_and_body.js]
-disabled = Bug 1224992
+skip-if = true # Bug 1224992
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -58,37 +58,98 @@ StringToUsage(const nsString& aUsage, Cr
   } else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_UNWRAPKEY)) {
     aUsageOut = CryptoKey::UNWRAPKEY;
   } else {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
   return NS_OK;
 }
 
+// This helper function will release the memory backing a SECKEYPrivateKey and
+// any resources acquired in its creation. It will leave the backing PKCS#11
+// object untouched, however. This should only be called from
+// PrivateKeyFromPrivateKeyTemplate.
+static void
+DestroyPrivateKeyWithoutDestroyingPKCS11Object(SECKEYPrivateKey* key)
+{
+  PK11_FreeSlot(key->pkcs11Slot);
+  PORT_FreeArena(key->arena, PR_TRUE);
+}
+
+// To protect against key ID collisions, PrivateKeyFromPrivateKeyTemplate
+// generates a random ID for each key. The given template must contain an
+// attribute slot for a key ID, but it must consist of a null pointer and have a
+// length of 0.
 SECKEYPrivateKey*
-PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
-                                 CK_ATTRIBUTE* aTemplate,
+PrivateKeyFromPrivateKeyTemplate(CK_ATTRIBUTE* aTemplate,
                                  CK_ULONG aTemplateSize)
 {
   // Create a generic object with the contents of the key
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   if (!slot) {
     return nullptr;
   }
 
+  // Generate a random 160-bit object ID. This ID must be unique.
+  ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20));
+  SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
+  if (rv != SECSuccess) {
+    return nullptr;
+  }
+  // Check if something is already using this ID.
+  SECKEYPrivateKey* preexistingKey = PK11_FindKeyByKeyID(slot, objID, nullptr);
+  if (preexistingKey) {
+    // Note that we can't just call SECKEY_DestroyPrivateKey here because that
+    // will destroy the PKCS#11 object that is backing a preexisting key (that
+    // we still have a handle on somewhere else in memory). If that object were
+    // destroyed, cryptographic operations performed by that other key would
+    // fail.
+    DestroyPrivateKeyWithoutDestroyingPKCS11Object(preexistingKey);
+    // Try again with a new ID (but only once - collisions are very unlikely).
+    rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
+    if (rv != SECSuccess) {
+      return nullptr;
+    }
+    preexistingKey = PK11_FindKeyByKeyID(slot, objID, nullptr);
+    if (preexistingKey) {
+      DestroyPrivateKeyWithoutDestroyingPKCS11Object(preexistingKey);
+      return nullptr;
+    }
+  }
+
+  CK_ATTRIBUTE* idAttributeSlot = nullptr;
+  for (CK_ULONG i = 0; i < aTemplateSize; i++) {
+    if (aTemplate[i].type == CKA_ID) {
+      if (aTemplate[i].pValue != nullptr || aTemplate[i].ulValueLen != 0) {
+        return nullptr;
+      }
+      idAttributeSlot = aTemplate + i;
+      break;
+    }
+  }
+  if (!idAttributeSlot) {
+    return nullptr;
+  }
+
+  idAttributeSlot->pValue = objID->data;
+  idAttributeSlot->ulValueLen = objID->len;
   ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot,
                                                        aTemplate,
                                                        aTemplateSize,
                                                        PR_FALSE));
+  // Unset the ID attribute slot's pointer and length so that data that only
+  // lives for the scope of this function doesn't escape.
+  idAttributeSlot->pValue = nullptr;
+  idAttributeSlot->ulValueLen = 0;
   if (!obj) {
     return nullptr;
   }
 
   // Have NSS translate the object to a private key.
-  return PK11_FindKeyByKeyID(slot, aObjID, nullptr);
+  return PK11_FindKeyByKeyID(slot, objID, nullptr);
 }
 
 CryptoKey::CryptoKey(nsIGlobalObject* aGlobal)
   : mGlobal(aGlobal)
   , mAttributes(0)
   , mSymKey()
   , mPrivateKey(nullptr)
   , mPublicKey(nullptr)
@@ -257,32 +318,20 @@ CryptoKey::AddPublicKeyData(SECKEYPublic
   MOZ_ASSERT(GetKeyType() == PRIVATE);
   // There should be a private NSS key with type 'EC'.
   MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey);
   // The given public key should have the same key type.
   MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType);
 
   nsNSSShutDownPreventionLock locker;
 
-  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-  if (!slot) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
-  // Generate a random 160-bit object ID.
-  ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20));
-  SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
-  if (rv != SECSuccess) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
   // Read EC params.
   ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0));
-  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_EC_PARAMS,
-                             params);
+  SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey,
+                                       CKA_EC_PARAMS, params);
   if (rv != SECSuccess) {
     return NS_ERROR_DOM_OPERATION_ERR;
   }
 
   // Read private value.
   ScopedSECItem value(::SECITEM_AllocItem(nullptr, nullptr, 0));
   rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_VALUE, value);
   if (rv != SECSuccess) {
@@ -295,23 +344,24 @@ CryptoKey::AddPublicKeyData(SECKEYPublic
   CK_KEY_TYPE ecValue = CKK_EC;
 
   CK_ATTRIBUTE keyTemplate[9] = {
     { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
     { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
     { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
     { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
     { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
-    { CKA_ID,               objID->data,          objID->len },
+    // PrivateKeyFromPrivateKeyTemplate sets the ID.
+    { CKA_ID,               nullptr,              0 },
     { CKA_EC_PARAMS,        params->data,         params->len },
     { CKA_EC_POINT,         point->data,          point->len },
     { CKA_VALUE,            value->data,          value->len },
   };
 
-  mPrivateKey = PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
+  mPrivateKey = PrivateKeyFromPrivateKeyTemplate(keyTemplate,
                                                  PR_ARRAY_SIZE(keyTemplate));
   NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR);
 
   return NS_OK;
 }
 
 void
 CryptoKey::ClearUsages()
@@ -722,38 +772,32 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
       return nullptr;
     }
 
     SECItem* ecPoint = CreateECPointForCoordinates(x, y, arena.get());
     if (!ecPoint) {
       return nullptr;
     }
 
-    // Compute the ID for this key
-    // This is generated with a SHA-1 hash, so unlikely to collide
-    ScopedSECItem objID(PK11_MakeIDFromPubKey(ecPoint));
-    if (!objID.get()) {
-      return nullptr;
-    }
-
     // Populate template from parameters
     CK_KEY_TYPE ecValue = CKK_EC;
     CK_ATTRIBUTE keyTemplate[9] = {
       { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
       { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
       { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
       { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
       { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
-      { CKA_ID,               objID->data,          objID->len },
+      // PrivateKeyFromPrivateKeyTemplate sets the ID.
+      { CKA_ID,               nullptr,              0 },
       { CKA_EC_PARAMS,        params->data,         params->len },
       { CKA_EC_POINT,         ecPoint->data,        ecPoint->len },
       { CKA_VALUE,            (void*) d.Elements(), (CK_ULONG) d.Length() },
     };
 
-    return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
+    return PrivateKeyFromPrivateKeyTemplate(keyTemplate,
                                             PR_ARRAY_SIZE(keyTemplate));
   }
 
   if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) {
     // Verify that all of the required parameters are present
     CryptoBuffer n, e, d, p, q, dp, dq, qi;
     if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) ||
         !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) ||
@@ -766,48 +810,37 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
       return nullptr;
     }
 
     ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     if (!arena) {
       return nullptr;
     }
 
-    // Compute the ID for this key
-    // This is generated with a SHA-1 hash, so unlikely to collide
-    SECItem nItem = { siBuffer, nullptr, 0 };
-    if (!n.ToSECItem(arena, &nItem)) {
-      return nullptr;
-    }
-
-    ScopedSECItem objID(PK11_MakeIDFromPubKey(&nItem));
-    if (!objID.get()) {
-      return nullptr;
-    }
-
     // Populate template from parameters
     CK_KEY_TYPE rsaValue = CKK_RSA;
     CK_ATTRIBUTE keyTemplate[14] = {
       { CKA_CLASS,            &privateKeyValue,      sizeof(privateKeyValue) },
       { CKA_KEY_TYPE,         &rsaValue,             sizeof(rsaValue) },
       { CKA_TOKEN,            &falseValue,           sizeof(falseValue) },
       { CKA_SENSITIVE,        &falseValue,           sizeof(falseValue) },
       { CKA_PRIVATE,          &falseValue,           sizeof(falseValue) },
-      { CKA_ID,               objID->data,           objID->len },
+      // PrivateKeyFromPrivateKeyTemplate sets the ID.
+      { CKA_ID,               nullptr,               0 },
       { CKA_MODULUS,          (void*) n.Elements(),  (CK_ULONG) n.Length() },
       { CKA_PUBLIC_EXPONENT,  (void*) e.Elements(),  (CK_ULONG) e.Length() },
       { CKA_PRIVATE_EXPONENT, (void*) d.Elements(),  (CK_ULONG) d.Length() },
       { CKA_PRIME_1,          (void*) p.Elements(),  (CK_ULONG) p.Length() },
       { CKA_PRIME_2,          (void*) q.Elements(),  (CK_ULONG) q.Length() },
       { CKA_EXPONENT_1,       (void*) dp.Elements(), (CK_ULONG) dp.Length() },
       { CKA_EXPONENT_2,       (void*) dq.Elements(), (CK_ULONG) dq.Length() },
       { CKA_COEFFICIENT,      (void*) qi.Elements(), (CK_ULONG) qi.Length() },
     };
 
-    return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
+    return PrivateKeyFromPrivateKeyTemplate(keyTemplate,
                                             PR_ARRAY_SIZE(keyTemplate));
   }
 
   return nullptr;
 }
 
 bool ReadAndEncodeAttribute(SECKEYPrivateKey* aKey,
                             CK_ATTRIBUTE_TYPE aAttribute,
--- a/dom/crypto/test/mochitest.ini
+++ b/dom/crypto/test/mochitest.ini
@@ -11,16 +11,17 @@ support-files =
 
 [test_indexedDB.html]
 skip-if = toolkit == 'android' # bug 1200570
 [test_WebCrypto.html]
 [test_WebCrypto_DH.html]
 [test_WebCrypto_ECDH.html]
 [test_WebCrypto_ECDSA.html]
 [test_WebCrypto_HKDF.html]
+[test_WebCrypto_Import_Multiple_Identical_Keys.html]
 [test_WebCrypto_JWK.html]
 [test_WebCrypto_Normalize.html]
 [test_WebCrypto_PBKDF2.html]
 [test_WebCrypto_Reject_Generating_Keys_Without_Usages.html]
 [test_WebCrypto_RSA_OAEP.html]
 [test_WebCrypto_RSA_PSS.html]
 [test_WebCrypto_Structured_Cloning.html]
 [test_WebCrypto_Workers.html]
new file mode 100644
--- /dev/null
+++ b/dom/crypto/test/test_WebCrypto_Import_Multiple_Identical_Keys.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<title>WebCrypto Test Suite</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<link rel="stylesheet" href="./test_WebCrypto.css"/>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+<!-- General testing framework -->
+<script src="./test-array.js"></script>
+
+<script>/*<![CDATA[*/
+"use strict";
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Import the same ECDSA key multiple times and ensure that it can be used.",
+  function () {
+    var alg = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" };
+    crypto.subtle.generateKey(alg, true, ["sign", "verify"])
+    .then(function(keyPair) {
+      return crypto.subtle.exportKey("jwk", keyPair.privateKey);
+    })
+    .then(function(exportedKey) {
+      let keyImportPromises = [];
+      for (let i = 0; i < 20; i++) {
+        keyImportPromises.push(
+          crypto.subtle.importKey("jwk", exportedKey, alg, false, ["sign"]));
+      }
+      return Promise.all(keyImportPromises);
+    })
+    .then(function(importedKeys) {
+      let signPromises = [];
+      let data = crypto.getRandomValues(new Uint8Array(32));
+      for (let key of importedKeys) {
+        signPromises.push(crypto.subtle.sign(alg, key, data));
+      }
+      return Promise.all(signPromises);
+    })
+    .then(complete(this, function(signatures) {
+      return signatures.length == 20;
+    }), error(this));
+  }
+);
+
+// -----------------------------------------------------------------------------
+// This is the same test, but with an RSA key. This test framework stringifies
+// each test so it can be sent to and ran in a worker, which unfortunately
+// means we can't factor out common code here.
+TestArray.addTest(
+  "Import the same RSA key multiple times and ensure that it can be used.",
+  function () {
+    var alg = {
+      name: "RSASSA-PKCS1-v1_5",
+      modulusLength: 2048,
+      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+      hash: "SHA-256"
+    };
+    crypto.subtle.generateKey(alg, true, ["sign", "verify"])
+    .then(function(keyPair) {
+      return crypto.subtle.exportKey("jwk", keyPair.privateKey);
+    })
+    .then(function(exportedKey) {
+      let keyImportPromises = [];
+      for (let i = 0; i < 20; i++) {
+        keyImportPromises.push(
+          crypto.subtle.importKey("jwk", exportedKey, alg, false, ["sign"]));
+      }
+      return Promise.all(keyImportPromises);
+    })
+    .then(function(importedKeys) {
+      let signPromises = [];
+      let data = crypto.getRandomValues(new Uint8Array(32));
+      for (let key of importedKeys) {
+        signPromises.push(crypto.subtle.sign(alg, key, data));
+      }
+      return Promise.all(signPromises);
+    })
+    .then(complete(this, function(signatures) {
+      return signatures.length == 20;
+    }), error(this));
+  }
+);
+/*]]>*/</script>
+</head>
+
+<body>
+
+<div id="content">
+	<div id="head">
+		<b>Web</b>Crypto<br>
+	</div>
+
+    <div id="start" onclick="start();">RUN ALL</div>
+
+    <div id="resultDiv" class="content">
+    Summary:
+    <span class="pass"><span id="passN">0</span> passed, </span>
+    <span class="fail"><span id="failN">0</span> failed, </span>
+    <span class="pending"><span id="pendingN">0</span> pending.</span>
+    <br/>
+    <br/>
+
+    <table id="results">
+        <tr>
+            <th>Test</th>
+            <th>Result</th>
+            <th>Time</th>
+        </tr>
+    </table>
+
+    </div>
+
+    <div id="foot"></div>
+</div>
+
+</body>
+</html>
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -695,31 +695,35 @@ EventListenerManager::ListenerCanHandle(
 }
 
 void
 EventListenerManager::AddEventListenerByType(
                         const EventListenerHolder& aListenerHolder,
                         const nsAString& aType,
                         const EventListenerFlags& aFlags)
 {
-  nsCOMPtr<nsIAtom> atom =
-    mIsMainThreadELM ? NS_Atomize(NS_LITERAL_STRING("on") + aType) : nullptr;
-  EventMessage message = nsContentUtils::GetEventMessage(atom);
+  nsCOMPtr<nsIAtom> atom;
+  EventMessage message = mIsMainThreadELM ?
+    nsContentUtils::GetEventMessageAndAtomForListener(aType,
+                                                      getter_AddRefs(atom)) :
+    eUnidentifiedEvent;
   AddEventListenerInternal(aListenerHolder, message, atom, aType, aFlags);
 }
 
 void
 EventListenerManager::RemoveEventListenerByType(
                         const EventListenerHolder& aListenerHolder,
                         const nsAString& aType,
                         const EventListenerFlags& aFlags)
 {
-  nsCOMPtr<nsIAtom> atom =
-    mIsMainThreadELM ? NS_Atomize(NS_LITERAL_STRING("on") + aType) : nullptr;
-  EventMessage message = nsContentUtils::GetEventMessage(atom);
+  nsCOMPtr<nsIAtom> atom;
+  EventMessage message = mIsMainThreadELM ?
+    nsContentUtils::GetEventMessageAndAtomForListener(aType,
+                                                      getter_AddRefs(atom)) :
+    eUnidentifiedEvent;
   RemoveEventListenerInternal(aListenerHolder, message, atom, aType, aFlags);
 }
 
 EventListenerManager::Listener*
 EventListenerManager::FindEventHandler(EventMessage aEventMessage,
                                        nsIAtom* aTypeAtom,
                                        const nsAString& aTypeString)
 {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -811,16 +811,17 @@ EventStateManager::PreHandleEvent(nsPres
     break;
   case eContentCommandCut:
   case eContentCommandCopy:
   case eContentCommandPaste:
   case eContentCommandDelete:
   case eContentCommandUndo:
   case eContentCommandRedo:
   case eContentCommandPasteTransferable:
+  case eContentCommandLookUpDictionary:
     DoContentCommandEvent(aEvent->AsContentCommandEvent());
     break;
   case eContentCommandScroll:
     DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
     break;
   case eCompositionStart:
     if (aEvent->IsTrusted()) {
       // If the event is trusted event, set the selected text to data of
@@ -2025,18 +2026,19 @@ EventStateManager::DoDefaultDragStart(ns
   return true;
 }
 
 nsresult
 EventStateManager::GetContentViewer(nsIContentViewer** aCv)
 {
   *aCv = nullptr;
 
-  nsCOMPtr<nsPIDOMWindowOuter> rootWindow;
-  rootWindow = mDocument->GetWindow()->GetPrivateRoot();
+  nsPIDOMWindowOuter* window = mDocument->GetWindow();
+  if (!window) return NS_ERROR_FAILURE;
+  nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
   if (!rootWindow) return NS_ERROR_FAILURE;
 
   TabChild* tabChild = TabChild::GetFrom(rootWindow);
   if (!tabChild) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (!fm) return NS_ERROR_FAILURE;
 
     nsCOMPtr<mozIDOMWindowProxy> activeWindow;
@@ -5215,16 +5217,19 @@ EventStateManager::DoContentCommandEvent
       cmd = "cmd_undo";
       break;
     case eContentCommandRedo:
       cmd = "cmd_redo";
       break;
     case eContentCommandPasteTransferable:
       cmd = "cmd_pasteTransferable";
       break;
+    case eContentCommandLookUpDictionary:
+      cmd = "cmd_lookUpDictionary";
+      break;
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
   nsCOMPtr<nsIController> controller;
   nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller));
   NS_ENSURE_SUCCESS(rv, rv);
   if (!controller) {
     // When GetControllerForCommand succeeded but there is no controller, the
@@ -5245,17 +5250,44 @@ EventStateManager::DoContentCommandEvent
           NS_ENSURE_SUCCESS(rv, rv);
 
           rv = params->SetISupportsValue("transferable", aEvent->mTransferable);
           NS_ENSURE_SUCCESS(rv, rv);
 
           rv = commandController->DoCommandWithParams(cmd, params);
           break;
         }
-        
+
+        case eContentCommandLookUpDictionary: {
+          nsCOMPtr<nsICommandController> commandController =
+            do_QueryInterface(controller);
+          if (NS_WARN_IF(!commandController)) {
+            return NS_ERROR_FAILURE;
+          }
+
+          nsCOMPtr<nsICommandParams> params =
+            do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+
+          rv = params->SetLongValue("x", aEvent->mRefPoint.x);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+
+          rv = params->SetLongValue("y", aEvent->mRefPoint.y);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+
+          rv = commandController->DoCommandWithParams(cmd, params);
+          break;
+        }
+
         default:
           rv = controller->DoCommand(cmd);
           break;
       }
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   aEvent->mSucceeded = true;
--- a/dom/events/KeyNameList.h
+++ b/dom/events/KeyNameList.h
@@ -39,31 +39,30 @@ DEFINE_KEYNAME_INTERNAL(SoftRight, "MozS
  * Modifier Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
 DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
 DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
 DEFINE_KEYNAME_WITH_SAME_NAME(Control)
 DEFINE_KEYNAME_WITH_SAME_NAME(Fn)
 DEFINE_KEYNAME_WITH_SAME_NAME(FnLock)
-// DEFINE_KEYNAME_WITH_SAME_NAME(Hyper)
+DEFINE_KEYNAME_WITH_SAME_NAME(Hyper)
 DEFINE_KEYNAME_WITH_SAME_NAME(Meta)
 DEFINE_KEYNAME_WITH_SAME_NAME(NumLock)
-DEFINE_KEYNAME_WITH_SAME_NAME(OS)
+DEFINE_KEYNAME_WITH_SAME_NAME(OS) // Dropped from the latest draft, bug 1232918
 DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock)
 DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
-// DEFINE_KEYNAME_WITH_SAME_NAME(Super)
+DEFINE_KEYNAME_WITH_SAME_NAME(Super)
 DEFINE_KEYNAME_WITH_SAME_NAME(Symbol)
 DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
 
 /******************************************************************************
  * Whitespace Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(Enter)
-DEFINE_KEYNAME_WITH_SAME_NAME(Separator)
 DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
 
 /******************************************************************************
  * Navigation Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(ArrowDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(ArrowLeft)
 DEFINE_KEYNAME_WITH_SAME_NAME(ArrowRight)
@@ -108,17 +107,16 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Select)
 DEFINE_KEYNAME_WITH_SAME_NAME(ZoomIn)
 DEFINE_KEYNAME_WITH_SAME_NAME(ZoomOut)
 
 /******************************************************************************
  * Device Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
 DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
 DEFINE_KEYNAME_WITH_SAME_NAME(LogOff)
 DEFINE_KEYNAME_WITH_SAME_NAME(Power)
 DEFINE_KEYNAME_WITH_SAME_NAME(PowerOff)
 DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
 DEFINE_KEYNAME_WITH_SAME_NAME(Hibernate)
 DEFINE_KEYNAME_WITH_SAME_NAME(Standby)
 DEFINE_KEYNAME_WITH_SAME_NAME(WakeUp)
@@ -206,43 +204,80 @@ DEFINE_KEYNAME_WITH_SAME_NAME(F35)
 DEFINE_KEYNAME_WITH_SAME_NAME(Soft1)
 DEFINE_KEYNAME_WITH_SAME_NAME(Soft2)
 DEFINE_KEYNAME_WITH_SAME_NAME(Soft3)
 DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
 
 /******************************************************************************
  * Multimedia Keys
  *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(Close)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaSelect)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackNext)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackPrevious)
 DEFINE_KEYNAME_WITH_SAME_NAME(New)
 DEFINE_KEYNAME_WITH_SAME_NAME(Open)
 DEFINE_KEYNAME_WITH_SAME_NAME(Print)
 DEFINE_KEYNAME_WITH_SAME_NAME(Save)
 DEFINE_KEYNAME_WITH_SAME_NAME(SpellCheck)
+
+/******************************************************************************
+ * Multimedia Numpad Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Key11)
+DEFINE_KEYNAME_WITH_SAME_NAME(Key12)
+
+/******************************************************************************
+ * Audio Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostToggle)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioTrebleDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioTrebleUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
+DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneToggle)
+DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneVolumeDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneVolumeUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneVolumeMute)
+
+/******************************************************************************
+ * Speech Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(SpeechCorrectionList)
+DEFINE_KEYNAME_WITH_SAME_NAME(SpeechInputToggle)
 
 /******************************************************************************
  * Application Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalculator)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalendar)
+DEFINE_KEYNAME_WITH_SAME_NAME(LaunchContacts)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMediaPlayer)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMusicPlayer)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMyComputer)
+DEFINE_KEYNAME_WITH_SAME_NAME(LaunchPhone)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchScreenSaver)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchSpreadsheet)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebBrowser)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebCam)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWordProcessor)
 
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication1)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication2)
@@ -270,38 +305,80 @@ DEFINE_KEYNAME_WITH_SAME_NAME(BrowserBac
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserFavorites)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserHome)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserRefresh)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserSearch)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserStop)
 
 /******************************************************************************
+ * Mobile Phone Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(AppSwitch)
+DEFINE_KEYNAME_WITH_SAME_NAME(Call)
+DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
+DEFINE_KEYNAME_WITH_SAME_NAME(CameraFocus)
+DEFINE_KEYNAME_WITH_SAME_NAME(EndCall)
+DEFINE_KEYNAME_WITH_SAME_NAME(GoBack)
+DEFINE_KEYNAME_WITH_SAME_NAME(GoHome)
+DEFINE_KEYNAME_WITH_SAME_NAME(HeadsetHook)
+DEFINE_KEYNAME_WITH_SAME_NAME(LastNumberRedial)
+DEFINE_KEYNAME_WITH_SAME_NAME(Notification)
+DEFINE_KEYNAME_WITH_SAME_NAME(MannerMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(VoiceDial)
+
+/******************************************************************************
+ * TV Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(TV)
+DEFINE_KEYNAME_WITH_SAME_NAME(TV3DMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVAntennaCable)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVAudioDescription)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVAudioDescriptionMixDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVAudioDescriptionMixUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVContentsMenu)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVDataService)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputComponent1)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputComponent2)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputComposite1)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputComposite2)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputHDMI1)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputHDMI2)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputHDMI3)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputHDMI4)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVInputVGA1)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVMediaContext)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVNetwork)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVNumberEntry)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVRadioService)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVSatellite)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVSatelliteBS)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVSatelliteCS)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVSatelliteToggle)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVTerrestrialAnalog)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVTerrestrialDigital)
+DEFINE_KEYNAME_WITH_SAME_NAME(TVTimer)
+
+/******************************************************************************
  * Media Controller Keys
  *****************************************************************************/
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
 DEFINE_KEYNAME_WITH_SAME_NAME(AVRInput)
 DEFINE_KEYNAME_WITH_SAME_NAME(AVRPower)
-DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF0Red)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF1Green)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF2Yellow)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF3Blue)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF4Grey)
 DEFINE_KEYNAME_WITH_SAME_NAME(ColorF5Brown)
 DEFINE_KEYNAME_WITH_SAME_NAME(ClosedCaptionToggle)
 DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
 DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
+DEFINE_KEYNAME_WITH_SAME_NAME(DVR)
 DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear0)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear1)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear2)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear3)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall0)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall1)
 DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall2)
@@ -315,26 +392,32 @@ DEFINE_KEYNAME_WITH_SAME_NAME(GuideNextD
 DEFINE_KEYNAME_WITH_SAME_NAME(GuidePreviousDay)
 DEFINE_KEYNAME_WITH_SAME_NAME(Info)
 DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
 DEFINE_KEYNAME_WITH_SAME_NAME(Link)
 DEFINE_KEYNAME_WITH_SAME_NAME(ListProgram)
 DEFINE_KEYNAME_WITH_SAME_NAME(LiveContent)
 DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaApps)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaAudioTrack)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaFastForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkip)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkipBackward)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkipForward)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaStepBackward)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaStepForward)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaTopMenu)
+DEFINE_KEYNAME_WITH_SAME_NAME(NavigateIn)
+DEFINE_KEYNAME_WITH_SAME_NAME(NavigateNext)
+DEFINE_KEYNAME_WITH_SAME_NAME(NavigateOut)
+DEFINE_KEYNAME_WITH_SAME_NAME(NavigatePrevious)
 DEFINE_KEYNAME_WITH_SAME_NAME(NextFavoriteChannel)
 DEFINE_KEYNAME_WITH_SAME_NAME(NextUserProfile)
 DEFINE_KEYNAME_WITH_SAME_NAME(OnDemand)
+DEFINE_KEYNAME_WITH_SAME_NAME(Pairing)
 DEFINE_KEYNAME_WITH_SAME_NAME(PinPDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(PinPMove)
 DEFINE_KEYNAME_WITH_SAME_NAME(PinPToggle)
 DEFINE_KEYNAME_WITH_SAME_NAME(PinPUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedReset)
 DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
@@ -344,17 +427,14 @@ DEFINE_KEYNAME_WITH_SAME_NAME(RfBypass)
 DEFINE_KEYNAME_WITH_SAME_NAME(ScanChannelsToggle)
 DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
 DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
 DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
 DEFINE_KEYNAME_WITH_SAME_NAME(STBInput)
 DEFINE_KEYNAME_WITH_SAME_NAME(STBPower)
 DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
 DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
-DEFINE_KEYNAME_WITH_SAME_NAME(TV)
-DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
-DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
 DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
 DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
 DEFINE_KEYNAME_WITH_SAME_NAME(ZoomToggle)
 
 #undef DEFINE_KEYNAME_WITH_SAME_NAME
 #undef DEFINE_KEYNAME_INTERNAL
--- a/dom/events/test/marionette/manifest.ini
+++ b/dom/events/test/marionette/manifest.ini
@@ -1,6 +1,4 @@
 [DEFAULT]
-b2g = true
-browser = false
-qemu = true
+run-if = buildapp == 'b2g'
 
 [test_sensor_orientation.js]
--- a/dom/fmradio/test/marionette/manifest.ini
+++ b/dom/fmradio/test/marionette/manifest.ini
@@ -1,13 +1,10 @@
 [DEFAULT]
-b2g = true
-browser = false
-; We don't support FM radio emulation yet, see bug 872417
-qemu = false
+run-if = buildapp == 'b2g'
 
 [test_enable_disable.js]
 [test_set_frequency.js]
 [test_cancel_seek.js]
 [test_one_seek_at_once.js]
 [test_seek_up_and_down.js]
 [test_bug862672.js]
 [test_bug876597.js]
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -97,28 +97,16 @@ NS_IMPL_STRING_ATTR(HTMLAnchorElement, T
 NS_IMPL_STRING_ATTR(HTMLAnchorElement, Download, download)
 
 int32_t
 HTMLAnchorElement::TabIndexDefault()
 {
   return 0;
 }
 
-void
-HTMLAnchorElement::GetItemValueText(DOMString& aValue)
-{
-  GetHref(aValue);
-}
-
-void
-HTMLAnchorElement::SetItemValueText(const nsAString& aValue)
-{
-  SetHref(aValue);
-}
-
 bool
 HTMLAnchorElement::Draggable() const
 {
   // links can be dragged as long as there is an href and the
   // draggable attribute isn't false
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
     // no href, so just use the same behavior as other elements
     return nsGenericHTMLElement::Draggable();
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -227,18 +227,16 @@ public:
     GetHref(aResult);
   }
 
   static DOMTokenListSupportedToken sSupportedRelValues[];
 
 protected:
   virtual ~HTMLAnchorElement();
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
   RefPtr<nsDOMTokenList > mRelList;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLAnchorElement_h
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -60,28 +60,16 @@ NS_IMPL_STRING_ATTR(HTMLAreaElement, Sha
 NS_IMPL_STRING_ATTR(HTMLAreaElement, Download, download)
 
 int32_t
 HTMLAreaElement::TabIndexDefault()
 {
   return 0;
 }
 
-void
-HTMLAreaElement::GetItemValueText(DOMString& aValue)
-{
-  GetHref(aValue);
-}
-
-void
-HTMLAreaElement::SetItemValueText(const nsAString& aValue)
-{
-  SetHref(aValue);
-}
-
 NS_IMETHODIMP
 HTMLAreaElement::GetTarget(nsAString& aValue)
 {
   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::target, aValue)) {
     GetBaseTarget(aValue);
   }
   return NS_OK;
 }
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -180,17 +180,15 @@ public:
     GetHref(aResult);
   }
 
 protected:
   virtual ~HTMLAreaElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
   RefPtr<nsDOMTokenList > mRelList;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLAreaElement_h */
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -588,20 +588,20 @@ nsChangeHint
 HTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::width ||
       aAttribute == nsGkAtoms::height)
   {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   } else if (aAttribute == nsGkAtoms::moz_opaque)
   {
-    NS_UpdateHint(retval, NS_STYLE_HINT_VISUAL);
+    retval |= NS_STYLE_HINT_VISUAL;
   }
   return retval;
 }
 
 bool
 HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID,
                                   nsIAtom* aAttribute,
                                   const nsAString& aValue,
--- a/dom/html/HTMLDataElement.cpp
+++ b/dom/html/HTMLDataElement.cpp
@@ -25,23 +25,10 @@ HTMLDataElement::~HTMLDataElement()
 NS_IMPL_ELEMENT_CLONE(HTMLDataElement)
 
 JSObject*
 HTMLDataElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLDataElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
-void
-HTMLDataElement::GetItemValueText(DOMString& text)
-{
-  GetValue(text);
-}
-
-void
-HTMLDataElement::SetItemValueText(const nsAString& text)
-{
-  ErrorResult rv;
-  SetValue(text, rv);
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLDataElement.h
+++ b/dom/html/HTMLDataElement.h
@@ -26,18 +26,16 @@ public:
     GetHTMLAttr(nsGkAtoms::value, aValue);
   }
 
   void SetValue(const nsAString& aValue, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::value, aValue, aError);
   }
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
 
 protected:
   virtual ~HTMLDataElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
--- a/dom/html/HTMLDetailsElement.cpp
+++ b/dom/html/HTMLDetailsElement.cpp
@@ -61,17 +61,17 @@ HTMLDetailsElement::GetFirstSummary() co
 
 nsChangeHint
 HTMLDetailsElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                            int32_t aModType) const
 {
   nsChangeHint hint =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::open) {
-    NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
+    hint |= nsChangeHint_ReconstructFrame;
   }
   return hint;
 }
 
 nsresult
 HTMLDetailsElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                   nsAttrValueOrString* aValue, bool aNotify)
 {
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -190,17 +190,17 @@ HTMLFrameSetElement::ParseAttribute(int3
 nsChangeHint
 HTMLFrameSetElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                             int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::rows ||
       aAttribute == nsGkAtoms::cols) {
-    NS_UpdateHint(retval, mCurrentRowColHint);
+    retval |= mCurrentRowColHint;
   }
   return retval;
 }
 
 /**
  * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
  */
 nsresult
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -50,28 +50,16 @@ NS_IMPL_STRING_ATTR(HTMLIFrameElement, M
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, MarginWidth, marginwidth)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Name, name)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Scrolling, scrolling)
 NS_IMPL_URI_ATTR(HTMLIFrameElement, Src, src)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Width, width)
 NS_IMPL_BOOL_ATTR(HTMLIFrameElement, AllowFullscreen, allowfullscreen)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Srcdoc, srcdoc)
 
-void
-HTMLIFrameElement::GetItemValueText(DOMString& aValue)
-{
-  GetSrc(aValue);
-}
-
-void
-HTMLIFrameElement::SetItemValueText(const nsAString& aValue)
-{
-  SetSrc(aValue);
-}
-
 NS_IMETHODIMP
 HTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
 {
   return nsGenericHTMLFrameElement::GetContentDocument(aContentDocument);
 }
 
 bool
 HTMLIFrameElement::ParseAttribute(int32_t aNamespaceID,
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -188,19 +188,16 @@ public:
   // set, the fullscreen state of this element will not be reverted
   // automatically when its subdocument exits fullscreen.
   bool FullscreenFlag() const { return mFullscreenFlag; }
   void SetFullscreenFlag(bool aValue) { mFullscreenFlag = aValue; }
 
 protected:
   virtual ~HTMLIFrameElement();
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 
   static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
 };
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -190,28 +190,16 @@ HTMLImageElement::GetCurrentSrc(nsAStrin
     CopyUTF8toUTF16(spec, aValue);
   } else {
     SetDOMStringToNull(aValue);
   }
 
   return NS_OK;
 }
 
-void
-HTMLImageElement::GetItemValueText(DOMString& aValue)
-{
-  GetSrc(aValue);
-}
-
-void
-HTMLImageElement::SetItemValueText(const nsAString& aValue)
-{
-  SetSrc(aValue);
-}
-
 bool
 HTMLImageElement::Draggable() const
 {
   // images may be dragged unless the draggable attribute is false
   return !AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
                       nsGkAtoms::_false, eIgnoreCase);
 }
 
@@ -350,21 +338,21 @@ HTMLImageElement::MapAttributesIntoRule(
 nsChangeHint
 HTMLImageElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                          int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::usemap ||
       aAttribute == nsGkAtoms::ismap) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   } else if (aAttribute == nsGkAtoms::alt) {
     if (aModType == nsIDOMMutationEvent::ADDITION ||
         aModType == nsIDOMMutationEvent::REMOVAL) {
-      NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+      retval |= NS_STYLE_HINT_FRAMECHANGE;
     }
   }
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLImageElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -333,18 +333,16 @@ protected:
   // If the node's srcset/sizes make for an invalid selector, returns
   // false. This does not guarantee the resulting selector matches an image,
   // only that it is valid.
   bool TryCreateResponsiveSelector(nsIContent *aSourceNode,
                                    const nsAString *aSrcset = nullptr,
                                    const nsAString *aSizes = nullptr);
 
   CSSIntPoint GetXY();
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
   void UpdateFormOwner();
 
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                  nsAttrValueOrString* aValue,
                                  bool aNotify) override;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4949,30 +4949,30 @@ HTMLInputElement::GetAttributeChangeHint
                                          int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::type ||
       // The presence or absence of the 'directory' attribute determines what
       // buttons we show for type=file.
       aAttribute == nsGkAtoms::directory) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   } else if (mType == NS_FORM_INPUT_IMAGE &&
              (aAttribute == nsGkAtoms::alt ||
               aAttribute == nsGkAtoms::value)) {
     // We might need to rebuild our alt text.  Just go ahead and
     // reconstruct our frame.  This should be quite rare..
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   } else if (aAttribute == nsGkAtoms::value) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   } else if (aAttribute == nsGkAtoms::size &&
              IsSingleLineTextControl(false)) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   } else if (PlaceholderApplies() && aAttribute == nsGkAtoms::placeholder) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   }
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLInputElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -60,17 +60,17 @@ HTMLLegendElement::ParseAttribute(int32_
 
 nsChangeHint
 HTMLLegendElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::align) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   }
   return retval;
 }
 
 nsresult
 HTMLLegendElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify)
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -127,28 +127,16 @@ NS_IMPL_URI_ATTR(HTMLLinkElement, Href, 
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Hreflang, hreflang)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Media, media)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Rel, rel)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Rev, rev)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Target, target)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Type, type)
 
 void
-HTMLLinkElement::GetItemValueText(DOMString& aValue)
-{
-  GetHref(aValue);
-}
-
-void
-HTMLLinkElement::SetItemValueText(const nsAString& aValue)
-{
-  SetHref(aValue);
-}
-
-void
 HTMLLinkElement::OnDNSPrefetchRequested()
 {
   UnsetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
   SetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
 }
 
 void
 HTMLLinkElement::OnDNSPrefetchDeferred()
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -164,21 +164,18 @@ protected:
   // nsStyleLinkElement
   virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsScoped,
                                  bool* aIsAlternate) override;
 protected:
-  // nsGenericHTMLElement
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
+  RefPtr<nsDOMTokenList> mRelList;
 
-  RefPtr<nsDOMTokenList > mRelList;
 private:
   RefPtr<ImportLoader> mImportLoader;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLLinkElement_h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2320,30 +2320,16 @@ HTMLMediaElement::~HTMLMediaElement()
 
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
   }
 
   WakeLockRelease();
 }
 
-void
-HTMLMediaElement::GetItemValueText(DOMString& aValue)
-{
-  // Can't call GetSrc because we don't have a JSContext
-  GetURIAttr(nsGkAtoms::src, nullptr, aValue);
-}
-
-void
-HTMLMediaElement::SetItemValueText(const nsAString& aValue)
-{
-  // Can't call SetSrc because we don't have a JSContext
-  SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true);
-}
-
 void HTMLMediaElement::StopSuspendingAfterFirstFrame()
 {
   mAllowSuspendAfterFirstFrame = false;
   if (!mSuspendedAfterFirstFrame)
     return;
   mSuspendedAfterFirstFrame = false;
   if (mDecoder) {
     mDecoder->Resume();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -728,19 +728,16 @@ protected:
   class StreamSizeListener;
 
   MediaDecoderOwner::NextFrameStatus NextFrameStatus();
   void SetDecoder(MediaDecoder* aDecoder) {
     MOZ_ASSERT(aDecoder); // Use ShutdownDecoder() to clear.
     mDecoder = aDecoder;
   }
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
   class WakeLockBoolWrapper {
   public:
     explicit WakeLockBoolWrapper(bool val = false)
       : mValue(val), mCanPlay(true), mOuter(nullptr) {}
 
     ~WakeLockBoolWrapper();
 
     void SetOuter(HTMLMediaElement* outer) { mOuter = outer; }
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -33,28 +33,16 @@ NS_IMPL_ISUPPORTS_INHERITED(HTMLMetaElem
 NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
 
 
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Content, content)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, HttpEquiv, httpEquiv)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Name, name)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Scheme, scheme)
 
-void
-HTMLMetaElement::GetItemValueText(DOMString& aValue)
-{
-  GetContent(aValue);
-}
-
-void
-HTMLMetaElement::SetItemValueText(const nsAString& aValue)
-{
-  SetContent(aValue);
-}
-
 nsresult
 HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument)
 {
   if (!aDocument ||
       !AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::referrer, eIgnoreCase)) {
     return NS_OK;
   }
   nsAutoString content;
@@ -125,28 +113,27 @@ HTMLMetaElement::BindToTree(nsIDocument*
       nsAutoString content;
       rv = GetContent(content);
       NS_ENSURE_SUCCESS(rv, rv);
       content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
 
       nsIPrincipal* principal = aDocument->NodePrincipal();
       nsCOMPtr<nsIContentSecurityPolicy> csp;
       nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
-      rv = principal->EnsureCSP(domDoc, getter_AddRefs(csp));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      // Multiple CSPs (delivered through either header of meta tag) need to be
-      // joined together, see:
-      // https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
-      rv = csp->AppendPolicy(content,
-                             false, // csp via meta tag can not be report only
-                             true); // delivered through the meta tag
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      aDocument->ApplySettingsFromCSP(false);
+      principal->EnsureCSP(domDoc, getter_AddRefs(csp));
+      if (csp) {
+        // Multiple CSPs (delivered through either header of meta tag) need to be
+        // joined together, see:
+        // https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
+        rv = csp->AppendPolicy(content,
+                               false, // csp via meta tag can not be report only
+                               true); // delivered through the meta tag
+        NS_ENSURE_SUCCESS(rv, rv);
+        aDocument->ApplySettingsFromCSP(false);
+      }
     }
   }
 
   // Referrer Policy spec requires a <meta name="referrer" tag to be in the
   // <head> element.
   rv = SetMetaReferrer(aDocument);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
--- a/dom/html/HTMLMetaElement.h
+++ b/dom/html/HTMLMetaElement.h
@@ -60,19 +60,16 @@ public:
     SetHTMLAttr(nsGkAtoms::scheme, aScheme, aRv);
   }
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 protected:
   virtual ~HTMLMetaElement();
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
 private:
   nsresult SetMetaReferrer(nsIDocument* aDocument);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLMetaElement_h
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -239,28 +239,16 @@ HTMLObjectElement::PostHandleEvent(Event
 #endif // #ifdef XP_MACOSX
 
 NS_IMETHODIMP
 HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
 {
   return nsGenericHTMLFormElement::GetForm(aForm);
 }
 
-void
-HTMLObjectElement::GetItemValueText(DOMString& aValue)
-{
-  GetData(aValue);
-}
-
-void
-HTMLObjectElement::SetItemValueText(const nsAString& aValue)
-{
-  SetData(aValue);
-}
-
 nsresult
 HTMLObjectElement::BindToTree(nsIDocument *aDocument,
                               nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
                                                      aBindingParent,
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -249,19 +249,16 @@ private:
    */
   bool IsFocusableForTabIndex();
 
   nsContentPolicyType GetContentPolicyType() const override
   {
     return nsIContentPolicy::TYPE_INTERNAL_OBJECT;
   }
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
   virtual ~HTMLObjectElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 
   bool mIsDoneAddingChildren;
--- a/dom/html/HTMLOptionElement.cpp
+++ b/dom/html/HTMLOptionElement.cpp
@@ -169,17 +169,17 @@ nsChangeHint
 HTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
 
   if (aAttribute == nsGkAtoms::label ||
       aAttribute == nsGkAtoms::text) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   }
   return retval;
 }
 
 nsresult
 HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                  nsAttrValueOrString* aValue,
                                  bool aNotify)
deleted file mode 100644
--- a/dom/html/HTMLPropertiesCollection.cpp
+++ /dev/null
@@ -1,518 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "HTMLPropertiesCollection.h"
-#include "nsIDocument.h"
-#include "nsContentUtils.h"
-#include "nsGenericHTMLElement.h"
-#include "nsVariant.h"
-#include "nsDOMTokenList.h"
-#include "nsAttrValue.h"
-#include "nsWrapperCacheInlines.h"
-#include "mozilla/dom/HTMLPropertiesCollectionBinding.h"
-#include "jsapi.h"
-#include "MainThreadUtils.h"
-#include "mozilla/Assertions.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLPropertiesCollection)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLPropertiesCollection)
-  // SetDocument(nullptr) ensures that we remove ourselves as a mutation observer
-  tmp->SetDocument(nullptr);
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNames)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNamedItemEntries)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mProperties)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLPropertiesCollection)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNames)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNamedItemEntries);
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProperties)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLPropertiesCollection)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-HTMLPropertiesCollection::HTMLPropertiesCollection(nsGenericHTMLElement* aRoot)
-  : mRoot(aRoot)
-  , mDoc(aRoot->GetUncomposedDoc())
-  , mIsDirty(true)
-{
-  mNames = new PropertyStringList(this);
-  if (mDoc) {
-    mDoc->AddMutationObserver(this);
-  }
-}
-
-HTMLPropertiesCollection::~HTMLPropertiesCollection()
-{
-  if (mDoc) {
-    mDoc->RemoveMutationObserver(this);
-  }
-}
-
-NS_INTERFACE_TABLE_HEAD(HTMLPropertiesCollection)
-    NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
-    NS_INTERFACE_TABLE(HTMLPropertiesCollection,
-                       nsIDOMHTMLCollection,
-                       nsIHTMLCollection,
-                       nsIMutationObserver)
-    NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLPropertiesCollection)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLPropertiesCollection)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLPropertiesCollection)
-
-void
-HTMLPropertiesCollection::SetDocument(nsIDocument* aDocument) {
-  if (mDoc) {
-    mDoc->RemoveMutationObserver(this);
-  }
-  mDoc = aDocument;
-  if (mDoc) {
-    mDoc->AddMutationObserver(this);
-  }
-  for (auto iter = mNamedItemEntries.Iter(); !iter.Done(); iter.Next()) {
-    iter.UserData()->SetDocument(aDocument);
-  }
-  mIsDirty = true;
-}
-
-JSObject*
-HTMLPropertiesCollection::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
-{
-  return HTMLPropertiesCollectionBinding::Wrap(cx, this, aGivenProto);
-}
-
-NS_IMETHODIMP
-HTMLPropertiesCollection::GetLength(uint32_t* aLength)
-{
-  EnsureFresh();
-  *aLength = mProperties.Length();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLPropertiesCollection::Item(uint32_t aIndex, nsIDOMNode** aResult)
-{
-  nsINode* result = nsIHTMLCollection::Item(aIndex);
-  if (result) {
-    NS_ADDREF(*aResult = result->AsDOMNode());
-  } else {
-    *aResult = nullptr;
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLPropertiesCollection::NamedItem(const nsAString& aName,
-                                    nsIDOMNode** aResult)
-{
-  *aResult = nullptr;
-  return NS_OK;
-}
-
-Element*
-HTMLPropertiesCollection::GetElementAt(uint32_t aIndex)
-{
-  EnsureFresh();
-  return mProperties.SafeElementAt(aIndex);
-}
-
-nsINode*
-HTMLPropertiesCollection::GetParentObject()
-{
-  return mRoot;
-}
-
-PropertyNodeList*
-HTMLPropertiesCollection::NamedItem(const nsAString& aName)
-{
-  EnsureFresh();
-
-  PropertyNodeList* propertyList = mNamedItemEntries.GetWeak(aName);
-  if (!propertyList) {
-    RefPtr<PropertyNodeList> newPropertyList =
-      new PropertyNodeList(this, mRoot, aName);
-    mNamedItemEntries.Put(aName, newPropertyList);
-    propertyList = newPropertyList;
-  }
-  return propertyList;
-}
-
-void
-HTMLPropertiesCollection::AttributeChanged(nsIDocument *aDocument, Element* aElement,
-                                           int32_t aNameSpaceID, nsIAtom* aAttribute,
-                                           int32_t aModType,
-                                           const nsAttrValue* aOldValue)
-{
-  mIsDirty = true;
-}
-
-void
-HTMLPropertiesCollection::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
-                                          nsIContent* aFirstNewContent,
-                                          int32_t aNewIndexInContainer)
-{
-  mIsDirty = true;
-}
-
-void
-HTMLPropertiesCollection::ContentInserted(nsIDocument *aDocument,
-                                          nsIContent* aContainer,
-                                          nsIContent* aChild,
-                                          int32_t aIndexInContainer)
-{
-  mIsDirty = true;
-}
-
-void
-HTMLPropertiesCollection::ContentRemoved(nsIDocument *aDocument,
-                                         nsIContent* aContainer,
-                                         nsIContent* aChild,
-                                         int32_t aIndexInContainer,
-                                         nsIContent* aPreviousSibling)
-{
-  mIsDirty = true;
-}
-
-void
-HTMLPropertiesCollection::EnsureFresh()
-{
-  if (mDoc && !mIsDirty) {
-    return;
-  }
-  mIsDirty = false;
-
-  mProperties.Clear();
-  mNames->Clear();
-  // We don't clear NamedItemEntries because the PropertyNodeLists must be live.
-  for (auto iter = mNamedItemEntries.Iter(); !iter.Done(); iter.Next()) {
-    iter.UserData()->SetDirty();
-  }
-  if (!mRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
-    return;
-  }
-
-  CrawlProperties();
-  TreeOrderComparator comparator;
-  mProperties.Sort(comparator);
-
-  // Create the names DOMStringList
-  uint32_t count = mProperties.Length();
-  for (uint32_t i = 0; i < count; ++i) {
-    const nsAttrValue* attr = mProperties.ElementAt(i)->GetParsedAttr(nsGkAtoms::itemprop); 
-    for (uint32_t i = 0; i < attr->GetAtomCount(); i++) {
-      nsDependentAtomString propName(attr->AtomAt(i));
-      bool contains = mNames->ContainsInternal(propName);
-      if (!contains) {
-        mNames->Add(propName);
-      }
-    }
-  }
-}
-
-static Element*
-GetElementByIdForConnectedSubtree(nsIContent* aContent, const nsIAtom* aId)
-{
-  aContent = static_cast<nsIContent*>(aContent->SubtreeRoot());
-  do {
-    if (aContent->GetID() == aId) {
-      return aContent->AsElement();
-    }
-    aContent = aContent->GetNextNode();
-  } while(aContent);
-
-  return nullptr;
-}
-
-void
-HTMLPropertiesCollection::CrawlProperties()
-{
-  nsIDocument* doc = mRoot->GetUncomposedDoc();
-
-  const nsAttrValue* attr = mRoot->GetParsedAttr(nsGkAtoms::itemref);
-  if (attr) {
-    for (uint32_t i = 0; i < attr->GetAtomCount(); i++) {
-      nsIAtom* ref = attr->AtomAt(i);
-      Element* element;
-      if (doc) {
-        element = doc->GetElementById(nsDependentAtomString(ref));
-      } else {
-        element = GetElementByIdForConnectedSubtree(mRoot, ref);
-      }
-      if (element && element != mRoot) {
-        CrawlSubtree(element);
-      }
-    }
-  }
-
-  CrawlSubtree(mRoot);
-}
-
-void
-HTMLPropertiesCollection::CrawlSubtree(Element* aElement)
-{
-  nsIContent* aContent = aElement;
-  while (aContent) {
-    // We must check aContent against mRoot because 
-    // an element must not be its own property
-    if (aContent == mRoot || !aContent->IsHTMLElement()) {
-      // Move on to the next node in the tree
-      aContent = aContent->GetNextNode(aElement);
-    } else {
-      MOZ_ASSERT(aContent->IsElement(), "IsHTMLElement() returned true!");
-      Element* element = aContent->AsElement();
-      if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) &&
-          !mProperties.Contains(element)) {
-        mProperties.AppendElement(static_cast<nsGenericHTMLElement*>(element));
-      }
-
-      if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
-        aContent = element->GetNextNonChildNode(aElement);
-      } else {
-        aContent = element->GetNextNode(aElement);
-      }
-    }
-  }
-}
-
-void
-HTMLPropertiesCollection::GetSupportedNames(nsTArray<nsString>& aNames)
-{
-  EnsureFresh();
-  mNames->CopyList(aNames);
-}
-
-PropertyNodeList::PropertyNodeList(HTMLPropertiesCollection* aCollection,
-                                   nsIContent* aParent, const nsAString& aName)
-  : mName(aName),
-    mDoc(aParent->GetUncomposedDoc()),
-    mCollection(aCollection),
-    mParent(aParent),
-    mIsDirty(true)
-{
-  if (mDoc) {
-    mDoc->AddMutationObserver(this);
-  }
-}
-
-PropertyNodeList::~PropertyNodeList()
-{
-  if (mDoc) {
-    mDoc->RemoveMutationObserver(this);
-  }
-}
-
-void
-PropertyNodeList::SetDocument(nsIDocument* aDoc)
-{
-  if (mDoc) {
-    mDoc->RemoveMutationObserver(this);
-  }
-  mDoc = aDoc;
-  if (mDoc) {
-    mDoc->AddMutationObserver(this);
-  }
-  mIsDirty = true;
-}
-
-NS_IMETHODIMP
-PropertyNodeList::GetLength(uint32_t* aLength)
-{
-  EnsureFresh();
-  *aLength = mElements.Length();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-PropertyNodeList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
-{
-  EnsureFresh();
-  nsINode* element = mElements.SafeElementAt(aIndex);
-  if (!element) {
-    *aReturn = nullptr;
-    return NS_OK;
-  }
-  return CallQueryInterface(element, aReturn);
-}
-
-nsIContent*
-PropertyNodeList::Item(uint32_t aIndex)
-{
-  EnsureFresh();
-  return mElements.SafeElementAt(aIndex);
-}
-
-int32_t
-PropertyNodeList::IndexOf(nsIContent* aContent)
-{
-  EnsureFresh();
-  return mElements.IndexOf(aContent);
-}
-
-nsINode*
-PropertyNodeList::GetParentObject()
-{
-  return mParent;
-}
-
-JSObject*
-PropertyNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
-  return PropertyNodeListBinding::Wrap(cx, this, aGivenProto);
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList)
-  // SetDocument(nullptr) ensures that we remove ourselves as a mutation observer
-  tmp->SetDocument(nullptr);
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCollection)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mElements)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PropertyNodeList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCollection)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PropertyNodeList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyNodeList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyNodeList)
-
-NS_INTERFACE_TABLE_HEAD(PropertyNodeList)
-    NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
-    NS_INTERFACE_TABLE(PropertyNodeList,
-                       nsIDOMNodeList,
-                       nsINodeList,
-                       nsIMutationObserver)
-    NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PropertyNodeList)
-NS_INTERFACE_MAP_END
-
-void
-PropertyNodeList::GetValues(JSContext* aCx, nsTArray<JS::Value >& aResult,
-                            ErrorResult& aError)
-{
-  EnsureFresh();
-
-  JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
-  JSAutoCompartment ac(aCx, wrapper);
-  uint32_t length = mElements.Length();
-  for (uint32_t i = 0; i < length; ++i) {
-    JS::Rooted<JS::Value> v(aCx);
-    mElements.ElementAt(i)->GetItemValue(aCx, wrapper, &v, aError);
-    if (aError.Failed()) {
-      return;
-    }
-    aResult.AppendElement(v);
-  }
-}
-
-void
-PropertyNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
-                                   int32_t aNameSpaceID, nsIAtom* aAttribute,
-                                   int32_t aModType,
-                                   const nsAttrValue* aOldValue)
-{
-  mIsDirty = true;
-}
-
-void
-PropertyNodeList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
-                                  nsIContent* aFirstNewContent,
-                                  int32_t aNewIndexInContainer)
-{
-  mIsDirty = true;
-}
-
-void
-PropertyNodeList::ContentInserted(nsIDocument* aDocument,
-                                  nsIContent* aContainer,
-                                  nsIContent* aChild,
-                                  int32_t aIndexInContainer)
-{
-  mIsDirty = true;
-}
-
-void
-PropertyNodeList::ContentRemoved(nsIDocument* aDocument,
-                                 nsIContent* aContainer,
-                                 nsIContent* aChild,
-                                 int32_t aIndexInContainer,
-                                 nsIContent* aPreviousSibling)
-{
-  mIsDirty = true;
-}
-
-void
-PropertyNodeList::EnsureFresh()
-{
-  if (mDoc && !mIsDirty) {
-    return;
-  }
-  mIsDirty = false;
-
-  mCollection->EnsureFresh();
-  Clear();
-
-  uint32_t count = mCollection->mProperties.Length();
-  for (uint32_t i = 0; i < count; ++i) {
-    nsGenericHTMLElement* element = mCollection->mProperties.ElementAt(i);
-    const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::itemprop);
-    if (attr->Contains(mName)) {
-      AppendElement(element);
-    }
-  }
-}
-
-PropertyStringList::PropertyStringList(HTMLPropertiesCollection* aCollection)
-  : DOMStringList()
-  , mCollection(aCollection)
-{ }
-
-PropertyStringList::~PropertyStringList()
-{ }
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(PropertyStringList, DOMStringList,
-                                   mCollection)
-
-NS_IMPL_ADDREF_INHERITED(PropertyStringList, DOMStringList)
-NS_IMPL_RELEASE_INHERITED(PropertyStringList, DOMStringList)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PropertyStringList)
-NS_INTERFACE_MAP_END_INHERITING(DOMStringList)
-
-void
-PropertyStringList::EnsureFresh()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  mCollection->EnsureFresh();
-}
-
-bool
-PropertyStringList::ContainsInternal(const nsAString& aString)
-{
-  // This method should not call EnsureFresh, otherwise we may become stuck in an infinite loop.
-  return mNames.Contains(aString);
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/html/HTMLPropertiesCollection.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef HTMLPropertiesCollection_h_
-#define HTMLPropertiesCollection_h_
-
-#include "mozilla/Attributes.h"
-#include "mozilla/dom/DOMStringList.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsAutoPtr.h"
-#include "nsCOMArray.h"
-#include "nsIMutationObserver.h"
-#include "nsStubMutationObserver.h"
-#include "nsBaseHashtable.h"
-#include "nsINodeList.h"
-#include "nsIHTMLCollection.h"
-#include "nsHashKeys.h"
-#include "nsRefPtrHashtable.h"
-#include "nsGenericHTMLElement.h"
-
-class nsIDocument;
-class nsINode;
-
-namespace mozilla {
-namespace dom {
-
-class HTMLPropertiesCollection;
-class PropertyNodeList;
-class Element;
-
-class PropertyStringList : public DOMStringList
-{
-public:
-  explicit PropertyStringList(HTMLPropertiesCollection* aCollection);
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PropertyStringList, DOMStringList)
-
-  bool ContainsInternal(const nsAString& aString);
-
-protected:
-  virtual ~PropertyStringList();
-
-  virtual void EnsureFresh() override;
-
-  RefPtr<HTMLPropertiesCollection> mCollection;
-};
-
-class HTMLPropertiesCollection final : public nsIHTMLCollection,
-                                       public nsStubMutationObserver,
-                                       public nsWrapperCache
-{
-  friend class PropertyNodeList;
-  friend class PropertyStringList;
-public:
-  explicit HTMLPropertiesCollection(nsGenericHTMLElement* aRoot);
-
-  // nsWrapperCache
-  using nsWrapperCache::GetWrapperPreserveColor;
-  using nsWrapperCache::GetWrapper;
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-protected:
-  virtual ~HTMLPropertiesCollection();
-
-  virtual JSObject* GetWrapperPreserveColorInternal() override
-  {
-    return nsWrapperCache::GetWrapperPreserveColor();
-  }
-public:
-
-  virtual Element* GetElementAt(uint32_t aIndex) override;
-
-  void SetDocument(nsIDocument* aDocument);
-  nsINode* GetParentObject() override;
-
-  virtual Element*
-  GetFirstNamedElement(const nsAString& aName, bool& aFound) override
-  {
-    // HTMLPropertiesCollection.namedItem and the named getter call the
-    // NamedItem that returns a PropertyNodeList, calling
-    // HTMLCollection.namedItem doesn't make sense so this returns null.
-    aFound = false;
-    return nullptr;
-  }
-  PropertyNodeList* NamedItem(const nsAString& aName);
-  PropertyNodeList* NamedGetter(const nsAString& aName, bool& aFound)
-  {
-    aFound = IsSupportedNamedProperty(aName);
-    return aFound ? NamedItem(aName) : nullptr;
-  }
-  DOMStringList* Names()
-  {
-    EnsureFresh();
-    return mNames;
-  }
-  virtual void GetSupportedNames(nsTArray<nsString>& aNames) override;
-
-  NS_DECL_NSIDOMHTMLCOLLECTION
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-
-  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(HTMLPropertiesCollection,
-                                                         nsIHTMLCollection)
-
-protected:
-  // Make sure this collection is up to date, in case the DOM has been mutated.
-  void EnsureFresh();
-
-  // Crawl the properties of mRoot, following any itemRefs it may have
-  void CrawlProperties();
-
-  // Crawl startNode and its descendants, looking for items
-  void CrawlSubtree(Element* startNode);
-
-  bool IsSupportedNamedProperty(const nsAString& aName)
-  {
-    EnsureFresh();
-    return mNames->ContainsInternal(aName);
-  }
-
-  // the items that make up this collection
-  nsTArray<RefPtr<nsGenericHTMLElement> > mProperties;
-
-  // the itemprop attribute of the properties
-  RefPtr<PropertyStringList> mNames;
-
-  // The cached PropertyNodeLists that are NamedItems of this collection
-  nsRefPtrHashtable<nsStringHashKey, PropertyNodeList> mNamedItemEntries;
-
-  // The element this collection is rooted at
-  RefPtr<nsGenericHTMLElement> mRoot;
-
-  // The document mRoot is in, if any
-  nsCOMPtr<nsIDocument> mDoc;
-
-  // True if there have been DOM modifications since the last EnsureFresh call.
-  bool mIsDirty;
-};
-
-class PropertyNodeList final : public nsINodeList,
-                               public nsStubMutationObserver
-{
-public:
-  PropertyNodeList(HTMLPropertiesCollection* aCollection,
-                   nsIContent* aRoot, const nsAString& aName);
-
-  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
-
-  void SetDocument(nsIDocument* aDocument);
-
-  void GetValues(JSContext* aCx, nsTArray<JS::Value >& aResult,
-                 ErrorResult& aError);
-
-  virtual nsIContent* Item(uint32_t aIndex) override;
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(PropertyNodeList,
-                                                         nsINodeList)
-  NS_DECL_NSIDOMNODELIST
-
-  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-
-  // nsINodeList interface
-  virtual int32_t IndexOf(nsIContent* aContent) override;
-  virtual nsINode* GetParentObject() override;
-
-  void AppendElement(nsGenericHTMLElement* aElement)
-  {
-    mElements.AppendElement(aElement);
-  }
-
-  void Clear()
-  {
-    mElements.Clear();
-  }
-
-  void SetDirty() { mIsDirty = true; }
-
-protected:
-  virtual ~PropertyNodeList();
-
-  // Make sure this list is up to date, in case the DOM has been mutated.
-  void EnsureFresh();
-
-  // the the name that this list corresponds to
-  nsString mName;
-
-  // the document mParent is in, if any
-  nsCOMPtr<nsIDocument> mDoc;
-
-  // the collection that this list is a named item of
-  RefPtr<HTMLPropertiesCollection> mCollection;
-
-  // the node this list is rooted at
-  nsCOMPtr<nsINode> mParent;
-
-  // the properties that make up this list
-  nsTArray<RefPtr<nsGenericHTMLElement> > mElements;
-
-  // True if there have been DOM modifications since the last EnsureFresh call. 
-  bool mIsDirty;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // HTMLPropertiesCollection_h_
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1408,17 +1408,17 @@ HTMLSelectElement::MapAttributesIntoRule
 nsChangeHint
 HTMLSelectElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::multiple ||
       aAttribute == nsGkAtoms::size) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   }
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLSelectElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -36,36 +36,16 @@ HTMLSharedObjectElement::HTMLSharedObjec
 {
   RegisterActivityObserver();
   SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
 
   // By default we're in the loading state
   AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
-void
-HTMLSharedObjectElement::GetItemValueText(DOMString& aValue)
-{
-  if (mNodeInfo->Equals(nsGkAtoms::applet)) {
-    nsGenericHTMLElement::GetItemValueText(aValue);
-  } else {
-    GetSrc(aValue);
-  }
-}
-
-void
-HTMLSharedObjectElement::SetItemValueText(const nsAString& aValue)
-{
-  if (mNodeInfo->Equals(nsGkAtoms::applet)) {
-    nsGenericHTMLElement::SetItemValueText(aValue);
-  } else {
-    SetSrc(aValue);
-  }
-}
-
 HTMLSharedObjectElement::~HTMLSharedObjectElement()
 {
 #ifdef XP_MACOSX
   HTMLObjectElement::OnFocusBlurPlugin(this, false);
 #endif
   UnregisterActivityObserver();
   DestroyImageLoadingContent();
 }
--- a/dom/html/HTMLSharedObjectElement.h
+++ b/dom/html/HTMLSharedObjectElement.h
@@ -207,19 +207,16 @@ private:
   }
 
   nsContentPolicyType GetContentPolicyType() const override;
 
   // mIsDoneAddingChildren is only really used for <applet>.  This boolean is
   // always true for <embed>, per the documentation in nsIContent.h.
   bool mIsDoneAddingChildren;
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 
   /**
    * Decides whether we should load embed node content.
    *
--- a/dom/html/HTMLSourceElement.cpp
+++ b/dom/html/HTMLSourceElement.cpp
@@ -141,28 +141,16 @@ HTMLSourceElement::AfterSetAttr(int32_t 
       }
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aNotify);
 }
 
-void
-HTMLSourceElement::GetItemValueText(DOMString& aValue)
-{
-  GetSrc(aValue);
-}
-
-void
-HTMLSourceElement::SetItemValueText(const nsAString& aValue)
-{
-  SetSrc(aValue);
-}
-
 nsresult
 HTMLSourceElement::BindToTree(nsIDocument *aDocument,
                               nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
                                                  aParent,
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -103,24 +103,20 @@ public:
   }
 
 protected:
   virtual ~HTMLSourceElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 protected:
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
-
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
                                 bool aNotify) override;
 
-
 private:
   RefPtr<nsMediaList> mMediaList;
   RefPtr<MediaSource> mSrcMediaSource;
 
   // Generates a new nsMediaList using the given input
   void UpdateMediaList(const nsAttrValue* aValue);
 };
 
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -431,21 +431,21 @@ HTMLTextAreaElement::MapAttributesIntoRu
 nsChangeHint
 HTMLTextAreaElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                             int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::rows ||
       aAttribute == nsGkAtoms::cols) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
+    retval |= NS_STYLE_HINT_REFLOW;
   } else if (aAttribute == nsGkAtoms::wrap) {
-    NS_UpdateHint(retval, nsChangeHint_ReconstructFrame);
+    retval |= nsChangeHint_ReconstructFrame;
   } else if (aAttribute == nsGkAtoms::placeholder) {
-    NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
+    retval |= NS_STYLE_HINT_FRAMECHANGE;
   }
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTextAreaElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
--- a/dom/html/HTMLTimeElement.cpp
+++ b/dom/html/HTMLTimeElement.cpp
@@ -27,28 +27,10 @@ HTMLTimeElement::~HTMLTimeElement()
 NS_IMPL_ELEMENT_CLONE(HTMLTimeElement)
 
 JSObject*
 HTMLTimeElement::WrapNode(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLTimeElementBinding::Wrap(cx, this, aGivenProto);
 }
 
-void
-HTMLTimeElement::GetItemValueText(DOMString& text)
-{
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::datetime)) {
-    GetDateTime(text);
-  } else {
-    ErrorResult rv;
-    GetTextContentInternal(text, rv);
-  }
-}
-
-void
-HTMLTimeElement::SetItemValueText(const nsAString& text)
-{
-  ErrorResult rv;
-  SetDateTime(text, rv);
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLTimeElement.h
+++ b/dom/html/HTMLTimeElement.h
@@ -27,18 +27,16 @@ public:
     GetHTMLAttr(nsGkAtoms::datetime, aDateTime);
   }
 
   void SetDateTime(const nsAString& aDateTime, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::datetime, aDateTime, aError);
   }
 
-  virtual void GetItemValueText(DOMString& text) override;
-  virtual void SetItemValueText(const nsAString& text) override;
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
 
 protected:
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLTrackElement.h
+++ b/dom/html/HTMLTrackElement.h
@@ -88,27 +88,16 @@ public:
 
   uint16_t ReadyState() const;
   void SetReadyState(uint16_t aReadyState);
 
   TextTrack* GetTrack();
 
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
 
-  // For Track, ItemValue reflects the src attribute
-  virtual void GetItemValueText(DOMString& aText) override
-  {
-    GetSrc(aText);
-  }
-  virtual void SetItemValueText(const nsAString& aText) override
-  {
-    ErrorResult rv;
-    SetSrc(aText, rv);
-  }
-
   // Override ParseAttribute() to convert kind strings to enum values.
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
 
   // Override BindToTree() so that we can trigger a load when we become
   // the child of a media element.
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -23,17 +23,16 @@ XPIDL_SOURCES += [
     'nsIImageDocument.idl',
     'nsIMenuBuilder.idl',
     'nsIPhonetic.idl',
 ]
 
 XPIDL_MODULE = 'content_html'
 
 EXPORTS += [
-    'HTMLPropertiesCollection.h',
     'nsFormSubmission.h',
     'nsGenericHTMLElement.h',
     'nsHTMLDNSPrefetch.h',
     'nsIConstraintValidation.h',
     'nsIForm.h',
     'nsIFormControl.h',
     'nsIFormProcessor.h',
     'nsIHTMLCollection.h',
@@ -163,17 +162,16 @@ UNIFIED_SOURCES += [
     'HTMLOptGroupElement.cpp',
     'HTMLOptionElement.cpp',
     'HTMLOptionsCollection.cpp',
     'HTMLOutputElement.cpp',
     'HTMLParagraphElement.cpp',
     'HTMLPictureElement.cpp',
     'HTMLPreElement.cpp',
     'HTMLProgressElement.cpp',
-    'HTMLPropertiesCollection.cpp',
     'HTMLScriptElement.cpp',
     'HTMLSelectElement.cpp',
     'HTMLShadowElement.cpp',
     'HTMLSharedElement.cpp',
     'HTMLSharedListElement.cpp',
     'HTMLSharedObjectElement.cpp',
     'HTMLSourceElement.cpp',
     'HTMLSpanElement.cpp',
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -89,17 +89,16 @@
 #include "HTMLMenuElement.h"
 #include "nsDOMMutationObserver.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/FromParser.h"
 #include "mozilla/dom/Link.h"
 #include "mozilla/dom/UndoManager.h"
 #include "mozilla/BloomFilter.h"
 
-#include "HTMLPropertiesCollection.h"
 #include "nsVariant.h"
 #include "nsDOMTokenList.h"
 #include "nsThreadUtils.h"
 #include "nsTextFragment.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/ErrorResult.h"
 #include "nsHTMLDocument.h"
@@ -542,23 +541,16 @@ nsGenericHTMLElement::BindToTree(nsIDocu
                                  bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
                                                      aBindingParent,
                                                      aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDocument) {
-    if (HasProperties()) {
-      HTMLPropertiesCollection* properties = 
-        static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
-      if (properties) {
-        properties->SetDocument(aDocument);
-      }
-    }
     RegAccessKey();
     if (HasName()) {
       aDocument->
         AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
     }
 
     if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
       nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
@@ -573,24 +565,16 @@ nsGenericHTMLElement::BindToTree(nsIDocu
 
 void
 nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   if (IsInUncomposedDoc()) {
     UnregAccessKey();
   }
   
-  if(HasProperties()) {
-    HTMLPropertiesCollection* properties = 
-      static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
-    if (properties) {
-      properties->SetDocument(nullptr);
-    }
-  }
-
   RemoveFromNameTable();
 
   if (GetContentEditableValue() == eTrue) {
     //XXXsmaug Fix this for Shadow DOM, bug 1066965.
     nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetUncomposedDoc());
     if (htmlDocument) {
       htmlDocument->ChangeContentEditableCount(this, -1);
     }
@@ -1023,20 +1007,17 @@ nsGenericHTMLElement::ParseAttribute(int
       return true;
     }
 
     if (aAttribute == nsGkAtoms::contenteditable) {
       aResult.ParseAtom(aValue);
       return true;
     }
 
-    if (aAttribute == nsGkAtoms::itemref ||
-        aAttribute == nsGkAtoms::itemprop ||
-        aAttribute == nsGkAtoms::itemtype ||
-        aAttribute