merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 03 Dec 2015 12:00:42 +0100
changeset 309551 85cf2e720a8405c43eabc9b34cce381b66d25ef9
parent 309387 31fc97d173b3e3da5de35d54018855e6c905787e (current diff)
parent 309550 c0f3de2d37b4ef542f61aa5cabf16ac176b0aef1 (diff)
child 309552 33d954cc69ff8e0bd22410e3641533e4fac500cf
child 309559 51fd1f4ffae133c5aac7f8bb6d1818ff5cf5bdb5
child 309587 d37627931b2ba7e4de8d3059e4b62500d3ba97ea
child 309621 68a90b9e9293b100b177e781fb3bf83773af9f92
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
85cf2e720a84 / 45.0a1 / 20151203053521 / files
nightly linux64
85cf2e720a84 / 45.0a1 / 20151203053521 / files
nightly mac
85cf2e720a84 / 45.0a1 / 20151203053521 / files
nightly win32
85cf2e720a84 / 45.0a1 / 20151203053521 / files
nightly win64
85cf2e720a84 / 45.0a1 / 20151203053521 / 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/components/extensions/ext-tabs.js
browser/components/extensions/ext-utils.js
browser/components/nsBrowserGlue.js
browser/themes/shared/aboutNetError_alert.svg
browser/themes/shared/jar.inc.mn
configure.in
js/src/jit-test/tests/asm.js/bug1122338.js
js/src/jit-test/tests/asm.js/gating.js
js/src/jit-test/tests/sharedbuf/toolong.js
js/src/vm/SharedTypedArrayObject.cpp
js/src/vm/SharedTypedArrayObject.h
testing/marionette/command.js
testing/web-platform/meta/workers/interfaces/WorkerUtils/importScripts/002.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html.ini
toolkit/components/extensions/Extension.jsm
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -711,21 +711,16 @@
 @RESPATH@/components/nsUrlClassifierLib.js
 @RESPATH@/components/url-classifier.xpt
 
 ; Private Browsing
 @RESPATH@/components/privatebrowsing.xpt
 @RESPATH@/components/PrivateBrowsing.manifest
 @RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
 
-; GNOME hooks
-#ifdef MOZ_ENABLE_GNOME_COMPONENT
-@RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
-#endif
-
 ; Signed Packaged Content
 @RESPATH@/components/InstallPackagedWebapp.manifest
 @RESPATH@/components/InstallPackagedWebapp.js
 
 ; ANGLE on Win32
 #ifdef XP_WIN32
 #ifndef HAVE_64BIT_BUILD
 @BINPATH@/libEGL.dll
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -104,50 +104,49 @@
           'block': 'none'
         };
         node.style.display = toggle[node.style.display];
       }
 
       function showCertificateErrorReporting() {
         // Display error reporting UI
         document.getElementById('certificateErrorReporting').style.display = 'block';
+      }
+
+      function showAdvancedButton(allowOverride) {
+        // Display weak crypto advanced UI
+        document.getElementById("buttonContainer").style.display = "flex";
+        document.getElementById("advancedButton").style.display = "block";
+        document.getElementById("errorTryAgain").style.display = "none";
 
         // Get the hostname and add it to the panel
-        document.getElementById('hostname').textContent = document.location.hostname;
+        var panel = document.getElementById("weakCryptoAdvancedPanel");
+        for (var span of panel.querySelectorAll("span.hostname")) {
+          span.textContent = document.location.hostname;
+        }
+        panel.replaceChild(document.getElementById("errorLongDesc"),
+                           document.getElementById("advancedLongDesc"));
 
-        // Register click handler for the certificateErrorReportingPanel
-        document.getElementById('showCertificateErrorReportingPanel')
-                .addEventListener('click', function togglePanelVisibility() {
-          var panel = document.getElementById('certificateErrorReportingPanel');
+        // Register click handler for the weakCryptoAdvancedPanel
+        document.getElementById("advancedButton")
+                .addEventListener("click", function togglePanelVisibility() {
           toggleDisplay(panel);
 
           if (panel.style.display == "block") {
             // send event to trigger telemetry ping
             var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles:true});
             document.dispatchEvent(event);
           }
         });
-      }
 
-      function showWeakCryptoAdvanced() {
-        // Display weak crypto advanced UI
-        document.getElementById("weakCryptoAdvanced").style.display = "block";
-
-        // Get the hostname and add it to the panel
-        var panel = document.getElementById("weakCryptoAdvancedPanel");
-        for (var span of panel.querySelectorAll("span.hostname")) {
-          span.textContent = document.location.hostname;
+        if (allowOverride) {
+          document.getElementById("overrideWeakCryptoPanel").style.display = "flex";
+          var overrideLink = document.getElementById("overrideWeakCrypto");
+          overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
         }
-
-        // Register click handler for the weakCryptoAdvancedPanel
-        document.getElementById("showWeakCryptoAdvancedPanel")
-                .addEventListener("click", () => toggleDisplay(panel));
-
-        var overrideLink = document.getElementById("overrideWeakCrypto");
-        overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
       }
 
       function sendErrorReport() {
         var event = new CustomEvent("AboutNetErrorSendReport", {bubbles:true});
 
         document.dispatchEvent(event);
       }
 
@@ -181,33 +180,26 @@
         if (ld)
         {
           ld.parentNode.replaceChild(errDesc, ld);
           // change id to the replaced child's id so styling works
           errDesc.id = "errorLongDesc";
         }
 
         if (err == "sslv3Used") {
-          var learnMoreText = document.getElementById("learn_more_ssl3");
-
           document.getElementById("errorTitle").setAttribute("sslv3", "true");
-
-          var retryBtn = document.getElementById("errorTryAgain");
-          retryBtn.textContent = learnMoreText.textContent;
-          retryBtn.setAttribute("onclick", "learnMoreSSLV3()");
+          document.getElementById("errorTryAgain").style.display = "none";
+          document.getElementById("learnMoreContainer").style.display = "block";
+          var learnMoreLink = document.getElementById("learnMoreLink");
+          learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
+          document.getElementById("buttonContainer").style.display = "flex";
         }
 
         if (err == "weakCryptoUsed") {
-          var learnMoreText = document.getElementById("learn_more_weak_crypto");
-
           document.getElementById("errorTitle").setAttribute("weakCrypto", "true");
-
-          var retryBtn = document.getElementById("errorTryAgain");
-          retryBtn.textContent = learnMoreText.textContent;
-          retryBtn.setAttribute("onclick", "learnMoreWeakCrypto()");
         }
 
         // remove undisplayed errors to avoid bug 39098
         var errContainer = document.getElementById("errorContainer");
         errContainer.parentNode.removeChild(errContainer);
 
         var className = getCSSClass();
         if (className && className != "expertBadCert") {
@@ -238,48 +230,55 @@
         if (err == "cspBlocked") {
           // Remove the "Try again" button for CSP violations, since it's
           // almost certainly useless. (Bug 553180)
           document.getElementById("errorTryAgain").style.display = "none";
         }
 
         window.addEventListener("AboutNetErrorOptions", function(evt) {
         // Pinning errors are of type nssFailure2
-          if (getErrorCode() == "nssFailure2") {
+          if (getErrorCode() == "nssFailure2" || getErrorCode() == "weakCryptoUsed") {
+            document.getElementById("learnMoreContainer").style.display = "block";
             var learnMoreLink = document.getElementById("learnMoreLink");
             // nssFailure2 also gets us other non-overrideable errors. Choose
             // a "learn more" link based on description:
             if (getDescription().includes("mozilla_pkix_error_key_pinning_failure")) {
               learnMoreLink.href = "https://support.mozilla.org/kb/certificate-pinning-reports";
             }
+            if (getErrorCode() == "weakCryptoUsed") {
+              learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-weak-crypto-error-messages-firefox";
+            }
 
             var options = JSON.parse(evt.detail);
             if (options && options.enabled) {
               var checkbox = document.getElementById('automaticallyReportInFuture');
               showCertificateErrorReporting();
               if (options.automatic) {
                 // set the checkbox
                 checkbox.checked = true;
               }
 
               checkbox.addEventListener('change', function(evt) {
                   var event = new CustomEvent("AboutNetErrorSetAutomatic",
                     {bubbles:true, detail:evt.target.checked});
                   document.dispatchEvent(event);
+                  if (evt.target.checked && reportBtn.style.display != "none") {
+                    sendErrorReport();
+                  }
                 }, false);
 
               var reportBtn = document.getElementById('reportCertificateError');
               var retryBtn = document.getElementById('reportCertificateErrorRetry');
 
               reportBtn.addEventListener('click', sendErrorReport, false);
               retryBtn.addEventListener('click', sendErrorReport, false);
             }
           }
-          if (getErrorCode() == "weakCryptoUsed") {
-            showWeakCryptoAdvanced();
+          if (getErrorCode() == "weakCryptoUsed" || getErrorCode() == "sslv3Used") {
+            showAdvancedButton(getErrorCode() == "weakCryptoUsed");
           }
         }.bind(this), true, true);
 
         var event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
         document.dispatchEvent(event);
 
         if (err == "nssBadCert") {
           // Remove the "Try again" button for security exceptions, since it's
@@ -376,28 +375,16 @@
          */
         if (endsWith(thisHost, "." + okHost))
           link.href = proto + okHost;
       }
 
       function endsWith(haystack, needle) {
         return haystack.slice(-needle.length) == needle;
       }
-
-      function learnMoreSSLV3() {
-        location.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
-        // Ensure users don't re-click the button:
-        e.target.disabled = true;
-      }
-
-      function learnMoreWeakCrypto() {
-        location.href = "https://support.mozilla.org/kb/how-resolve-weak-crypto-error-messages-firefox";
-        // Ensure users don't re-click the button:
-        e.target.disabled = true;
-      }
     ]]></script>
   </head>
 
   <body dir="&locale.dir;">
 
     <!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
     <div id="errorContainer">
       <div id="errorTitlesContainer">
@@ -453,19 +440,17 @@
         <div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
         <div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
         <div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div>
         <div id="ed_forbiddenBlocked">&forbiddenBlocked.longDesc;</div>
         <div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
         <div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
         <div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
         <div id="ed_sslv3Used">&sslv3Used.longDesc;</div>
-        <div id="learn_more_ssl3">&sslv3Used.learnMore;</div>
         <div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc;</div>
-        <div id="learn_more_weak_crypto">&weakCryptoUsed.learnMore;</div>
       </div>
     </div>
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
 
       <!-- Error Title -->
       <div id="errorTitle">
@@ -485,19 +470,27 @@
 
         <!-- Override section - For ssl errors only.  Removed on init for other
              error types.  -->
         <div id="securityOverrideDiv">
           <a id="securityOverrideLink" href="javascript:showSecuritySection();" >&securityOverride.linkText;</a>
           <div id="securityOverrideContent" style="display: none;">&securityOverride.warningContent;</div>
         </div>
 
+        <div id="learnMoreContainer">
+          <p><a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
+        </div>
+
+        <div id="buttonContainer">
+          <button id="returnButton" autocomplete="off" autofocus="true">&returnToPreviousPage.label;</button>
+          <div id="buttonSpacer"></div>
+          <button id="advancedButton" autocomplete="off" autofocus="true">&advanced.label;</button>
+        </div>
       </div>
 
-      <!-- Retry Button -->
       <button id="errorTryAgain" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
       <script>
         // Only do autofocus if we're the toplevel frame; otherwise we
         // don't want to call attention to ourselves!  The key part is
         // that autofocus happens on insertion into the tree, so we
         // can remove the button, add @autofocus, and reinsert the
         // button.
         if (window.top == window) {
@@ -508,48 +501,34 @@
             button.setAttribute("autofocus", "true");
             parent.insertBefore(button, nextSibling);
         }
       </script>
 
       <!-- UI for option to report certificate errors to Mozilla. Removed on
            init for other error types .-->
       <div id="certificateErrorReporting">
-        <a id="showCertificateErrorReportingPanel" href="#">&errorReporting.title;<span class="downArrow"> ▼</span></a>
-      </div>
+        <p>
+          <input type="checkbox" id="automaticallyReportInFuture" />
+          <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
 
-      <div id="certificateErrorReportingPanel">
-        <div id="certificateErrorReportingDescription">
-          <p>&errorReporting.longDesc;</p>
-          <p>
-            <input type="checkbox" id="automaticallyReportInFuture" />
-            <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
-          </p>
-        </div>
-        <div id="errorStatePanel">
-          <a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a>
           <span id="reportingState">
             <button id="reportCertificateError">&errorReporting.report;</button>
             <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
             <span id="reportSendingMessage">&errorReporting.sending;</span>
             <span id="reportSentMessage">&errorReporting.sent;</span>
           </span>
-        </div>
-      </div>
-
-      <!-- UI for option to override weak crypto errors. Removed on
-           init for other error types .-->
-      <div id="weakCryptoAdvanced">
-        <a id="showWeakCryptoAdvancedPanel" href="#">&weakCryptoAdvanced.title;<span class="downArrow"> &#x25bc;</span></a>
+        </p>
       </div>
 
       <div id="weakCryptoAdvancedPanel">
         <div id="weakCryptoAdvancedDescription">
           <p>&weakCryptoAdvanced.longDesc;</p>
         </div>
+        <div id="advancedLongDesc" />
         <div id="overrideWeakCryptoPanel">
           <a id="overrideWeakCrypto" href="#">&weakCryptoAdvanced.override;</a>
         </div>
       </div>
 
     </div>
 
     <!--
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2658,27 +2658,29 @@ var BrowserOnClick = {
     let mm = window.messageManager;
     mm.addMessageListener("Browser:CertExceptionError", this);
     mm.addMessageListener("Browser:SiteBlockedError", this);
     mm.addMessageListener("Browser:EnableOnlineMode", this);
     mm.addMessageListener("Browser:SendSSLErrorReport", this);
     mm.addMessageListener("Browser:SetSSLErrorReportAuto", this);
     mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
     mm.addMessageListener("Browser:OverrideWeakCrypto", this);
+    mm.addMessageListener("Browser:SSLErrorGoBack", this);
   },
 
   uninit: function () {
     let mm = window.messageManager;
     mm.removeMessageListener("Browser:CertExceptionError", this);
     mm.removeMessageListener("Browser:SiteBlockedError", this);
     mm.removeMessageListener("Browser:EnableOnlineMode", this);
     mm.removeMessageListener("Browser:SendSSLErrorReport", this);
     mm.removeMessageListener("Browser:SetSSLErrorReportAuto", this);
     mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
     mm.removeMessageListener("Browser:OverrideWeakCrypto", this);
+    mm.removeMessageListener("Browser:SSLErrorGoBack", this);
   },
 
   handleEvent: function (event) {
     if (!event.isTrusted || // Don't trust synthetic events
         event.button == 2) {
       return;
     }
 
@@ -2733,16 +2735,19 @@ var BrowserOnClick = {
       break;
       case "Browser:OverrideWeakCrypto":
         let weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
                                    .getService(Ci.nsIWeakCryptoOverride);
         weakCryptoOverride.addWeakCryptoOverride(
           msg.data.location.hostname,
           PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser));
       break;
+      case "Browser:SSLErrorGoBack":
+        goBackFromErrorPage();
+      break;
     }
   },
 
   onSSLErrorReport: function(browser, elementId, documentURI, location, securityInfo) {
     function showReportStatus(reportStatus) {
       gBrowser.selectedBrowser
           .messageManager
           .sendAsyncMessage("Browser:SSLErrorReportStatus",
@@ -5457,17 +5462,17 @@ function handleLinkClick(event, href, li
 
   // first get document wide referrer policy, then
   // get referrer attribute from clicked link and parse it and
   // allow per element referrer to overrule the document wide referrer if enabled
   let referrerPolicy = doc.referrerPolicy;
   if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
       linkNode) {
     let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
-                            getAttribute("referrer"));
+                            getAttribute("referrerpolicy"));
     if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
       referrerPolicy = referrerAttrValue;
     }
   }
 
   urlSecurityCheck(href, doc.nodePrincipal);
   let params = { charset: doc.characterSet,
                  allowMixedContent: persistAllowMixedContentInChildTab,
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -109,17 +109,17 @@ var handleContentContextMenu = function 
                                           .outerWindowID;
   let loginFillInfo = LoginManagerContent.getFieldContext(event.target);
 
   // get referrer attribute from clicked link and parse it
   // if per element referrer is enabled, the element referrer overrules
   // the document wide referrer
   if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
     let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
-                            getAttribute("referrer"));
+                            getAttribute("referrerpolicy"));
     if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
       referrerPolicy = referrerAttrValue;
     }
   }
 
   let disableSetDesktopBg = null;
   // Media related cache info parent needs for saving
   let contentType = null;
@@ -384,17 +384,17 @@ var ClickEventHandler = {
 
     // get referrer attribute from clicked link and parse it
     // if per element referrer is enabled, the element referrer overrules
     // the document wide referrer
     let referrerPolicy = ownerDoc.referrerPolicy;
     if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
         node) {
       let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
-                              getAttribute("referrer"));
+                              getAttribute("referrerpolicy"));
       if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
         referrerPolicy = referrerAttrValue;
       }
     }
 
     let json = { button: event.button, shiftKey: event.shiftKey,
                  ctrlKey: event.ctrlKey, metaKey: event.metaKey,
                  altKey: event.altKey, href: null, title: null,
@@ -468,16 +468,20 @@ var ClickEventHandler = {
       reason: reason,
       elementId: targetElement.getAttribute("id"),
       isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView)
     });
   },
 
   onAboutNetError: function (event, documentURI) {
     let elmId = event.originalTarget.getAttribute("id");
+    if (elmId == "returnButton") {
+      sendAsyncMessage("Browser:SSLErrorGoBack", {});
+      return;
+    }
     if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
       return;
     }
     // browser front end will handle clearing offline mode and refreshing
     // the page *if* we're in offline mode now. Otherwise let the error page
     // handle the click.
     if (Services.io.offline) {
       event.preventDefault();
--- a/browser/base/content/test/referrer/browser.ini
+++ b/browser/base/content/test/referrer/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   file_referrer_policyserver.sjs
+  file_referrer_policyserver_attr.sjs
   file_referrer_testserver.sjs
   head.js
 
 [browser_referrer_middle_click.js]
 [browser_referrer_open_link_in_private.js]
 skip-if = os == 'linux' # Bug 1145199
 [browser_referrer_open_link_in_tab.js]
 skip-if = os == 'linux' # Bug 1144816
copy from browser/base/content/test/referrer/file_referrer_policyserver.sjs
copy to browser/base/content/test/referrer/file_referrer_policyserver_attr.sjs
--- a/browser/base/content/test/referrer/file_referrer_policyserver.sjs
+++ b/browser/base/content/test/referrer/file_referrer_policyserver_attr.sjs
@@ -10,28 +10,27 @@ function handleRequest(request, response
 
   let scheme = query.get("scheme");
   let policy = query.get("policy");
   let rel = query.get("rel");
 
   let linkUrl = scheme +
                 "test1.example.com/browser/browser/base/content/test/referrer/" +
                 "file_referrer_testserver.sjs";
-  let metaReferrerTag =
-      policy ? `<meta name='referrer' content='${policy}'>` : "";
+  let referrerPolicy =
+      policy ? `referrerpolicy="${policy}"` : "";
 
   let html = `<!DOCTYPE HTML>
               <html>
               <head>
               <meta charset='utf-8'>
-              ${metaReferrerTag}
               <title>Test referrer</title>
               </head>
               <body>
-              <a id='testlink' href='${linkUrl}' ${rel ? ` rel='${rel}'` : ""}>
+              <a id='testlink' href='${linkUrl}' ${referrerPolicy} ${rel ? ` rel='${rel}'` : ""}>
               referrer test link</a>
               </body>
               </html>`;
 
   response.setHeader("Cache-Control", "no-cache", false);
   response.setHeader("Content-Type", "text/html", false);
   response.write(html);
 }
--- a/browser/base/content/test/referrer/head.js
+++ b/browser/base/content/test/referrer/head.js
@@ -5,18 +5,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserTestUtils",
   "resource://testing-common/BrowserTestUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ContentTask",
   "resource://testing-common/ContentTask.jsm");
 
 const REFERRER_URL_BASE = "/browser/browser/base/content/test/referrer/";
 const REFERRER_POLICYSERVER_URL =
   "test1.example.com" + REFERRER_URL_BASE + "file_referrer_policyserver.sjs";
+const REFERRER_POLICYSERVER_URL_ATTRIBUTE =
+  "test1.example.com" + REFERRER_URL_BASE + "file_referrer_policyserver_attr.sjs";
+
+SpecialPowers.pushPrefEnv({"set": [['network.http.enablePerElementReferrer', true]]});
 
 var gTestWindow = null;
+var rounds = 0;
 
 // We test that the UI code propagates three pieces of state - the referrer URI
 // itself, the referrer policy, and the triggering principal. After that, we
 // trust nsIWebNavigation to do the right thing with the info it's given, which
 // is covered more exhaustively by dom/base/test/test_bug704320.html (which is
 // a faster content-only test). So, here, we limit ourselves to cases that
 // would break when the UI code drops either of these pieces; we don't try to
 // duplicate the entire cross-product test in bug 704320 - that would be slow,
@@ -44,30 +49,31 @@ var _referrerTests = [
   },
   {
     fromScheme: "https://",
     toScheme: "http://",
     policy: "origin",
     rel: "noreferrer",
     result: ""  // rel=noreferrer trumps meta-referrer
   },
-  // 3. Origin-when-cross-origin policy - this depends on the triggering
+  // 3. XXX: using no-referrer here until we support all attribute values (bug 1178337)
+  //    Origin-when-cross-origin policy - this depends on the triggering
   //    principal.  We expect full referrer for same-origin requests,
   //    and origin referrer for cross-origin requests.
   {
     fromScheme: "https://",
     toScheme: "https://",
-    policy: "origin-when-cross-origin",
-    result: "https://test1.example.com/browser"  // same origin
+    policy: "no-referrer",
+    result: ""  // same origin https://test1.example.com/browser
   },
   {
     fromScheme: "http://",
     toScheme: "https://",
-    policy: "origin-when-cross-origin",
-    result: "http://test1.example.com"  // cross origin
+    policy: "no-referrer",
+    result: ""  // cross origin http://test1.example.com
   },
 ];
 
 /**
  * Returns the test object for a given test number.
  * @param aTestNumber The test number - 0, 1, 2, ...
  * @return The test object, or undefined if the number is out of range.
  */
@@ -186,17 +192,19 @@ function doContextMenuCommand(aWindow, a
 /**
  * Loads a single test case, i.e., a source url into gTestWindow.
  * @param aTestNumber The test case number - 0, 1, 2...
  * @return {Promise}
  * @resolves When the source url for this test case is loaded.
  */
 function referrerTestCaseLoaded(aTestNumber) {
   let test = getReferrerTest(aTestNumber);
-  let url = test.fromScheme + REFERRER_POLICYSERVER_URL +
+  let server = rounds == 0 ? REFERRER_POLICYSERVER_URL :
+                             REFERRER_POLICYSERVER_URL_ATTRIBUTE;
+  let url = test.fromScheme + server +
             "?scheme=" + escape(test.toScheme) +
             "&policy=" + escape(test.policy || "") +
             "&rel=" + escape(test.rel || "");
   var browser = gTestWindow.gBrowser;
   browser.selectedTab = browser.addTab(url);
   return BrowserTestUtils.browserLoaded(browser.selectedBrowser);
 }
 
@@ -222,16 +230,22 @@ function checkReferrerAndStartNextTest(a
     gTestWindow.gBrowser.removeTab(gTestWindow.gBrowser.tabs[1]);
 
     // Move on to the next test.  Or finish if we're done.
     var nextTestNumber = aTestNumber + 1;
     if (getReferrerTest(nextTestNumber)) {
       referrerTestCaseLoaded(nextTestNumber).then(function() {
         aStartTestCase(nextTestNumber);
       });
+    } else if (rounds == 0) {
+      nextTestNumber = 0;
+      rounds = 1;
+      referrerTestCaseLoaded(nextTestNumber).then(function() {
+        aStartTestCase(nextTestNumber);
+      });
     } else {
       finish();
     }
   });
 }
 
 /**
  * Fires up the complete referrer test.
--- a/browser/branding/aurora/branding.nsi
+++ b/browser/branding/aurora/branding.nsi
@@ -15,17 +15,17 @@
 !define HelpLink              "https://support.mozilla.org"
 
 !define URLStubDownload "http://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-aurora-latest"
 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=aurora&installer_lang=${AB_CD}"
 !define Channel "aurora"
 
 # The installer's certificate name and issuer expected by the stub installer
 !define CertNameDownload   "Mozilla Corporation"
-!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
+!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
 
 # Dialog units are used so the UI displays correctly with the system's DPI
 # settings.
 # The dialog units for the bitmap's dimensions should match exactly with the
 # bitmap's width and height in pixels.
 !define APPNAME_BMP_WIDTH_DU 108u
 !define APPNAME_BMP_HEIGHT_DU 48u
 !define INTRO_BLURB_WIDTH_DU "232u"
--- a/browser/branding/branding-common.mozbuild
+++ b/browser/branding/branding-common.mozbuild
@@ -1,16 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 JS_PREFERENCE_FILES += [
-    'pref/firefox-branding.js',
+    '/%s/pref/firefox-branding.js' % CONFIG['MOZ_BRANDING_DIRECTORY'],
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     BRANDING_FILES += [
         'appname.bmp',
         'bgintro.bmp',
         'branding.nsi',
         'clock.bmp',
--- a/browser/branding/nightly/branding.nsi
+++ b/browser/branding/nightly/branding.nsi
@@ -14,17 +14,17 @@
 !define HelpLink              "https://support.mozilla.org"
 
 !define URLStubDownload "http://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-nightly-latest"
 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=nightly&installer_lang=${AB_CD}"
 !define Channel "nightly"
 
 # The installer's certificate name and issuer expected by the stub installer
 !define CertNameDownload   "Mozilla Corporation"
-!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
+!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
 
 # Dialog units are used so the UI displays correctly with the system's DPI
 # settings.
 # The dialog units for the bitmap's dimensions should match exactly with the
 # bitmap's width and height in pixels.
 !define APPNAME_BMP_WIDTH_DU 159u
 !define APPNAME_BMP_HEIGHT_DU 28u
 !define INTRO_BLURB_WIDTH_DU "230u"
--- a/browser/branding/official/branding.nsi
+++ b/browser/branding/official/branding.nsi
@@ -19,17 +19,17 @@
 ; set the update channel to beta.
 !define OFFICIAL
 !define URLStubDownload "http://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-latest"
 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=release&installer_lang=${AB_CD}"
 !define Channel "release"
 
 # The installer's certificate name and issuer expected by the stub installer
 !define CertNameDownload   "Mozilla Corporation"
-!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
+!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
 
 # Dialog units are used so the UI displays correctly with the system's DPI
 # settings.
 # The dialog units for the bitmap's dimensions should match exactly with the
 # bitmap's width and height in pixels.
 !define APPNAME_BMP_WIDTH_DU "134u"
 !define APPNAME_BMP_HEIGHT_DU "36u"
 !define INTRO_BLURB_WIDTH_DU "258u"
--- a/browser/branding/unofficial/branding.nsi
+++ b/browser/branding/unofficial/branding.nsi
@@ -14,17 +14,17 @@
 !define HelpLink              "https://support.mozilla.org"
 
 !define URLStubDownload "http://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-latest"
 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=release&installer_lang=${AB_CD}"
 !define Channel "unofficial"
 
 # The installer's certificate name and issuer expected by the stub installer
 !define CertNameDownload   "Mozilla Corporation"
-!define CertIssuerDownload "Thawte Code Signing CA - G2"
+!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
 
 # Dialog units are used so the UI displays correctly with the system's DPI
 # settings.
 # The dialog units for the bitmap's dimensions should match exactly with the
 # bitmap's width and height in pixels.
 !define APPNAME_BMP_WIDTH_DU 159u
 !define APPNAME_BMP_HEIGHT_DU 50u
 !define INTRO_BLURB_WIDTH_DU "230u"
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -19,20 +19,16 @@ DEFINES += -DMOZ_MULET
 endif
 
 DEFINES += -DMOZ_APP_NAME=$(MOZ_APP_NAME) -DPREF_DIR=$(PREF_DIR)
 
 ifdef MOZ_DEBUG
 DEFINES += -DMOZ_DEBUG=1
 endif
 
-ifdef MOZ_ENABLE_GNOME_COMPONENT
-DEFINES += -DMOZ_ENABLE_GNOME_COMPONENT=1
-endif
-
 ifdef MOZ_WIDGET_GTK
 DEFINES += -DMOZ_GTK=1
 ifdef MOZ_ENABLE_GTK3
 DEFINES += -DMOZ_GTK3=1
 endif
 endif
 
 ifdef MOZ_NATIVE_NSPR
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -490,22 +490,16 @@
 @RESPATH@/browser/components/360seProfileMigrator.js
 @RESPATH@/browser/components/EdgeProfileMigrator.js
 @RESPATH@/browser/components/IEProfileMigrator.js
 @RESPATH@/browser/components/SafariProfileMigrator.js
 #endif
 #ifdef XP_MACOSX
 @RESPATH@/browser/components/SafariProfileMigrator.js
 #endif
-#ifdef MOZ_ENABLE_GNOME_COMPONENT
-@RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
-#endif
-#if defined(MOZ_ENABLE_DBUS) || defined(MOZ_ENABLE_GNOME_COMPONENT)
-@RESPATH@/components/components.manifest
-#endif
 @RESPATH@/components/nsINIProcessor.manifest
 @RESPATH@/components/nsINIProcessor.js
 @RESPATH@/components/nsPrompter.manifest
 @RESPATH@/components/nsPrompter.js
 #ifdef MOZ_DATA_REPORTING
 @RESPATH@/components/DataReporting.manifest
 @RESPATH@/components/DataReportingService.js
 #endif
--- a/browser/installer/windows/nsis/defines.nsi.in
+++ b/browser/installer/windows/nsis/defines.nsi.in
@@ -32,17 +32,17 @@
 !define AppRegName            "Firefox"
 
 !ifndef DEV_EDITION
 !define BrandShortName        "@MOZ_APP_DISPLAYNAME@"
 !endif
 !define BrandFullName         "${BrandFullNameInternal}"
 
 !define CERTIFICATE_NAME      "Mozilla Corporation"
-!define CERTIFICATE_ISSUER    "DigiCert Assured ID Code Signing CA-1"
+!define CERTIFICATE_ISSUER    "DigiCert SHA2 Assured ID Code Signing CA"
 
 # LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP
 # category value is ANDed together to set multiple permitted categories.
 # See http://msdn.microsoft.com/en-us/library/ms742253%28VS.85%29.aspx
 # The value below removes all LSP categories previously set.
 !define LSP_CATEGORIES "0x00000000"
 
 !if "@MOZ_UPDATE_CHANNEL@" == ""
--- a/browser/installer/windows/nsis/maintenanceservice_installer.nsi
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -215,17 +215,17 @@ Section "MaintenanceService"
   WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
   WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1
   DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled"
 
   ; Included here for debug purposes only.  
   ; These keys are used to bypass the installation dir is a valid installation
   ; check from the service so that tests can be run.
   ; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
-  ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert Assured ID Code Signing CA-1"
+  ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert SHA2 Assured ID Code Signing CA"
   ${If} ${RunningX64}
     SetRegView lastused
   ${EndIf}
 SectionEnd
 
 ; By renaming before deleting we improve things slightly in case
 ; there is a file in use error. In this case a new install can happen.
 Function un.RenameDelete
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -2,16 +2,18 @@
    - 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/. -->
 
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
 %brandDTD;
 
 <!ENTITY loadError.label "Problem loading page">
 <!ENTITY retry.label "Try Again">
+<!ENTITY returnToPreviousPage.label "Go Back">
+<!ENTITY advanced.label "Advanced">
 
 <!-- Specific error messages -->
 
 <!ENTITY connectionFailure.title "Unable to connect">
 <!ENTITY connectionFailure.longDesc "&sharedLongDesc;">
 
 <!ENTITY deniedPortAccess.title "This address is restricted">
 <!ENTITY deniedPortAccess.longDesc "">
@@ -197,34 +199,30 @@ functionality specific to firefox. -->
 
 <!ENTITY securityOverride.warningContent "
 <p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
 
 <button id='getMeOutOfHereButton'>&securityOverride.getMeOutOfHereButton;</button>
 <button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
 ">
 
-<!ENTITY errorReporting.title "Report this error">
-<!ENTITY errorReporting.longDesc "Reporting the address and certificate information for <span id='hostname'></span> will help us identify and block malicious sites. Thanks for helping create a safer web!">
-<!ENTITY errorReporting.automatic "Automatically report errors in the future">
+<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
 <!ENTITY errorReporting.learnMore "Learn more…">
 <!ENTITY errorReporting.sending "Sending report">
 <!ENTITY errorReporting.sent "Report sent">
 <!ENTITY errorReporting.report "Report">
 <!ENTITY errorReporting.tryAgain "Try again">
 
 <!ENTITY remoteXUL.title "Remote XUL">
 <!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
 
 <!ENTITY sslv3Used.title "Unable to Connect Securely">
 <!-- LOCALIZATION NOTE (sslv3Used.longDesc) - Do not translate
      "ssl_error_unsupported_version". -->
 <!ENTITY sslv3Used.longDesc "Advanced info: ssl_error_unsupported_version">
-<!ENTITY sslv3Used.learnMore "Learn More…">
 
 <!ENTITY weakCryptoUsed.title "Your connection is not secure">
 <!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc) - Do not translate
      "ssl_error_no_cypher_overlap". -->
 <!ENTITY weakCryptoUsed.longDesc "Advanced info: ssl_error_no_cypher_overlap">
-<!ENTITY weakCryptoUsed.learnMore "Learn More…">
 <!ENTITY weakCryptoAdvanced.title "Advanced">
 <!ENTITY weakCryptoAdvanced.longDesc "<span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe.">
 <!ENTITY weakCryptoAdvanced.override "(Not secure) Try loading <span class='hostname'></span> using outdated security">
--- a/browser/locales/en-US/searchplugins/list.txt
+++ b/browser/locales/en-US/searchplugins/list.txt
@@ -1,7 +1,8 @@
 amazondotcom
 bing
 eBay
 google
 twitter
 wikipedia
 yahoo
+yahoo-en-CA:hidden
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/searchplugins/yahoo-en-CA.xml
@@ -0,0 +1,30 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Yahoo Canada</ShortName>
+<Description>Yahoo Canada Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAEACAA8DQAAJgAAACAgAAABAAgAowsAAGINAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAAJcEhZcwAACxMAAAsTAQCanBgAAApPaUNDUFBob3Rvc2hvcCBJQ0MgcHJvZmlsZQAAeNqdU2dUU+kWPffe9EJLiICUS29SFQggUkKLgBSRJiohCRBKiCGh2RVRwRFFRQQbyKCIA46OgIwVUSwMigrYB+Qhoo6Do4iKyvvhe6Nr1rz35s3+tdc+56zznbPPB8AIDJZIM1E1gAypQh4R4IPHxMbh5C5AgQokcAAQCLNkIXP9IwEA+H48PCsiwAe+AAF40wsIAMBNm8AwHIf/D+pCmVwBgIQBwHSROEsIgBQAQHqOQqYAQEYBgJ2YJlMAoAQAYMtjYuMAUC0AYCd/5tMAgJ34mXsBAFuUIRUBoJEAIBNliEQAaDsArM9WikUAWDAAFGZLxDkA2C0AMElXZkgAsLcAwM4QC7IACAwAMFGIhSkABHsAYMgjI3gAhJkAFEbyVzzxK64Q5yoAAHiZsjy5JDlFgVsILXEHV1cuHijOSRcrFDZhAmGaQC7CeZkZMoE0D+DzzAAAoJEVEeCD8/14zg6uzs42jrYOXy3qvwb/ImJi4/7lz6twQAAA4XR+0f4sL7MagDsGgG3+oiXuBGheC6B194tmsg9AtQCg6dpX83D4fjw8RaGQudnZ5eTk2ErEQlthyld9/mfCX8BX/Wz5fjz89/XgvuIkgTJdgUcE+ODCzPRMpRzPkgmEYtzmj0f8twv//B3TIsRJYrlYKhTjURJxjkSajPMypSKJQpIpxSXS/2Ti3yz7Az7fNQCwaj4Be5EtqF1jA/ZLJxBYdMDi9wAA8rtvwdQoCAOAaIPhz3f/7z/9R6AlAIBmSZJxAABeRCQuVMqzP8cIAABEoIEqsEEb9MEYLMAGHMEF3MEL/GA2hEIkxMJCEEIKZIAccmAprIJCKIbNsB0qYC/UQB00wFFohpNwDi7CVbgOPXAP+mEInsEovIEJBEHICBNhIdqIAWKKWCOOCBeZhfghwUgEEoskIMmIFFEiS5E1SDFSilQgVUgd8j1yAjmHXEa6kTvIADKC/Ia8RzGUgbJRPdQMtUO5qDcahEaiC9BkdDGajxagm9BytBo9jDah59CraA/ajz5DxzDA6BgHM8RsMC7Gw0KxOCwJk2PLsSKsDKvGGrBWrAO7ifVjz7F3BBKBRcAJNgR3QiBhHkFIWExYTthIqCAcJDQR2gk3CQOEUcInIpOoS7QmuhH5xBhiMjGHWEgsI9YSjxMvEHuIQ8Q3JBKJQzInuZACSbGkVNIS0kbSblIj6SypmzRIGiOTydpka7IHOZQsICvIheSd5MPkM+Qb5CHyWwqdYkBxpPhT4ihSympKGeUQ5TTlBmWYMkFVo5pS3aihVBE1j1pCraG2Uq9Rh6gTNHWaOc2DFklLpa2ildMaaBdo92mv6HS6Ed2VHk6X0FfSy+lH6JfoA/R3DA2GFYPHiGcoGZsYBxhnGXcYr5hMphnTixnHVDA3MeuY55kPmW9VWCq2KnwVkcoKlUqVJpUbKi9Uqaqmqt6qC1XzVctUj6leU32uRlUzU+OpCdSWq1WqnVDrUxtTZ6k7qIeqZ6hvVD+kfln9iQZZw0zDT0OkUaCxX+O8xiALYxmzeCwhaw2rhnWBNcQmsc3ZfHYqu5j9HbuLPaqpoTlDM0ozV7NS85RmPwfjmHH4nHROCecop5fzforeFO8p4ikbpjRMuTFlXGuqlpeWWKtIq1GrR+u9Nq7tp52mvUW7WfuBDkHHSidcJ0dnj84FnedT2VPdpwqnFk09OvWuLqprpRuhu0R3v26n7pievl6Ankxvp955vef6HH0v/VT9bfqn9UcMWAazDCQG2wzOGDzFNXFvPB0vx9vxUUNdw0BDpWGVYZfhhJG50Tyj1UaNRg+MacZc4yTjbcZtxqMmBiYhJktN6k3umlJNuaYppjtMO0zHzczNos3WmTWbPTHXMueb55vXm9+3YFp4Wiy2qLa4ZUmy5FqmWe62vG6FWjlZpVhVWl2zRq2drSXWu627pxGnuU6TTque1mfDsPG2ybaptxmw5dgG2662bbZ9YWdiF2e3xa7D7pO9k326fY39PQcNh9kOqx1aHX5ztHIUOlY63prOnO4/fcX0lukvZ1jPEM/YM+O2E8spxGmdU5vTR2cXZ7lzg/OIi4lLgssulz4umxvG3ci95Ep09XFd4XrS9Z2bs5vC7ajbr+427mnuh9yfzDSfKZ5ZM3PQw8hD4FHl0T8Ln5Uwa9+sfk9DT4FntecjL2MvkVet17C3pXeq92HvFz72PnKf4z7jPDfeMt5ZX8w3wLfIt8tPw2+eX4XfQ38j/2T/ev/RAKeAJQFnA4mBQYFbAvv4enwhv44/Ottl9rLZ7UGMoLlBFUGPgq2C5cGtIWjI7JCtIffnmM6RzmkOhVB+6NbQB2HmYYvDfgwnhYeFV4Y/jnCIWBrRMZc1d9HcQ3PfRPpElkTem2cxTzmvLUo1Kj6qLmo82je6NLo/xi5mWczVWJ1YSWxLHDkuKq42bmy+3/zt84fineIL43sXmC/IXXB5oc7C9IWnFqkuEiw6lkBMiE44lPBBECqoFowl8hN3JY4KecIdwmciL9E20YjYQ1wqHk7ySCpNepLskbw1eSTFM6Us5bmEJ6mQvEwNTN2bOp4WmnYgbTI9Or0xg5KRkHFCqiFNk7Zn6mfmZnbLrGWFsv7Fbou3Lx6VB8lrs5CsBVktCrZCpuhUWijXKgeyZ2VXZr/Nico5lqueK83tzLPK25A3nO+f/+0SwhLhkralhktXLR1Y5r2sajmyPHF52wrjFQUrhlYGrDy4irYqbdVPq+1Xl65+vSZ6TWuBXsHKgsG1AWvrC1UK5YV969zX7V1PWC9Z37Vh+oadGz4ViYquFNsXlxV/2CjceOUbh2/Kv5nclLSpq8S5ZM9m0mbp5t4tnlsOlqqX5pcObg3Z2rQN31a07fX2Rdsvl80o27uDtkO5o788uLxlp8nOzTs/VKRU9FT6VDbu0t21Ydf4btHuG3u89jTs1dtbvPf9Psm+21UBVU3VZtVl+0n7s/c/romq6fiW+21drU5tce3HA9ID/QcjDrbXudTVHdI9VFKP1ivrRw7HH77+ne93LQ02DVWNnMbiI3BEeeTp9wnf9x4NOtp2jHus4QfTH3YdZx0vakKa8ppGm1Oa+1tiW7pPzD7R1ureevxH2x8PnDQ8WXlK81TJadrpgtOTZ/LPjJ2VnX1+LvncYNuitnvnY87fag9v77oQdOHSRf+L5zu8O85c8rh08rLb5RNXuFearzpfbep06jz+k9NPx7ucu5quuVxrue56vbV7ZvfpG543zt30vXnxFv/W1Z45Pd2983pv98X39d8W3X5yJ/3Oy7vZdyfurbxPvF/0QO1B2UPdh9U/W/7c2O/cf2rAd6Dz0dxH9waFg8/+kfWPD0MFj5mPy4YNhuueOD45OeI/cv3p/KdDz2TPJp4X/qL+y64XFi9++NXr187RmNGhl/KXk79tfKX96sDrGa/bxsLGHr7JeDMxXvRW++3Bd9x3He+j3w9P5Hwgfyj/aPmx9VPQp/uTGZOT/wQDmPP8YzMt2wAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACZ0lEQVR42mzSP4icZRTF4ee+38xOkp2sG5cQxVJIIaaKkICxTkqJjQhpJFYiop2F1YKFQqoUVpEoCBYSS7dfOxVFWGIsokUE/0TEye7OzPe977XYNWk83b0cDoffvXHWGxkKYjt0N1fi+FaJIzNIFSJ0kDXn0z5nF1O9Sp5PzaizamLD2NELo5W4sOwXqqX/04o1R2wg9PYs/GXUmTjqpGNxwvWdFzz19Akvjj+XUkYTggylFLfml93due+tZ7+y577BrkJnbNWke8yHmzvgi/4lq+WU1XjCsThl2p1ya3GZ4KNrt03KuhXH0SkkkbTOL5+u2PnuZ/D8axtGMTaKsbOvrINP3v/W3Y9XhCJjQCrUWRedVpaq3nvn7oHXrz8jD8PfvnEGbL0716LXytIoxqizkups4R/VwhB7hpi7sXkbXNo86bkrazK5sXnbEHND7BvMLcykOotz3vlxvZw+faRb08VEiVC64rPdSw/pZ/Ly9EutNi3TkHOLOvN3u3OnHNx7MFio5qq5Ifdce/WHhwEfXPnekPuq/UPPQhrAKOV0MFdyRFQFRefr7Z9wRrb0zfYd1aCpGmr2BvtSTkcp1wZLnX0tx4oQjeHX+UF97P75QGspM7VMqTfopVwb0aY1F4ZWlFK1SCVDHQKUEvphj0ztkEdrvZoLtOkoNS2XlkHJIlroIky7Jw8atDSJdQ/aPTUdtJBaLqVmlJpqQataCZKhY/L4HwcEI/Qbv1v8tivbIdVG1UtNnPVmFmPEoT9l/Dc9Ujp42Mx4uGl6I5pmgdjGzaLbopsdJqZHWZnqtKkXcZU8D/8OAPAMQ4kD8KK1AAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAByVJREFUWAm1l1uIldcVx9d3ruMZZzRaay+pCjFJH6LSRqxQqA1NH0pBiH3Qp774kEAg4EOkxKdQSCjUFvpm6YsNVNoSaGjFtmga2yZgCIIawdv04g2kM7Uz6lzO+c758v/t/9lzTB/61Oxhn7332muv9V+3vb8pnooDVRkzZ4oY/LmK6mQZa05frX6yFJ9Ae7x4qd2IuV1FFM9WMfhaI9Z+pQBAL+aiEZ0QgNBm2YuZmxHF9VZMXqmivFaLweUyuteWYvHGVPWr2f+F7YvF/ola9DZGVJsHUXs8YvBEK1ZrXt9URDwqxY1BdGMQvWjGqkgA+iLUtazHuADUoowHYugKTilaR7SIpZjWqOMRfY090RbasS4JglpFtzWIcqwZa+pSqnWVcLLXijXpZCFpvbgb/VhMe8huMLPylWkci8/oSD8xJq7hj4WUWvXrlbqVrUyKtBYdpX3Bh9YbzsdErwRgbZKyFP+KdqxPssu4l2hDAOOxIj6bCHigKWRNCcpMCHHHB4TJLc+TXxKHnC51Ct+Qgxl/TZ0qE5Be/EdWTwjqQuJJAPIB8qAZk4kZoXJnvHH+27Hq0+0YX12PH+w7E3/8zbWkitN2M8pS7kCKZ761OV55c2fcm+nG7J1e7N/+e3m2nbyKQcAhnHWZLC86B1rxiFRvSIkIgJHFVWzZ+qk4fG5HEr4wV8buVb+Vuv5QeVZsi/HeW//eHZ1HbNfLT5+Jc2dndBav9KXugfqc+pLsv6Xxvk6kVheumnpDnXlTVMZWfHh+Li6cdOKvmGzEC69+WTskzwr1SfUJ9ZWp7z/0pWXlF9+ejQtnUdCWnAxQ+al5Tdz80lIVEP8x9eZQWCQwOTAhNc34Re+rUW8U0S+r2Ns8nWzBKgONBOeX3V3RaCpPRN7XeFcO7yYl+InML2U3VdBVHszHzbSXYLBJkuTSQzBuphoYZ7X/u8O30gFAHHxzi+Yop8ETcfDXW5JyKMd/fFuO9l3mYuwLAl5gbMg8QuKdYQg4Zjcxo7HikMeIn37vcizes9Ide9bGhs9NLPN9YX0ndnzHpbZ4vx9HXr6kc6Sobo2hIkuzOnIh0xMFRlvc0waWL+p3UePCQ/Myjjx/JSnl59CJbUkJgl75g+ZD/D978Yrc7EuMPe4ESo6OYsaasiiX7tADAyny5cGtyMHsDxzFnP0Tx6Z0SfsW27B1PHZ+c13seGZdbNo2Lo6Iu7e7cfznfxc/8ggNQBhZI9dSs2c5k+rFaHBXmZhd32xTGdlZPvzDvefj9XddlgeObYVpuf1o3zkpyrEnCJwBDjlmr9i7XP3jgrYkDamhEqRA8UOBxZ53tcOtBbgyzr53M65f8DU6sVZ1o067cfFBvP+XGzrDOa5s+JkTShIc+dBtlLOLlRpqAUDc+yqQMnViNq81edDVnPixno/vP/dXjn2svbbnPa1RiqXEHVkYQ06RWygnFEtpbZDLAJws2X1OHgfCv+hiRkZU8Y+pmbjwzjTE1D48PR1TV+5IMErgsjex2A8TJrqCHH9Cw6U0BGBkPUWrKTZnPq4L9WqIOFvEO8ml+vbRvyUB/Jw6OiUa9GydM58qQl6lTrNHyiENrwyTkOvXLziVkMlOOsesVKyIFtZB1zfDAGvdyj4xtkD7yHQ8Ynn4hCrwvYA+DOJCSlXAZl3MjNQobNzVPK7gJm0AiPsQyEg0c6s1cbEB5X08AmDz1TTLucApzHHyJgADvUqVysJMKOSicLRQl+emOIvbnaw+ot2pSTzl5zzJVjPaZ6ix7zCSN4E1shOAWnqbyYH8bOqd1h9AGJ0qtl6LRBubcBKxbo6xh60kWlbLjgG4NJ2ETkwqbl7SeUXVSCq+BF1C2bWEgEO4CxBGvOydGmu3ooXv7AEogLFqn2JtWKO8yc9xAmDxjhGiWMOQXe63zCvHtIjOpGOIwvGJlhRQepyzaiu0MQ4MnFhuT7CiJQC+sUg4jtOYO+1IH9OdCwgBSmOkP2r60CarHeXMjxw3PGyvOBnN670EgOPOc1yEYgDYCxbqTPDXki1srChi4R6lpQ+uDmVFDtkA5GH1qJEvQFgacqCFT37pyP+Y+DMJs0Y54NgbiIVn61jhEUrNARuNIi3vOQf8iUeQuNzILe4b/jFZ7RDYJhTbVRaJTxyWh8PgO93hQJCBsSa2GQyyoLlBzWDxgnm9l0JgADgNgVxElCH22xs4NCsaieSUyzWXaSTLDAPlGQB0Kt6JaqpzYjkJQT9id60aNwqZjVqlz9Kqp+JcfDjOAqhirNoCI6MelpVPAjZ/CbFv45Y9YNcicqDMKm/Xo/FPJdMlqZ9SIK7qSrrci9mbl6q3/DGQ5f7XuK347rgKeuMgiicEfLPmT0rGY1K5SdI/ryritlMbJrr/PZ8+I8qf9PF8qhMrT39QHfHLkhj/fz/bi+eb83F/VxX1b6jWvt6KdTs/AvvCmqXE235jAAAAAElFTkSuQmCC</Image>
+<Image width="65" height="26">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjcwNUUyRjFGQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjcwNUUyRjIwQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NzA1RTJGMURCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NzA1RTJGMUVCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4qMBarAAAI8ElEQVR42uxZeVRT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</Image>
+<Image width="130" height="52">data:image/png;base64,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</Image>
+<Url type="application/x-suggestions+json" method="GET"
+     template="https://ca.search.yahoo.com/sugg/ff">
+  <Param name="output"  value="fxjson" />
+  <Param name="appid"   value="ffd" />
+  <Param name="command" value="{searchTerms}" />
+</Url>
+<Url type="text/html" method="GET" template="https://ca.search.yahoo.com/yhs/search"
+     resultdomain="yahoo.com" rel="searchform">
+  <Param name="p" value="{searchTerms}"/>
+  <Param name="ei" value="UTF-8"/>
+  <Param name="hspart" value="mozilla"/>
+  <MozParam name="hsimp" condition="purpose" purpose="searchbar"   value="yhs-001"/>
+  <MozParam name="hsimp" condition="purpose" purpose="keyword"     value="yhs-002"/>
+  <MozParam name="hsimp" condition="purpose" purpose="homepage"    value="yhs-003"/>
+  <MozParam name="hsimp" condition="purpose" purpose="newtab"      value="yhs-004"/>
+  <MozParam name="hsimp" condition="purpose" purpose="contextmenu" value="yhs-005"/>
+  <MozParam name="hsimp" condition="purpose" purpose="system"      value="yhs-007"/>
+</Url>
+</SearchPlugin>
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -46,17 +46,17 @@ ul {
 }
 
 #errorTitleText:-moz-dir(rtl) {
   background-position: right 0;
 }
 
 #errorTitle[sslv3=true],
 #errorTitle[weakCrypto=true] {
-  background-image: url("aboutNetError_alert.svg");
+  background-image: url("cert-error.svg");
 }
 
 #errorTryAgain {
   margin-top: 1.2em;
   min-width: 150px
 }
 
 #errorContainer {
@@ -74,77 +74,101 @@ ul {
 
 /* Pressing the retry button will cause the cursor to flicker from a pointer to
  * not-allowed. Override the disabled cursor behaviour since we will never show
  * the button disabled as the initial state. */
 button:disabled {
   cursor: pointer;
 }
 
-div#certificateErrorReporting,
+#learnMoreContainer {
+  display: none;
+}
+
+#buttonContainer {
+  display: none;
+  flex-flow: row wrap;
+}
+
+#buttonSpacer {
+  flex: 1;
+}
+
+#returnButton {
+  background-color: var(--in-content-primary-button-background);
+  border: none;
+  color: var(--in-content-selected-text);
+  min-width: 250px;
+  margin-inline-start: 0;
+}
+
+#returnButton:hover {
+  background-color: var(--in-content-primary-button-background-hover) !important;
+}
+
+#returnButton:hover:active {
+  background-color: var(--in-content-primary-button-background-active) !important;
+}
+
+#advancedButton {
+  display: none;
+  min-width: 150px;
+}
+
+#certificateErrorReporting,
+#reportCertificateError,
+#reportSentMessage {
+  display: none;
+}
+
 div#weakCryptoAdvanced {
   display: none;
   float: right;
   /* Align with the "Try Again" button */
   margin-top: 24px;
   -moz-margin-end: 24px;
 }
 
-div#certificateErrorReporting a,
 div#weakCryptoAdvanced a {
   text-decoration: none;
 }
 
-div#certificateErrorReporting a:hover,
 div#weakCryptoAdvanced a:hover {
   text-decoration: underline;
 }
 
 span.downArrow {
   display: inline-block;
   vertical-align: middle;
   font-size: 0.6em;
   -moz-margin-start: 0.5em;
   transform: scaleY(0.7);
 }
 
-div#certificateErrorReportingPanel,
 div#weakCryptoAdvancedPanel {
   /* Hidden until the link is clicked */
   display: none;
   background-color: white;
   border: 1px lightgray solid;
   /* Don't use top padding because the default p style has top padding, and it
    * makes the overall div look uneven */
   padding: 0 12px 12px 12px;
   box-shadow: 0 0 4px #ddd;
   font-size: 0.9em;
   position: absolute;
-  width: 75%;
-  margin-top: 10px;
-}
-
-div#certificateErrorReportingPanel:-moz-dir(ltr),
-div#weakCryptoAdvancedPanel:-moz-dir(ltr) {
-  left: 34%;
 }
 
-div#certificateErrorReportingPanel:-moz-dir(rtl),
-div#weakCryptoAdvancedPanel:-moz-dir(rtl) {
-  right: 0;
-}
-
-#errorStatePanel,
 #overrideWeakCryptoPanel {
-  display: flex;
+  display: none;
   flex-direction: row;
   flex-wrap: wrap;
   justify-content: space-between;
   align-content: space-between;
   align-items: flex-start;
+  margin-top: 1em;
 }
 
 span#hostname {
   font-weight: bold;
 }
 
 #automaticallyReportInFuture {
   cursor: pointer;
deleted file mode 100644
--- a/browser/themes/shared/aboutNetError_alert.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">
-  <defs>
-    <linearGradient id="gradient1" gradientUnits="userSpaceOnUse" x1="20" y1="4" x2="20" y2="36">
-      <stop offset="0" style="stop-color: #e63b2e"/>
-      <stop offset="1" style="stop-color: #c33931"/>
-    </linearGradient>
-    <linearGradient id="gradient2" gradientUnits="userSpaceOnUse" x1="20" y1="0" x2="20" y2="40">
-      <stop offset="0" style="stop-color: #e63b2e"/>
-      <stop offset="1" style="stop-color: #c33931"/>
-    </linearGradient>
-  </defs>
-  <path fill="url(#gradient1)" d="M13.373,4L4,13.372v13.256L13.373,36h13.255L36,26.628V13.372L26.627,4H13.373z M22.176,8.704 l-0.48,14.304h-3.424L17.76,8.704H22.176z M20,31.296c-1.44,0-2.592-1.184-2.592-2.592c0-1.44,1.152-2.592,2.592-2.592 c1.472,0,2.592,1.152,2.592,2.592C22.592,30.112,21.472,31.296,20,31.296z"/>
-  <path fill="url(#gradient2)" d="M28.284,0H11.716L0,11.716v16.569L11.716,40h16.569L40,28.284V11.716L28.284,0z M38,27.456 L27.456,38H12.544L2,27.456V12.544L12.544,2h14.911L38,12.544V27.456z"/>
-</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -4,17 +4,16 @@
 
 # This is not a complete / proper jar manifest. It is included by the
 # actual theme-specific manifests, so that shared resources need only
 # be specified once. As a result, the source file paths are relative
 # to the location of the actual manifest.
 
   skin/classic/browser/aboutCertError.css                      (../shared/aboutCertError.css)
   skin/classic/browser/aboutNetError.css                       (../shared/aboutNetError.css)
-  skin/classic/browser/aboutNetError_alert.svg                 (../shared/aboutNetError_alert.svg)
 * skin/classic/browser/aboutProviderDirectory.css              (../shared/aboutProviderDirectory.css)
 * skin/classic/browser/aboutSessionRestore.css                 (../shared/aboutSessionRestore.css)
   skin/classic/browser/aboutSocialError.css                    (../shared/aboutSocialError.css)
   skin/classic/browser/aboutTabCrashed.css                     (../shared/aboutTabCrashed.css)
   skin/classic/browser/aboutWelcomeBack.css                    (../shared/aboutWelcomeBack.css)
   skin/classic/browser/addons/addon-install-blocked.svg        (../shared/addons/addon-install-blocked.svg)
   skin/classic/browser/addons/addon-install-confirm.svg        (../shared/addons/addon-install-confirm.svg)
   skin/classic/browser/addons/addon-install-downloading.svg    (../shared/addons/addon-install-downloading.svg)
--- a/build/autoconf/nspr-build.m4
+++ b/build/autoconf/nspr-build.m4
@@ -160,17 +160,17 @@ elif test -z "$JS_POSIX_NSPR"; then
     NSPR_CFLAGS="-I${DIST}/include/nspr"
     if test -n "$GNU_CC"; then
         NSPR_LIBS="-L${DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}"
     else
         NSPR_LIBS="${DIST}/lib/nspr${NSPR_VERSION}.lib ${DIST}/lib/plc${NSPR_VERSION}.lib ${DIST}/lib/plds${NSPR_VERSION}.lib "
     fi
 fi
 
-AC_SUBST(NSPR_CFLAGS)
+AC_SUBST_LIST(NSPR_CFLAGS)
 
 NSPR_PKGCONF_CHECK="nspr"
 if test -n "$MOZ_NATIVE_NSPR"; then
     # piggy back on $MOZ_NATIVE_NSPR to set a variable for the nspr check for js.pc
     NSPR_PKGCONF_CHECK="nspr >= $NSPR_MINVER"
 
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS $NSPR_CFLAGS"
--- a/build/autoconf/nspr.m4
+++ b/build/autoconf/nspr.m4
@@ -99,12 +99,12 @@ AC_ARG_WITH(nspr-exec-prefix,
 		AC_MSG_RESULT(yes)
 		ifelse([$2], , :, [$2])     
 	else
 		AC_MSG_RESULT(no)
 		ifelse([$3], , :, [$3])
 	fi
 
 
-	AC_SUBST(NSPR_CFLAGS)
+	AC_SUBST_LIST(NSPR_CFLAGS)
 	AC_SUBST_LIST(NSPR_LIBS)
 
 ])
--- a/build/autoconf/nss.m4
+++ b/build/autoconf/nss.m4
@@ -80,12 +80,12 @@ AC_ARG_WITH(nss-exec-prefix,
 		AC_MSG_RESULT(yes)
 		ifelse([$2], , :, [$2])     
 	else
 		AC_MSG_RESULT(no)
 		ifelse([$3], , :, [$3])
 	fi
 
 
-	AC_SUBST(NSS_CFLAGS)
+	AC_SUBST_LIST(NSS_CFLAGS)
 	AC_SUBST_LIST(NSS_LIBS)
 
 ])
--- a/build/autoconf/zlib.m4
+++ b/build/autoconf/zlib.m4
@@ -42,13 +42,13 @@ if test -z "$MOZ_ZLIB_LIBS$MOZ_ZLIB_CFLA
                            AC_MSG_ERROR([Insufficient zlib version for --with-system-zlib ($MOZZLIB required)]))
         fi
     fi
     CFLAGS=$_SAVE_CFLAGS
     LDFLAGS=$_SAVE_LDFLAGS
     LIBS=$_SAVE_LIBS
 fi
 
-AC_SUBST(MOZ_ZLIB_CFLAGS)
+AC_SUBST_LIST(MOZ_ZLIB_CFLAGS)
 AC_SUBST_LIST(MOZ_ZLIB_LIBS)
 AC_SUBST(MOZ_NATIVE_ZLIB)
 
 ])
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -107,17 +107,16 @@ MACH_MODULES = [
     'layout/tools/reftest/mach_commands.py',
     'python/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/compare-locales/mach_commands.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/backend/mach_commands.py',
     'python/mozbuild/mozbuild/compilation/codecomplete.py',
-    'python/mozbuild/mozbuild/compilation/database.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'services/common/tests/mach_commands.py',
     'testing/luciddream/mach_commands.py',
     'testing/mach_commands.py',
     'testing/taskcluster/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
--- a/build/moz.build
+++ b/build/moz.build
@@ -49,30 +49,29 @@ for var in ('MOZ_CRASHREPORTER', 'MOZ_PR
         DEFINES[var] = True
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     PYTHON_UNIT_TESTS += [
         'compare-mozconfig/compare-mozconfigs-wrapper.py',
     ]
 
 if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']:
-    tools_dir = TOPSRCDIR + '/tools/rb/'
-    FINAL_TARGET_FILES += [tools_dir + 'fix_stack_using_bpsyms.py']
+    FINAL_TARGET_FILES += ['/tools/rb/fix_stack_using_bpsyms.py']
     if CONFIG['OS_ARCH'] == 'Darwin':
-        FINAL_TARGET_FILES += [tools_dir + 'fix_macosx_stack.py']
+        FINAL_TARGET_FILES += ['/tools/rb/fix_macosx_stack.py']
     if CONFIG['OS_ARCH'] == 'Linux':
-        FINAL_TARGET_FILES += [tools_dir + 'fix_linux_stack.py']
+        FINAL_TARGET_FILES += ['/tools/rb/fix_linux_stack.py']
 
 if CONFIG['MOZ_DMD']:
-    FINAL_TARGET_FILES += [TOPSRCDIR + '/memory/replace/dmd/dmd.py']
+    FINAL_TARGET_FILES += ['/memory/replace/dmd/dmd.py']
 
 # Put a useful .gdbinit in the bin directory, to be picked up automatically
 # by GDB when we debug executables there.
-FINAL_TARGET_FILES += [TOPSRCDIR + '/.gdbinit']
+FINAL_TARGET_FILES += ['/.gdbinit']
 
 # Install the clang-cl runtime library for ASAN next to the binaries we produce.
 if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']:
-    FINAL_TARGET_FILES += [CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
+    FINAL_TARGET_FILES += ['%' + CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
 
 if CONFIG['MOZ_APP_BASENAME']:
     FINAL_TARGET_PP_FILES += ['application.ini']
     if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android' and CONFIG['MOZ_UPDATER']:
         FINAL_TARGET_PP_FILES += ['update-settings.ini']
--- a/build/mozconfig.cache
+++ b/build/mozconfig.cache
@@ -7,17 +7,17 @@
 # Avoid duplication if the file happens to be included twice.
 if test -z "$bucket"; then
 
 read branch platform master <<EOF
 $(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
 EOF
 
 bucket=
-if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET"; then
+if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
     case "${branch}" in
     try)
         case "${master}" in
         *scl1.mozilla.com*|*.scl3.mozilla.com*)
             bucket=mozilla-releng-s3-cache-us-west-1-try
             ;;
         *use1.mozilla.com*)
             bucket=mozilla-releng-s3-cache-us-east-1-try
--- a/configure.in
+++ b/configure.in
@@ -4698,26 +4698,16 @@ then
     then
         PKG_CHECK_MODULES(MOZ_LIBPROXY, libproxy-1.0)
         AC_DEFINE(MOZ_ENABLE_LIBPROXY)
     fi
 fi
 AC_SUBST(MOZ_ENABLE_LIBPROXY)
 
 dnl ========================================================
-dnl = GNOME component (mozgnome)
-dnl ========================================================
-
-if test "$MOZ_ENABLE_GTK"
-then
-    MOZ_ENABLE_GNOME_COMPONENT=1
-fi
-AC_SUBST(MOZ_ENABLE_GNOME_COMPONENT)
-
-dnl ========================================================
 dnl = libgnomeui support module
 dnl ========================================================
 
 if test "$MOZ_ENABLE_GTK"
 then
     MOZ_ARG_ENABLE_BOOL(gnomeui,
     [  --enable-gnomeui        Enable libgnomeui instead of GIO & GTK for icon theme support ],
         MOZ_ENABLE_GNOMEUI=force,
@@ -8828,41 +8818,39 @@ HOST_CFLAGS=`echo \
 HOST_CXXFLAGS=`echo \
     $HOST_CXXFLAGS \
     $_DEPEND_CFLAGS`
 
 AC_SUBST(MOZ_NATIVE_JPEG)
 AC_SUBST(MOZ_NATIVE_PNG)
 AC_SUBST(MOZ_NATIVE_BZ2)
 
-AC_SUBST(MOZ_JPEG_CFLAGS)
+AC_SUBST_LIST(MOZ_JPEG_CFLAGS)
 AC_SUBST_LIST(MOZ_JPEG_LIBS)
 AC_SUBST_LIST(MOZ_BZ2_CFLAGS)
 AC_SUBST_LIST(MOZ_BZ2_LIBS)
-AC_SUBST(MOZ_PNG_CFLAGS)
+AC_SUBST_LIST(MOZ_PNG_CFLAGS)
 AC_SUBST_LIST(MOZ_PNG_LIBS)
 
 if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
     export MOZ_NUWA_PROCESS
     AC_DEFINE(MOZ_NUWA_PROCESS)
 fi
 AC_SUBST(MOZ_NUWA_PROCESS)
 if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_B2G_LOADER"; then
     if test -z "$MOZ_NUWA_PROCESS"; then
        AC_MSG_ERROR([B2G loader works with Nuwa]);
     fi
     export MOZ_B2G_LOADER
     AC_DEFINE(MOZ_B2G_LOADER)
 fi
 AC_SUBST(MOZ_B2G_LOADER)
 
-AC_SUBST(NSPR_CFLAGS)
 AC_SUBST(MOZ_NATIVE_NSPR)
 
-AC_SUBST(NSS_CFLAGS)
 AC_SUBST(MOZ_NATIVE_NSS)
 AC_SUBST(NSS_DISABLE_DBM)
 
 OS_CFLAGS="$CFLAGS"
 OS_CXXFLAGS="$CXXFLAGS"
 OS_CPPFLAGS="$CPPFLAGS"
 OS_COMPILE_CFLAGS="$COMPILE_CFLAGS"
 OS_COMPILE_CXXFLAGS="$COMPILE_CXXFLAGS"
--- a/docshell/base/LoadContext.cpp
+++ b/docshell/base/LoadContext.cpp
@@ -2,17 +2,44 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/LoadContext.h"
+#include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
+#include "nsContentUtils.h"
+#include "xpcpublic.h"
 
+bool
+nsILoadContext::GetOriginAttributes(mozilla::DocShellOriginAttributes& aAttrs)
+{
+  mozilla::dom::AutoJSAPI jsapi;
+  bool ok = jsapi.Init(xpc::PrivilegedJunkScope());
+  NS_ENSURE_TRUE(ok, false);
+  JS::Rooted<JS::Value> v(jsapi.cx());
+  nsresult rv = GetOriginAttributes(&v);
+  NS_ENSURE_SUCCESS(rv, false);
+  NS_ENSURE_TRUE(v.isObject(), false);
+  JS::Rooted<JSObject*> obj(jsapi.cx(), &v.toObject());
+
+  // If we're JS-implemented, the object will be left in a different (System-Principaled)
+  // scope, so we may need to enter its compartment.
+  MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)));
+  JSAutoCompartment ac(jsapi.cx(), obj);
+
+  mozilla::DocShellOriginAttributes attrs;
+  ok = attrs.Init(jsapi.cx(), v);
+  NS_ENSURE_TRUE(ok, false);
+  aAttrs = attrs;
+  return true;
+}
+  
 namespace mozilla {
 
 NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor)
 
 LoadContext::LoadContext(nsIPrincipal* aPrincipal,
                          nsILoadContext* aOptionalBase)
   : mTopFrameElement(nullptr)
   , mNestedFrameId(0)
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -14158,30 +14158,36 @@ nsDocShell::ChannelIntercepted(nsIInterc
   nsCOMPtr<nsIDocument> doc;
 
   bool isSubresourceLoad = !nsContentUtils::IsNonSubresourceRequest(channel);
   if (isSubresourceLoad) {
     doc = GetDocument();
     if (!doc) {
       return NS_ERROR_NOT_AVAILABLE;
     }
+  } else {
+    // For top-level navigations, save a document ID which will be passed to
+    // the FetchEvent as the clientId later on.
+    rv = nsIDocument::GenerateDocumentId(mInterceptedDocumentId);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool isReload = mLoadType & LOAD_CMD_RELOAD;
 
   nsCOMPtr<nsIURI> uri;
   rv = channel->GetURI(getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrincipalOriginAttributes attrs;
   attrs.InheritFromDocShellToDoc(GetOriginAttributes(), uri);
 
   ErrorResult error;
   nsCOMPtr<nsIRunnable> runnable =
-    swm->PrepareFetchEvent(attrs, doc, aChannel, isReload, isSubresourceLoad, error);
+    swm->PrepareFetchEvent(attrs, doc, mInterceptedDocumentId, aChannel,
+                           isReload, isSubresourceLoad, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   MOZ_ASSERT(runnable);
   RefPtr<FetchEventDispatcher> dispatcher =
     new FetchEventDispatcher(aChannel, runnable);
   dispatcher.forget(aFetchDispatcher);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -268,16 +268,21 @@ public:
   void SetInFrameSwap(bool aInSwap)
   {
     mInFrameSwap = aInSwap;
   }
   bool InFrameSwap();
 
   mozilla::DocShellOriginAttributes GetOriginAttributes();
 
+  void GetInterceptedDocumentId(nsAString& aId)
+  {
+    aId = mInterceptedDocumentId;
+  }
+
 private:
   // An observed docshell wrapper is created when recording markers is enabled.
   mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
 
   // It is necessary to allow adding a timeline marker wherever a docshell
   // instance is available. This operation happens frequently and needs to
   // be very fast, so instead of using a Map or having to search for some
   // docshell-specific markers storage, a pointer to an `ObservedDocShell` is
@@ -1009,16 +1014,18 @@ protected:
   nsString mPaymentRequestId;
 
   nsString GetInheritedPaymentRequestId();
 
   // The packageId for a signed packaged iff this docShell is created
   // for a signed package.
   nsString mSignedPkg;
 
+  nsString mInterceptedDocumentId;
+
 private:
   nsCString mForcedCharset;
   nsCString mParentCharset;
   int32_t mParentCharsetSource;
   nsCOMPtr<nsIPrincipal> mParentCharsetPrincipal;
   nsTObserverArray<nsWeakPtr> mPrivacyObservers;
   nsTObserverArray<nsWeakPtr> mReflowObservers;
   nsTObserverArray<nsWeakPtr> mScrollObservers;
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -7,28 +7,25 @@
 #include "nsISupports.idl"
 
 interface nsIDOMWindow;
 interface nsIDOMElement;
 
 %{C++
 #ifdef MOZILLA_INTERNAL_API
 #include "mozilla/BasePrincipal.h" // for DocShellOriginAttributes
-#include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
-#include "xpcpublic.h" // for PrivilegedJunkScope
-#include "nsContentUtils.h" // for IsSystemPrincipal
 #endif
 %}
 
 /**
  * An nsILoadContext represents the context of a load.  This interface
  * can be queried for various information about where the load is
  * happening.
  */
-[scriptable, uuid(96014778-d30b-4fee-8902-a3481788907b)]
+[scriptable, uuid(c71ef717-8fb9-425e-98ef-aef5894890f8)]
 interface nsILoadContext : nsISupports
 {
   /**
    * associatedWindow is the window with which the load is associated, if any.
    * Note that the load may be triggered by a document which is different from
    * the document in associatedWindow, and in fact the source of the load need
    * not be same-origin with the document in associatedWindow.  This attribute
    * may be null if there is no associated window.
@@ -134,35 +131,15 @@ interface nsILoadContext : nsISupports
    * nsILoadContext.
    */
   readonly attribute jsval originAttributes;
 
 %{C++
 #ifdef MOZILLA_INTERNAL_API
   /**
    * The C++ getter for origin attributes.
+   *
+   * Defined in LoadContext.cpp
    */
-  bool GetOriginAttributes(mozilla::DocShellOriginAttributes& aAttrs)
-  {
-    mozilla::dom::AutoJSAPI jsapi;
-    bool ok = jsapi.Init(xpc::PrivilegedJunkScope());
-    NS_ENSURE_TRUE(ok, false);
-    JS::Rooted<JS::Value> v(jsapi.cx());
-    nsresult rv = GetOriginAttributes(&v);
-    NS_ENSURE_SUCCESS(rv, false);
-    NS_ENSURE_TRUE(v.isObject(), false);
-    JS::Rooted<JSObject*> obj(jsapi.cx(), &v.toObject());
-
-    // If we're JS-implemented, the object will be left in a different (System-Principaled)
-    // scope, so we may need to enter its compartment.
-    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)));
-    JSAutoCompartment ac(jsapi.cx(), obj);
-
-    mozilla::DocShellOriginAttributes attrs;
-    ok = attrs.Init(jsapi.cx(), v);
-    NS_ENSURE_TRUE(ok, false);
-    aAttrs = attrs;
-    return true;
-  }
-
+  bool GetOriginAttributes(mozilla::DocShellOriginAttributes& aAttrs);
 #endif
 %}
 };
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -57,16 +57,22 @@ void
 Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
                         JS::MutableHandle<JSObject*> aRetval,
                         ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Called on the wrong thread");
 
   JS::Rooted<JSObject*> view(aCx, aArray.Obj());
 
+  if (JS_IsTypedArrayObject(view) && JS_GetTypedArraySharedness(view)) {
+    // Throw if the object is mapping shared memory (must opt in).
+    aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of Crypto.getRandomValues"));
+    return;
+  }
+
   // Throw if the wrong type of ArrayBufferView is passed in
   // (Part of the Web Crypto API spec)
   switch (JS_GetArrayBufferViewType(view)) {
     case js::Scalar::Int8:
     case js::Scalar::Uint8:
     case js::Scalar::Uint8Clamped:
     case js::Scalar::Int16:
     case js::Scalar::Uint16:
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -172,28 +172,26 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   tmp->mThrownJSVal.setNull();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CI_INTERFACE_GETTER(Exception, nsIXPCException)
 
 Exception::Exception(const nsACString& aMessage,
                      nsresult aResult,
@@ -243,17 +241,17 @@ Exception::Exception(const nsACString& a
       nsCOMPtr<nsIStackFrame> caller;
       if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) {
         break;
       }
       location = caller;
     }
   }
 
-  Initialize(aMessage, aResult, aName, location, aData, nullptr);
+  Initialize(aMessage, aResult, aName, location, aData);
 }
 
 Exception::Exception()
   : mResult(NS_OK),
     mLineNumber(-1),
     mInitialized(false),
     mHoldingJSVal(false)
 {
@@ -395,27 +393,16 @@ Exception::GetData(nsISupports** aData)
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   nsCOMPtr<nsISupports> data = mData;
   data.forget(aData);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Exception::GetInner(nsIException** aException)
-{
-  NS_ENSURE_ARG_POINTER(aException);
-  NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
-
-  nsCOMPtr<nsIException> inner = mInner;
-  inner.forget(aException);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 Exception::ToString(nsACString& _retval)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   static const char defaultMsg[] = "<no message>";
   static const char defaultLocation[] = "<unknown>";
   static const char format[] =
 "[Exception... \"%s\"  nsresult: \"0x%x (%s)\"  location: \"%s\"  data: %s]";
@@ -449,17 +436,17 @@ Exception::ToString(nsACString& _retval)
   _retval.AppendPrintf(format, msg, mResult, resultName,
                        location.get(), data);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Exception::Initialize(const nsACString& aMessage, nsresult aResult,
                       const nsACString& aName, nsIStackFrame *aLocation,
-                      nsISupports *aData, nsIException *aInner)
+                      nsISupports *aData)
 {
   NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED);
 
   mMessage = aMessage;
   mName = aName;
   mResult = aResult;
 
   if (aLocation) {
@@ -469,17 +456,16 @@ Exception::Initialize(const nsACString& 
     nsXPConnect* xpc = nsXPConnect::XPConnect();
     rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   mData = aData;
-  mInner = aInner;
 
   mInitialized = true;
   return NS_OK;
 }
 
 JSObject*
 Exception::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
 {
@@ -539,23 +525,16 @@ Exception::ColumnNumber() const
 already_AddRefed<nsIStackFrame>
 Exception::GetLocation() const
 {
   nsCOMPtr<nsIStackFrame> location = mLocation;
   return location.forget();
 }
 
 already_AddRefed<nsISupports>
-Exception::GetInner() const
-{
-  nsCOMPtr<nsIException> inner = mInner;
-  return inner.forget();
-}
-
-already_AddRefed<nsISupports>
 Exception::GetData() const
 {
   nsCOMPtr<nsISupports> data = mData;
   return data.forget();
 }
 
 void
 Exception::GetStack(nsAString& aStack, ErrorResult& aRv) const
@@ -618,35 +597,16 @@ DOMException::ToString(nsACString& aRetu
   static const char defaultMsg[] = "<no message>";
   static const char defaultLocation[] = "<unknown>";
   static const char defaultName[] = "<unknown>";
   static const char format[] =
     "[Exception... \"%s\"  code: \"%d\" nsresult: \"0x%x (%s)\"  location: \"%s\"]";
 
   nsAutoCString location;
 
-  if (mInner) {
-    nsString filename;
-    mInner->GetFilename(filename);
-
-    if (!filename.IsEmpty()) {
-      uint32_t line_nr = 0;
-
-      mInner->GetLineNumber(&line_nr);
-
-      char *temp = PR_smprintf("%s Line: %d",
-                               NS_ConvertUTF16toUTF8(filename).get(),
-                               line_nr);
-      if (temp) {
-        location.Assign(temp);
-        PR_smprintf_free(temp);
-      }
-    }
-  }
-
   if (location.IsEmpty()) {
     location = defaultLocation;
   }
 
   const char* msg = !mMessage.IsEmpty() ? mMessage.get() : defaultMsg;
   const char* resultName = !mName.IsEmpty() ? mName.get() : defaultName;
 
   aReturn.AppendPrintf(format, msg, mCode, mResult, resultName,
--- a/dom/base/DOMException.h
+++ b/dom/base/DOMException.h
@@ -79,18 +79,16 @@ public:
   // return an empty filename in that case anyway, instead of throwing.
 
   uint32_t LineNumber() const;
 
   uint32_t ColumnNumber() const;
 
   already_AddRefed<nsIStackFrame> GetLocation() const;
 
-  already_AddRefed<nsISupports> GetInner() const;
-
   already_AddRefed<nsISupports> GetData() const;
 
   void GetStack(nsAString& aStack, ErrorResult& aRv) const;
 
   void Stringify(nsString& retval);
 
   // XPCOM factory ctor.
   Exception();
@@ -106,17 +104,16 @@ protected:
 
   nsCString       mMessage;
   nsresult        mResult;
   nsCString       mName;
   nsCOMPtr<nsIStackFrame> mLocation;
   nsCOMPtr<nsISupports> mData;
   nsString        mFilename;
   int             mLineNumber;
-  nsCOMPtr<nsIException> mInner;
   bool            mInitialized;
 
   bool mHoldingJSVal;
   JS::Heap<JS::Value> mThrownJSVal;
 
 private:
   static bool sEverMadeOneFromFactory;
 };
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -541,16 +541,26 @@ Element::ClassList()
 }
 
 void
 Element::GetClassList(nsISupports** aClassList)
 {
   NS_ADDREF(*aClassList = ClassList());
 }
 
+void
+Element::GetAttributeNames(nsTArray<nsString>& aResult)
+{
+  uint32_t count = mAttrsAndChildren.AttrCount();
+  for (uint32_t i = 0; i < count; ++i) {
+    const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
+    name->GetQualifiedName(*aResult.AppendElement());
+  }
+}
+
 already_AddRefed<nsIHTMLCollection>
 Element::GetElementsByTagName(const nsAString& aLocalName)
 {
   return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
 }
 
 void
 Element::GetElementsByTagName(const nsAString& aLocalName,
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -619,16 +619,19 @@ public:
   {
     nsDOMSlots* slots = DOMSlots();
     if (!slots->mAttributeMap) {
       slots->mAttributeMap = new nsDOMAttributeMap(this);
     }
 
     return slots->mAttributeMap;
   }
+
+  void GetAttributeNames(nsTArray<nsString>& aResult);
+
   void GetAttribute(const nsAString& aName, nsString& aReturn)
   {
     DOMString str;
     GetAttribute(aName, str);
     str.ToString(aReturn);
   }
 
   void GetAttribute(const nsAString& aName, DOMString& aReturn);
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -539,26 +539,35 @@ AutoJSAPI::ReportException()
       ClearException();
     }
   } else {
     NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
   }
 }
 
 bool
+AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
+{
+  MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
+  MOZ_ASSERT(HasException());
+  MOZ_ASSERT(js::GetContextCompartment(cx()));
+  if (!JS_GetPendingException(cx(), aVal)) {
+    return false;
+  }
+  return true;
+}
+
+bool
 AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
 {
-    MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
-    MOZ_ASSERT(HasException());
-    MOZ_ASSERT(js::GetContextCompartment(cx()));
-    if (!JS_GetPendingException(cx(), aVal)) {
-      return false;
-    }
-    JS_ClearPendingException(cx());
-    return true;
+  if (!PeekException(aVal)) {
+    return false;
+  }
+  JS_ClearPendingException(cx());
+  return true;
 }
 
 AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
                                  const char *aReason,
                                  bool aIsMainThread,
                                  JSContext* aCx)
   : AutoJSAPI(aGlobalObject, aIsMainThread,
               aCx ? aCx : FindJSContext(aGlobalObject))
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -286,16 +286,24 @@ public:
   // Transfers ownership of the current exception from the JS engine to the
   // caller. Callers must ensure that HasException() is true, and that cx()
   // is in a non-null compartment.
   //
   // Note that this fails if and only if we OOM while wrapping the exception
   // into the current compartment.
   bool StealException(JS::MutableHandle<JS::Value> aVal);
 
+  // Peek the current exception from the JS engine, without stealing it.
+  // Callers must ensure that HasException() is true, and that cx() is in a
+  // non-null compartment.
+  //
+  // Note that this fails if and only if we OOM while wrapping the exception
+  // into the current compartment.
+  bool PeekException(JS::MutableHandle<JS::Value> aVal);
+
   void ClearException() {
     MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
     JS_ClearPendingException(cx());
   }
 
 protected:
   // Protected constructor, allowing subclasses to specify a particular cx to
   // be used. This constructor initialises the AutoJSAPI, so Init must NOT be
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6145,17 +6145,19 @@ nsContentUtils::CreateArrayBuffer(JSCont
   *aResult = JS_NewArrayBuffer(aCx, dataLen);
   if (!*aResult) {
     return NS_ERROR_FAILURE;
   }
 
   if (dataLen > 0) {
     NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
     JS::AutoCheckCannotGC nogc;
-    memcpy(JS_GetArrayBufferData(*aResult, nogc), aData.BeginReading(), dataLen);
+    bool isShared;
+    memcpy(JS_GetArrayBufferData(*aResult, &isShared, nogc), aData.BeginReading(), dataLen);
+    MOZ_ASSERT(!isShared);
   }
 
   return NS_OK;
 }
 
 // Initial implementation: only stores to RAM, not file
 // TODO: bug 704447: large file support
 nsresult
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -235,16 +235,17 @@
 #include "nsContentPermissionHelper.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsLocation.h"
 #include "mozilla/dom/FontFaceSet.h"
 #include "mozilla/dom/BoxObject.h"
 #include "gfxVR.h"
 #include "gfxPrefs.h"
+#include "nsISupportsPrimitives.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
 #include "nsISpeculativeConnect.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "mozilla/MediaManager.h"
 #endif // MOZ_MEDIA_NAVIGATOR
@@ -1639,16 +1640,21 @@ nsDocument::~nsDocument()
   mPendingTitleChangeEvent.Revoke();
 
   // We don't want to leave residual locks on images. Make sure we're in an
   // unlocked state, and then clear the table.
   SetImageLockingState(false);
   mImageTracker.Clear();
 
   mPlugins.Clear();
+
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  if (os) {
+    os->RemoveObserver(this, "service-worker-get-client");
+  }
 }
 
 NS_INTERFACE_TABLE_HEAD(nsDocument)
   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE_BEGIN
     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
@@ -2040,16 +2046,21 @@ nsDocument::Init()
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
   mScopeObject = do_GetWeakReference(global);
   MOZ_ASSERT(mScopeObject);
 
   mScriptLoader = new nsScriptLoader(this);
 
   mozilla::HoldJSObjects(this);
 
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  if (os) {
+    os->AddObserver(this, "service-worker-get-client", /* ownsWeak */ true);
+  }
+
   return NS_OK;
 }
 
 void
 nsIDocument::DeleteAllProperties()
 {
   for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
     PropertyTable(i)->DeleteAllProperties();
@@ -4614,17 +4625,20 @@ nsDocument::SetScriptGlobalObject(nsIScr
     // If we are shift-reloaded, don't associate with a ServiceWorker.
     if (IsForceReloadType(loadType)) {
       NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
       return;
     }
 
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (swm) {
-      swm->MaybeStartControlling(this);
+      nsAutoString documentId;
+      static_cast<nsDocShell*>(docShell.get())->GetInterceptedDocumentId(documentId);
+
+      swm->MaybeStartControlling(this, documentId);
       mMaybeServiceWorkerControlled = true;
     }
   }
 }
 
 nsIScriptGlobalObject*
 nsDocument::GetScriptHandlingObjectInternal() const
 {
@@ -12197,16 +12211,26 @@ nsDocument::Observe(nsISupports *aSubjec
                     const char16_t *aData)
 {
   if (strcmp("app-theme-changed", aTopic) == 0) {
     if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
         !IsUnstyledDocument()) {
       // We don't want to style the chrome window, only app ones.
       OnAppThemeChanged();
     }
+  } else if (strcmp("service-worker-get-client", aTopic) == 0) {
+    nsAutoString clientId;
+    GetOrCreateId(clientId);
+    if (!clientId.IsEmpty() && clientId.Equals(aData)) {
+      nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_QueryInterface(aSubject);
+      if (ifptr) {
+        ifptr->SetData(static_cast<nsIDocument*>(this));
+        ifptr->SetDataIID(&NS_GET_IID(nsIDocument));
+      }
+    }
   }
   return NS_OK;
 }
 
 void
 nsDocument::OnAppThemeChanged()
 {
   // Bail out if there is no theme support set up properly.
@@ -13048,45 +13072,57 @@ nsIDocument::CreateHTMLElement(nsIAtom* 
   DebugOnly<nsresult> rv = NS_NewHTMLElement(getter_AddRefs(element),
                                              nodeInfo.forget(),
                                              mozilla::dom::NOT_FROM_PARSER);
 
   MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_NewHTMLElement should never fail");
   return element.forget();
 }
 
+/* static */
 nsresult
-nsIDocument::GetId(nsAString& aId)
+nsIDocument::GenerateDocumentId(nsAString& aId)
+{
+  nsID id;
+  nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
+  char buffer[NSID_LENGTH];
+  id.ToProvidedString(buffer);
+  NS_ConvertASCIItoUTF16 uuid(buffer);
+
+  // Remove {} and the null terminator
+  aId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
+  return NS_OK;
+}
+
+nsresult
+nsIDocument::GetOrCreateId(nsAString& aId)
 {
   if (mId.IsEmpty()) {
-    nsresult rv;
-    nsCOMPtr<nsIUUIDGenerator> uuidgen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
+    nsresult rv = GenerateDocumentId(mId);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
-
-    nsID id;
-    rv = uuidgen->GenerateUUIDInPlace(&id);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    // Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
-    char buffer[NSID_LENGTH];
-    id.ToProvidedString(buffer);
-    NS_ConvertASCIItoUTF16 uuid(buffer);
-
-    // Remove {} and the null terminator
-    mId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
   }
 
   aId = mId;
   return NS_OK;
 }
 
+void
+nsIDocument::SetId(const nsAString& aId)
+{
+  MOZ_ASSERT(mId.IsEmpty(), "Cannot set the document ID after we have one");
+  mId = aId;
+}
+
 bool
 MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
 {
   nsCOMArray<nsIDocument>* documents =
     static_cast<nsCOMArray<nsIDocument>*>(aData);
   if (aDoc) {
     aDoc->SetIsInSyncOperation(true);
     documents->AppendObject(aDoc);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2822,16 +2822,21 @@ nsFocusManager::DetermineElementToMoveFo
         // appears in the tab order before all of the elements in the document.
         // Chrome documents however cannot be focused directly, so instead we
         // focus the first focusable element within the window.
         // For example, the urlbar.
         nsIContent* root = GetRootForFocus(piWindow, doc, true, true);
         return FocusFirst(root, aNextContent);
       }
 
+      // Once we have hit the top-level and have iterated to the end again, we
+      // just want to break out next time we hit this spot to prevent infinite
+      // iteration.
+      mayFocusRoot = true;
+
       // reset the tab index and start again from the beginning or end
       startContent = rootContent;
       tabIndex = forward ? 1 : 0;
     }
 
     // wrapped all the way around and didn't find anything to move the focus
     // to, so just break out
     if (startContent == originalStartContent)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -579,16 +579,30 @@ DialogValueHolder::Get(nsIPrincipal* aSu
     result = mValue;
   } else {
     result = CreateVoidVariant();
   }
   result.forget(aResult);
   return NS_OK;
 }
 
+void
+DialogValueHolder::Get(JSContext* aCx, JS::Handle<JSObject*> aScope,
+                       nsIPrincipal* aSubject,
+                       JS::MutableHandle<JS::Value> aResult,
+                       mozilla::ErrorResult& aError)
+{
+  if (aSubject->Subsumes(mOrigin)) {
+    aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
+                                                      mValue, aResult);
+  } else {
+    aResult.setUndefined();
+  }
+}
+
 namespace mozilla {
 namespace dom {
 extern uint64_t
 NextWindowID();
 } // namespace dom
 } // namespace mozilla
 
 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -262,25 +262,17 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(DialogValueHolder)
 
   DialogValueHolder(nsIPrincipal* aSubject, nsIVariant* aValue)
     : mOrigin(aSubject)
     , mValue(aValue) {}
   nsresult Get(nsIPrincipal* aSubject, nsIVariant** aResult);
   void Get(JSContext* aCx, JS::Handle<JSObject*> aScope, nsIPrincipal* aSubject,
-           JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError)
-  {
-    if (aSubject->Subsumes(mOrigin)) {
-      aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
-                                                        mValue, aResult);
-    } else {
-      aResult.setUndefined();
-    }
-  }
+           JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError);
 private:
   virtual ~DialogValueHolder() {}
 
   nsCOMPtr<nsIPrincipal> mOrigin;
   nsCOMPtr<nsIVariant> mValue;
 };
 
 //*****************************************************************************
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -130,16 +130,25 @@ nsHostObjectURI::Deserialize(const mozil
   if (hostParams.principal().type() == OptionalPrincipalInfo::Tvoid_t) {
     return true;
   }
 
   mPrincipal = PrincipalInfoToPrincipal(hostParams.principal().get_PrincipalInfo());
   return mPrincipal != nullptr;
 }
 
+NS_IMETHODIMP
+nsHostObjectURI::SetScheme(const nsACString& aScheme)
+{
+  // 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,
                                nsIURI** aClone)
 {
   nsCOMPtr<nsIURI> simpleClone;
   nsresult rv =
     nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
--- a/dom/base/nsHostObjectURI.h
+++ b/dom/base/nsHostObjectURI.h
@@ -33,16 +33,18 @@ public:
   nsHostObjectURI() : nsSimpleURI() {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIURIWITHPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
   NS_DECL_NSIIPCSERIALIZABLEURI
 
+  NS_IMETHOD SetScheme(const nsACString &aProtocol) override;
+
   // 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
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -801,17 +801,19 @@ public:
   InsertAnonymousContent(mozilla::dom::Element& aElement,
                          mozilla::ErrorResult& aError);
   void RemoveAnonymousContent(mozilla::dom::AnonymousContent& aContent,
                               mozilla::ErrorResult& aError);
   nsTArray<RefPtr<mozilla::dom::AnonymousContent>>& GetAnonymousContents() {
     return mAnonymousContents;
   }
 
-  nsresult GetId(nsAString& aId);
+  static nsresult GenerateDocumentId(nsAString& aId);
+  nsresult GetOrCreateId(nsAString& aId);
+  void SetId(const nsAString& aId);
 
 protected:
   virtual Element *GetRootElementInternal() const = 0;
 
 private:
   class SelectorCacheKey
   {
     public:
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -7,16 +7,17 @@
 #include <cmath>
 #include <limits>
 #include "BatteryManager.h"
 #include "Constants.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Hal.h"
 #include "mozilla/dom/BatteryManagerBinding.h"
 #include "mozilla/Preferences.h"
+#include "nsContentUtils.h"
 #include "nsIDOMClassInfo.h"
 #include "nsIDocument.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
 #define LEVELCHANGE_EVENT_NAME           NS_LITERAL_STRING("levelchange")
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -185,22 +185,18 @@ CallbackObject::CallSetup::CallSetup(Cal
   // Note that if the callback is a wrapper, this will not be the same
   // compartment that we ended up in with mAutoEntryScript above, because the
   // entry point is based off of the unwrapped callback (realCallback).
   mAc.emplace(cx, *mRootedCallable);
 
   // And now we're ready to go.
   mCx = cx;
 
-  // Make sure the JS engine doesn't report exceptions we want to re-throw
-  if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
-      mExceptionHandling == eRethrowExceptions) {
-    mSavedJSContextOptions = JS::ContextOptionsRef(cx);
-    JS::ContextOptionsRef(cx).setDontReportUncaught(true);
-  }
+  // Make sure the JS engine doesn't report exceptions we want to re-throw.
+  mAutoEntryScript->TakeOwnershipOfErrorReporting();
 }
 
 bool
 CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aException)
 {
   if (mExceptionHandling == eRethrowExceptions) {
     if (!mCompartment) {
       // Caller didn't ask us to filter for only exceptions we subsume.
@@ -248,58 +244,63 @@ CallbackObject::CallSetup::~CallSetup()
   // so we end up reporting them while in the compartment of our entry point,
   // not whatever cross-compartment wrappper mCallback might be.
   // Be careful: the JSAutoCompartment might not have been constructed at all!
   mAc.reset();
 
   // Now, if we have a JSContext, report any pending errors on it, unless we
   // were told to re-throw them.
   if (mCx) {
-    bool needToDealWithException = JS_IsExceptionPending(mCx);
+    bool needToDealWithException = mAutoEntryScript->HasException();
     if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
         mExceptionHandling == eRethrowExceptions) {
-      // Restore the old context options
-      JS::ContextOptionsRef(mCx) = mSavedJSContextOptions;
       mErrorResult.MightThrowJSException();
+      MOZ_ASSERT(mAutoEntryScript->OwnsErrorReporting());
       if (needToDealWithException) {
         JS::Rooted<JS::Value> exn(mCx);
-        if (JS_GetPendingException(mCx, &exn) &&
+        if (mAutoEntryScript->PeekException(&exn) &&
             ShouldRethrowException(exn)) {
+          mAutoEntryScript->ClearException();
+          MOZ_ASSERT(!mAutoEntryScript->HasException());
           mErrorResult.ThrowJSException(mCx, exn);
-          JS_ClearPendingException(mCx);
           needToDealWithException = false;
         }
       }
     }
 
     if (needToDealWithException) {
       // Either we're supposed to report our exceptions, or we're supposed to
-      // re-throw them but we failed to JS_GetPendingException.  Either way,
+      // re-throw them but we failed to get the exception value.  Either way,
       // just report the pending exception, if any.
       //
       // We don't use nsJSUtils::ReportPendingException here because all it
       // does at this point is JS_SaveFrameChain and enter a compartment around
       // a JS_ReportPendingException call.  But our mAutoEntryScript should
       // already do a JS_SaveFrameChain and we are already in the compartment
       // we want to be in, so all nsJSUtils::ReportPendingException would do is
       // screw up our compartment, which is exactly what we do not want.
       //
       // XXXbz FIXME: bug 979525 means we don't always JS_SaveFrameChain here,
-      // so we need to go ahead and do that.
+      // so we need to go ahead and do that.  This is also the reason we don't
+      // just rely on ~AutoJSAPI reporting the exception for us.  I think if we
+      // didn't need to JS_SaveFrameChain here, we could just rely on that.
       JS::Rooted<JSObject*> oldGlobal(mCx, JS::CurrentGlobalOrNull(mCx));
       MOZ_ASSERT(oldGlobal, "How can we not have a global here??");
       bool saved = JS_SaveFrameChain(mCx);
       // Make sure the JSAutoCompartment goes out of scope before the
       // JS_RestoreFrameChain call!
       {
         JSAutoCompartment ac(mCx, oldGlobal);
         MOZ_ASSERT(!JS::DescribeScriptedCaller(mCx),
                    "Our comment above about JS_SaveFrameChain having been "
                    "called is a lie?");
-        JS_ReportPendingException(mCx);
+        // Note that we don't JS_ReportPendingException here because we want to
+        // go through our AutoEntryScript's reporting mechanism instead, since
+        // it currently owns error reporting.
+        mAutoEntryScript->ReportException();
       }
       if (saved) {
         JS_RestoreFrameChain(mCx);
       }
     }
   }
 
   mAutoIncumbentScript.reset();
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -21,17 +21,16 @@
 #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/dom/ScriptSettings.h"
-#include "nsContentUtils.h"
 #include "nsWrapperCache.h"
 #include "nsJSEnvironment.h"
 #include "xpcpublic.h"
 #include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -256,17 +255,16 @@ protected:
     // we pop the JSContext. Though in practice we'll often manually order
     // those two things.
     Maybe<JSAutoCompartment> mAc;
 
     // An ErrorResult to possibly re-throw exceptions on and whether
     // we should re-throw them.
     ErrorResult& mErrorResult;
     const ExceptionHandling mExceptionHandling;
-    JS::ContextOptions mSavedJSContextOptions;
     const bool mIsMainThread;
   };
 };
 
 template<class WebIDLCallbackT, class XPCOMCallbackT>
 class CallbackObjectHolder;
 
 template<class T, class U>
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -86,8 +86,9 @@ MSG_DEF(MSG_INVALID_KEYFRAME_OFFSETS, 0,
 MSG_DEF(MSG_ILLEGAL_PROMISE_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Non-constructor value passed to NewPromiseCapability.")
 MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
 MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
 MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
 MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
 MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
 MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
 MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
+MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -59,62 +59,127 @@ private:
 /*
  * Various typed array classes for argument conversion.  We have a base class
  * that has a way of initializing a TypedArray from an existing typed array, and
  * a subclass of the base class that supports creation of a relevant typed array
  * or array buffer object.
  */
 template<typename T,
          JSObject* UnwrapArray(JSObject*),
-         void GetLengthAndData(JSObject*, uint32_t*, T**)>
+         void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*, T**)>
 struct TypedArray_base : public TypedArrayObjectStorage {
   typedef T element_type;
 
   TypedArray_base()
     : mData(nullptr),
       mLength(0),
+      mShared(false),
       mComputed(false)
   {
   }
 
   TypedArray_base(TypedArray_base&& aOther)
     : TypedArrayObjectStorage(Move(aOther)),
       mData(aOther.mData),
       mLength(aOther.mLength),
+      mShared(aOther.mShared),
       mComputed(aOther.mComputed)
   {
     aOther.mData = nullptr;
     aOther.mLength = 0;
+    aOther.mShared = false;
     aOther.mComputed = false;
   }
 
 private:
   mutable T* mData;
   mutable uint32_t mLength;
+  mutable bool mShared;
   mutable bool mComputed;
 
 public:
   inline bool Init(JSObject* obj)
   {
     MOZ_ASSERT(!inited());
     mTypedObj = mWrappedObj = UnwrapArray(obj);
     return inited();
   }
 
   inline bool inited() const {
     return !!mTypedObj;
   }
 
+  // About shared memory:
+  //
+  // Any DOM TypedArray as well as any DOM ArrayBufferView that does
+  // not represent a JS DataView can map the memory of either a JS
+  // ArrayBuffer or a JS SharedArrayBuffer.  (DataView cannot view
+  // shared memory.)  If the TypedArray maps a SharedArrayBuffer the
+  // Length() and Data() accessors on the DOM view will return zero
+  // and nullptr; to get the actual length and data, call the
+  // LengthAllowShared() and DataAllowShared() accessors instead.
+  //
+  // Two methods are available for determining if a DOM view maps
+  // shared memory.  The IsShared() method is cheap and can be called
+  // if the view has been computed; the JS_GetTypedArraySharedness()
+  // method is slightly more expensive and can be called on the Obj()
+  // value if the view may not have been computed and if the value is
+  // known to represent a JS TypedArray.
+  //
+  // (Just use JS_IsSharedArrayBuffer() to test if any object is of
+  // that type.)
+  //
+  // Code that elects to allow views that map shared memory to be used
+  // -- ie, code that "opts in to shared memory" -- should generally
+  // not access the raw data buffer with standard C++ mechanisms as
+  // that creates the possibility of C++ data races, which is
+  // undefined behavior.  The JS engine will eventually export (bug
+  // 1225033) a suite of methods that avoid undefined behavior.
+  //
+  // Callers of Obj() that do not opt in to shared memory can produce
+  // better diagnostics by checking whether the JSObject in fact maps
+  // shared memory and throwing an error if it does.  However, it is
+  // safe to use the value of Obj() without such checks.
+  //
+  // The DOM TypedArray abstraction prevents the underlying buffer object
+  // from being accessed directly, but JS_GetArrayBufferViewBuffer(Obj())
+  // will obtain the buffer object.  Code that calls that function must
+  // not assume the returned buffer is an ArrayBuffer.  That is guarded
+  // against by an out parameter on that call that communicates the
+  // sharedness of the buffer.
+  //
+  // Finally, note that the buffer memory of a SharedArrayBuffer is
+  // not detachable.
+
+  inline bool IsShared() const {
+    MOZ_ASSERT(mComputed);
+    return mShared;
+  }
+
   inline T *Data() const {
     MOZ_ASSERT(mComputed);
+    if (mShared)
+      return nullptr;
+    return mData;
+  }
+
+  inline T *DataAllowShared() const {
+    MOZ_ASSERT(mComputed);
     return mData;
   }
 
   inline uint32_t Length() const {
     MOZ_ASSERT(mComputed);
+    if (mShared)
+      return 0;
+    return mLength;
+  }
+
+  inline uint32_t LengthAllowShared() const {
+    MOZ_ASSERT(mComputed);
     return mLength;
   }
 
   inline JSObject *Obj() const {
     MOZ_ASSERT(inited());
     return mWrappedObj;
   }
 
@@ -123,32 +188,34 @@ public:
     return JS_WrapObject(cx,
       JS::MutableHandle<JSObject*>::fromMarkedLocation(&mWrappedObj));
   }
 
   inline void ComputeLengthAndData() const
   {
     MOZ_ASSERT(inited());
     MOZ_ASSERT(!mComputed);
-    GetLengthAndData(mTypedObj, &mLength, &mData);
+    GetLengthAndDataAndSharedness(mTypedObj, &mLength, &mShared, &mData);
     mComputed = true;
   }
 
 private:
   TypedArray_base(const TypedArray_base&) = delete;
 };
 
 template<typename T,
          JSObject* UnwrapArray(JSObject*),
-         T* GetData(JSObject*, const JS::AutoCheckCannotGC&),
-         void GetLengthAndData(JSObject*, uint32_t*, T**),
+         T* GetData(JSObject*, bool* isShared, const JS::AutoCheckCannotGC&),
+         void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*, T**),
          JSObject* CreateNew(JSContext*, uint32_t)>
-struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
+struct TypedArray
+  : public TypedArray_base<T, UnwrapArray, GetLengthAndDataAndSharedness>
+{
 private:
-  typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
+  typedef TypedArray_base<T, UnwrapArray, GetLengthAndDataAndSharedness> Base;
 
 public:
   TypedArray()
     : Base()
   {}
 
   TypedArray(TypedArray&& aOther)
     : Base(Move(aOther))
@@ -176,32 +243,39 @@ private:
   static inline JSObject*
   CreateCommon(JSContext* cx, uint32_t length, const T* data) {
     JSObject* obj = CreateNew(cx, length);
     if (!obj) {
       return nullptr;
     }
     if (data) {
       JS::AutoCheckCannotGC nogc;
-      T* buf = static_cast<T*>(GetData(obj, nogc));
+      bool isShared;
+      T* buf = static_cast<T*>(GetData(obj, &isShared, nogc));
+      // Data will not be shared, until a construction protocol exists
+      // for constructing shared data.
+      MOZ_ASSERT(!isShared);
       memcpy(buf, data, length*sizeof(T));
     }
     return obj;
   }
 
   TypedArray(const TypedArray&) = delete;
 };
 
 template<JSObject* UnwrapArray(JSObject*),
-         void GetLengthAndData(JSObject*, uint32_t*, uint8_t**),
+         void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*,
+                                            uint8_t**),
          js::Scalar::Type GetViewType(JSObject*)>
-struct ArrayBufferView_base : public TypedArray_base<uint8_t, UnwrapArray,
-                                                     GetLengthAndData> {
+struct ArrayBufferView_base
+  : public TypedArray_base<uint8_t, UnwrapArray, GetLengthAndDataAndSharedness>
+{
 private:
-  typedef TypedArray_base<uint8_t, UnwrapArray, GetLengthAndData> Base;
+  typedef TypedArray_base<uint8_t, UnwrapArray, GetLengthAndDataAndSharedness>
+          Base;
 
 public:
   ArrayBufferView_base()
     : Base()
   {
   }
 
   ArrayBufferView_base(ArrayBufferView_base&& aOther)
@@ -262,47 +336,16 @@ typedef TypedArray<double, js::UnwrapFlo
 typedef ArrayBufferView_base<js::UnwrapArrayBufferView,
                              js::GetArrayBufferViewLengthAndData,
                              JS_GetArrayBufferViewType>
         ArrayBufferView;
 typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
                    js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
         ArrayBuffer;
 
-typedef TypedArray<int8_t, js::UnwrapSharedInt8Array, JS_GetSharedInt8ArrayData,
-                   js::GetSharedInt8ArrayLengthAndData, JS_NewSharedInt8Array>
-        SharedInt8Array;
-typedef TypedArray<uint8_t, js::UnwrapSharedUint8Array, JS_GetSharedUint8ArrayData,
-                   js::GetSharedUint8ArrayLengthAndData, JS_NewSharedUint8Array>
-        SharedUint8Array;
-typedef TypedArray<uint8_t, js::UnwrapSharedUint8ClampedArray, JS_GetSharedUint8ClampedArrayData,
-                   js::GetSharedUint8ClampedArrayLengthAndData, JS_NewSharedUint8ClampedArray>
-        SharedUint8ClampedArray;
-typedef TypedArray<int16_t, js::UnwrapSharedInt16Array, JS_GetSharedInt16ArrayData,
-                   js::GetSharedInt16ArrayLengthAndData, JS_NewSharedInt16Array>
-        SharedInt16Array;
-typedef TypedArray<uint16_t, js::UnwrapSharedUint16Array, JS_GetSharedUint16ArrayData,
-                   js::GetSharedUint16ArrayLengthAndData, JS_NewSharedUint16Array>
-        SharedUint16Array;
-typedef TypedArray<int32_t, js::UnwrapSharedInt32Array, JS_GetSharedInt32ArrayData,
-                   js::GetSharedInt32ArrayLengthAndData, JS_NewSharedInt32Array>
-        SharedInt32Array;
-typedef TypedArray<uint32_t, js::UnwrapSharedUint32Array, JS_GetSharedUint32ArrayData,
-                   js::GetSharedUint32ArrayLengthAndData, JS_NewSharedUint32Array>
-        SharedUint32Array;
-typedef TypedArray<float, js::UnwrapSharedFloat32Array, JS_GetSharedFloat32ArrayData,
-                   js::GetSharedFloat32ArrayLengthAndData, JS_NewSharedFloat32Array>
-        SharedFloat32Array;
-typedef TypedArray<double, js::UnwrapSharedFloat64Array, JS_GetSharedFloat64ArrayData,
-                   js::GetSharedFloat64ArrayLengthAndData, JS_NewSharedFloat64Array>
-        SharedFloat64Array;
-typedef ArrayBufferView_base<js::UnwrapSharedArrayBufferView,
-                             js::GetSharedArrayBufferViewLengthAndData,
-                             JS_GetSharedArrayBufferViewType>
-        SharedArrayBufferView;
 typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
                    js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
         SharedArrayBuffer;
 
 // A class for converting an nsTArray to a TypedArray
 // Note: A TypedArrayCreator must not outlive the nsTArray it was created from.
 //       So this is best used to pass from things that understand nsTArray to
 //       things that understand TypedArray, as with Promise::ArgumentToJSValue.
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1829,25 +1829,19 @@ class IDLType(IDLObject):
         return False
 
     def isArrayBufferView(self):
         return False
 
     def isSharedArrayBuffer(self):
         return False
 
-    def isSharedArrayBufferView(self):
-        return False
-
     def isTypedArray(self):
         return False
 
-    def isSharedTypedArray(self):
-        return False
-
     def isCallbackInterface(self):
         return False
 
     def isNonCallbackInterface(self):
         return False
 
     def isGeckoInterface(self):
         """ Returns a boolean indicating whether this type is an 'interface'
@@ -1858,19 +1852,17 @@ class IDLType(IDLObject):
 
     def isSpiderMonkeyInterface(self):
         """ Returns a boolean indicating whether this type is an 'interface'
             type that is implemented in Spidermonkey.  At the moment, this
             only returns true for the types from the TypedArray spec. """
         return self.isInterface() and (self.isArrayBuffer() or
                                        self.isArrayBufferView() or
                                        self.isSharedArrayBuffer() or
-                                       self.isSharedArrayBufferView() or
-                                       self.isTypedArray() or
-                                       self.isSharedTypedArray())
+                                       self.isTypedArray())
 
     def isDictionary(self):
         return False
 
     def isInterface(self):
         return False
 
     def isAny(self):
@@ -2047,25 +2039,19 @@ class IDLNullableType(IDLType):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
 
     def isSharedArrayBuffer(self):
         return self.inner.isSharedArrayBuffer()
 
-    def isSharedArrayBufferView(self):
-        return self.inner.isSharedArrayBufferView()
-
     def isTypedArray(self):
         return self.inner.isTypedArray()
 
-    def isSharedTypedArray(self):
-        return self.inner.isSharedTypedArray()
-
     def isDictionary(self):
         return self.inner.isDictionary()
 
     def isInterface(self):
         return self.inner.isInterface()
 
     def isPromise(self):
         return self.inner.isPromise()
@@ -2562,25 +2548,19 @@ class IDLTypedefType(IDLType):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
 
     def isSharedArrayBuffer(self):
         return self.inner.isSharedArrayBuffer()
 
-    def isSharedArrayBufferView(self):
-        return self.inner.isSharedArrayBufferView()
-
     def isTypedArray(self):
         return self.inner.isTypedArray()
 
-    def isSharedTypedArray(self):
-        return self.inner.isSharedTypedArray()
-
     def isInterface(self):
         return self.inner.isInterface()
 
     def isCallbackInterface(self):
         return self.inner.isCallbackInterface()
 
     def isNonCallbackInterface(self):
         return self.inner.isNonCallbackInterface()
@@ -2840,35 +2820,25 @@ class IDLBuiltinType(IDLType):
         'usvstring',
         'object',
         'date',
         'void',
         # Funny stuff
         'ArrayBuffer',
         'ArrayBufferView',
         'SharedArrayBuffer',
-        'SharedArrayBufferView',
         'Int8Array',
         'Uint8Array',
         'Uint8ClampedArray',
         'Int16Array',
         'Uint16Array',
         'Int32Array',
         'Uint32Array',
         'Float32Array',
-        'Float64Array',
-        'SharedInt8Array',
-        'SharedUint8Array',
-        'SharedUint8ClampedArray',
-        'SharedInt16Array',
-        'SharedUint16Array',
-        'SharedInt32Array',
-        'SharedUint32Array',
-        'SharedFloat32Array',
-        'SharedFloat64Array'
+        'Float64Array'
         )
 
     TagLookup = {
         Types.byte: IDLType.Tags.int8,
         Types.octet: IDLType.Tags.uint8,
         Types.short: IDLType.Tags.int16,
         Types.unsigned_short: IDLType.Tags.uint16,
         Types.long: IDLType.Tags.int32,
@@ -2885,35 +2855,25 @@ class IDLBuiltinType(IDLType):
         Types.bytestring: IDLType.Tags.bytestring,
         Types.usvstring: IDLType.Tags.usvstring,
         Types.object: IDLType.Tags.object,
         Types.date: IDLType.Tags.date,
         Types.void: IDLType.Tags.void,
         Types.ArrayBuffer: IDLType.Tags.interface,
         Types.ArrayBufferView: IDLType.Tags.interface,
         Types.SharedArrayBuffer: IDLType.Tags.interface,
-        Types.SharedArrayBufferView: IDLType.Tags.interface,
         Types.Int8Array: IDLType.Tags.interface,
         Types.Uint8Array: IDLType.Tags.interface,
         Types.Uint8ClampedArray: IDLType.Tags.interface,
         Types.Int16Array: IDLType.Tags.interface,
         Types.Uint16Array: IDLType.Tags.interface,
         Types.Int32Array: IDLType.Tags.interface,
         Types.Uint32Array: IDLType.Tags.interface,
         Types.Float32Array: IDLType.Tags.interface,
-        Types.Float64Array: IDLType.Tags.interface,
-        Types.SharedInt8Array: IDLType.Tags.interface,
-        Types.SharedUint8Array: IDLType.Tags.interface,
-        Types.SharedUint8ClampedArray: IDLType.Tags.interface,
-        Types.SharedInt16Array: IDLType.Tags.interface,
-        Types.SharedUint16Array: IDLType.Tags.interface,
-        Types.SharedInt32Array: IDLType.Tags.interface,
-        Types.SharedUint32Array: IDLType.Tags.interface,
-        Types.SharedFloat32Array: IDLType.Tags.interface,
-        Types.SharedFloat64Array: IDLType.Tags.interface
+        Types.Float64Array: IDLType.Tags.interface
     }
 
     def __init__(self, location, name, type):
         IDLType.__init__(self, location, name)
         self.builtin = True
         self._typeTag = type
 
     def isPrimitive(self):
@@ -2946,37 +2906,28 @@ class IDLBuiltinType(IDLType):
         return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
 
     def isArrayBufferView(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
 
     def isSharedArrayBuffer(self):
         return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer
 
-    def isSharedArrayBufferView(self):
-        return self._typeTag == IDLBuiltinType.Types.SharedArrayBufferView
-
     def isTypedArray(self):
         return (self._typeTag >= IDLBuiltinType.Types.Int8Array and
                 self._typeTag <= IDLBuiltinType.Types.Float64Array)
 
-    def isSharedTypedArray(self):
-        return (self._typeTag >= IDLBuiltinType.Types.SharedInt8Array and
-                self._typeTag <= IDLBuiltinType.Types.SharedFloat64Array)
-
     def isInterface(self):
         # TypedArray things are interface types per the TypedArray spec,
         # but we handle them as builtins because SpiderMonkey implements
         # all of it internally.
         return (self.isArrayBuffer() or
                 self.isArrayBufferView() or
                 self.isSharedArrayBuffer() or
-                self.isSharedArrayBufferView() or
-                self.isTypedArray() or
-                self.isSharedTypedArray())
+                self.isTypedArray())
 
     def isNonCallbackInterface(self):
         # All the interfaces we can be are non-callback
         return self.isInterface()
 
     def isFloat(self):
         return (self._typeTag == IDLBuiltinType.Types.float or
                 self._typeTag == IDLBuiltinType.Types.double or
@@ -3044,25 +2995,21 @@ class IDLBuiltinType(IDLType):
                  # ArrayBuffer is distinguishable from everything
                  # that's not an ArrayBuffer or a callback interface
                  (self.isArrayBuffer() and not other.isArrayBuffer()) or
                  (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
                  # ArrayBufferView is distinguishable from everything
                  # that's not an ArrayBufferView or typed array.
                  (self.isArrayBufferView() and not other.isArrayBufferView() and
                   not other.isTypedArray()) or
-                 (self.isSharedArrayBufferView() and not other.isSharedArrayBufferView() and
-                  not other.isSharedTypedArray()) or
                  # Typed arrays are distinguishable from everything
                  # except ArrayBufferView and the same type of typed
                  # array
                  (self.isTypedArray() and not other.isArrayBufferView() and not
-                  (other.isTypedArray() and other.name == self.name)) or
-                 (self.isSharedTypedArray() and not other.isSharedArrayBufferView() and not
-                  (other.isSharedTypedArray() and other.name == self.name)))))
+                  (other.isTypedArray() and other.name == self.name)))))
 
     def _getDependentObjects(self):
         return set()
 
 BuiltinTypes = {
     IDLBuiltinType.Types.byte:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
                        IDLBuiltinType.Types.byte),
@@ -3127,19 +3074,16 @@ BuiltinTypes = {
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer",
                        IDLBuiltinType.Types.ArrayBuffer),
     IDLBuiltinType.Types.ArrayBufferView:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView",
                        IDLBuiltinType.Types.ArrayBufferView),
     IDLBuiltinType.Types.SharedArrayBuffer:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBuffer",
                        IDLBuiltinType.Types.SharedArrayBuffer),
-    IDLBuiltinType.Types.SharedArrayBufferView:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBufferView",
-                       IDLBuiltinType.Types.SharedArrayBufferView),
     IDLBuiltinType.Types.Int8Array:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array",
                        IDLBuiltinType.Types.Int8Array),
     IDLBuiltinType.Types.Uint8Array:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8Array",
                        IDLBuiltinType.Types.Uint8Array),
     IDLBuiltinType.Types.Uint8ClampedArray:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8ClampedArray",
@@ -3156,44 +3100,17 @@ BuiltinTypes = {
     IDLBuiltinType.Types.Uint32Array:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint32Array",
                        IDLBuiltinType.Types.Uint32Array),
     IDLBuiltinType.Types.Float32Array:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float32Array",
                        IDLBuiltinType.Types.Float32Array),
     IDLBuiltinType.Types.Float64Array:
         IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array",
-                       IDLBuiltinType.Types.Float64Array),
-    IDLBuiltinType.Types.SharedInt8Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt8Array",
-                       IDLBuiltinType.Types.SharedInt8Array),
-    IDLBuiltinType.Types.SharedUint8Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8Array",
-                       IDLBuiltinType.Types.SharedUint8Array),
-    IDLBuiltinType.Types.SharedUint8ClampedArray:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8ClampedArray",
-                       IDLBuiltinType.Types.SharedUint8ClampedArray),
-    IDLBuiltinType.Types.SharedInt16Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt16Array",
-                       IDLBuiltinType.Types.SharedInt16Array),
-    IDLBuiltinType.Types.SharedUint16Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint16Array",
-                       IDLBuiltinType.Types.SharedUint16Array),
-    IDLBuiltinType.Types.SharedInt32Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt32Array",
-                       IDLBuiltinType.Types.SharedInt32Array),
-    IDLBuiltinType.Types.SharedUint32Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint32Array",
-                       IDLBuiltinType.Types.SharedUint32Array),
-    IDLBuiltinType.Types.SharedFloat32Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat32Array",
-                       IDLBuiltinType.Types.SharedFloat32Array),
-    IDLBuiltinType.Types.SharedFloat64Array:
-        IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat64Array",
-                       IDLBuiltinType.Types.SharedFloat64Array)
+                       IDLBuiltinType.Types.Float64Array)
 }
 
 
 integerTypeSizes = {
     IDLBuiltinType.Types.byte: (-128, 127),
     IDLBuiltinType.Types.octet:  (0, 255),
     IDLBuiltinType.Types.short: (-32768, 32767),
     IDLBuiltinType.Types.unsigned_short: (0, 65535),
@@ -6526,17 +6443,17 @@ class Parser(Tokenizer):
         self._filename = None
 
         self.parser.parse(lexer=self.lexer, tracking=True)
 
     def _installBuiltins(self, scope):
         assert isinstance(scope, IDLScope)
 
         # xrange omits the last value.
-        for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.SharedFloat64Array + 1):
+        for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
             builtin = BuiltinTypes[x]
             name = builtin.name
             typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
 
     @ staticmethod
     def handleModifiers(type, modifiers):
         for (modifier, modifierLocation) in modifiers:
             assert (modifier == IDLMethod.TypeSuffixModifier.QMark or
@@ -6629,17 +6546,16 @@ class Parser(Tokenizer):
 
     def reset(self):
         return Parser(lexer=self.lexer)
 
     # Builtin IDL defined by WebIDL
     _builtins = """
         typedef unsigned long long DOMTimeStamp;
         typedef (ArrayBufferView or ArrayBuffer) BufferSource;
-        typedef (SharedArrayBufferView or SharedArrayBuffer) SharedBufferSource;
     """
 
 
 def main():
     # Parse arguments.
     from optparse import OptionParser
     usageString = "usage: %prog [options] files"
     o = OptionParser(usage=usageString)
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -156,35 +156,35 @@ def WebIDLTest(parser, harness):
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
                  "long[]", "short[]", "Date", "Date?", "any",
                  "Promise<any>", "Promise<any>?",
-                 "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "SharedArrayBufferView",
-                 "Uint8Array", "SharedUint8Array", "Uint16Array", "SharedUint16Array" ]
+                 "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
+                 "Uint8Array", "Uint16Array" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2 and
                 (a != "any" and a != "Promise<any>" and a != "Promise<any>?")]
     numerics = [ "long", "short", "long?", "short?" ]
     booleans = [ "boolean", "boolean?" ]
     primitives = numerics + booleans
     nonNumerics = allBut(argTypes, numerics)
     nonBooleans = allBut(argTypes, booleans)
     strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ]
     nonStrings = allBut(argTypes, strings)
     nonObjects = primitives + strings
     objects = allBut(argTypes, nonObjects )
     bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"]
-    sharedBufferSourceTypes = ["SharedArrayBuffer", "SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array"]
+    sharedBufferSourceTypes = ["SharedArrayBuffer"]
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
                    "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
     nullables = ["long?", "short?", "boolean?", "Interface?",
                  "CallbackInterface?", "optional Dict", "optional Dict2",
                  "Date?", "any", "Promise<any>?"]
     dates = [ "Date", "Date?" ]
     sequences = [ "sequence<long>", "sequence<short>" ]
     arrays = [ "long[]", "short[]" ]
@@ -242,19 +242,16 @@ def WebIDLTest(parser, harness):
     setDistinguishable("any", [])
     setDistinguishable("Promise<any>", [])
     setDistinguishable("Promise<any>?", [])
     setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"]))
     setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"]))
     setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
     setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"]))
     setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"]))
-    setDistinguishable("SharedArrayBufferView", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array", "object"]))
-    setDistinguishable("SharedUint8Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "object"]))
-    setDistinguishable("SharedUint16Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint16Array", "object"]))
 
     def areDistinguishable(type1, type2):
         return data[type1].get(type2, False)
 
     def checkDistinguishability(parser, type1, type2):
         idlTemplate = """
           enum Enum { "a", "b" };
           enum Enum2 { "c", "d" };
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -59,14 +59,15 @@ skip-if = debug == false
 skip-if = debug == false
 [test_exception_options_from_jsimplemented.html]
 skip-if = debug == false
 [test_promise_rejections_from_jsimplemented.html]
 skip-if = debug == false
 [test_worker_UnwrapArg.html]
 [test_unforgeablesonexpando.html]
 [test_crossOriginWindowSymbolAccess.html]
+[test_callback_exceptions.html]
 [test_bug1123516_maplikesetlike.html]
 skip-if = debug == false
 [test_jsimplemented_eventhandler.html]
 skip-if = debug == false
 [test_iterable.html]
 skip-if = debug == false
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_callback_exceptions.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for ...</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+promise_test(function(t) {
+  var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, JSON.parse);
+  return promise_rejects(t, new SyntaxError,
+                         Promise.resolve().then(iterator.nextNode.bind(iterator)));
+}, "Trying to use JSON.parse as filter should throw a catchable SyntaxError exception even when the filter is invoked async");
+
+promise_test(function(t) {
+  return promise_rejects(t, new SyntaxError, Promise.resolve('{').then(JSON.parse));
+}, "Trying to use JSON.parse as a promise callback should allow the next promise to handle the resulting exception.");
+</script>
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -8,16 +8,17 @@
 #include "BroadcastChannelChild.h"
 #include "mozilla/dom/BroadcastChannelBinding.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
+#include "nsContentUtils.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
 #include "nsIBFCacheEntry.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 
 #ifdef XP_WIN
--- a/dom/cache/CacheStorage.cpp
+++ b/dom/cache/CacheStorage.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/dom/cache/Feature.h"
 #include "mozilla/dom/cache/PCacheChild.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsIGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsURLParsers.h"
 #include "WorkerPrivate.h"
 
 namespace mozilla {
 namespace dom {
--- a/dom/cache/PrincipalVerifier.cpp
+++ b/dom/cache/PrincipalVerifier.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/dom/cache/PrincipalVerifier.h"
 
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/cache/ManagerId.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
+#include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5203,17 +5203,19 @@ CanvasRenderingContext2D::GetImageDataAr
   uint32_t srcStride;
 
   if (readback) {
     srcStride = rawData.mStride;
     src = rawData.mData + srcReadRect.y * srcStride + srcReadRect.x * 4;
   }
 
   JS::AutoCheckCannotGC nogc;
-  uint8_t* data = JS_GetUint8ClampedArrayData(darray, nogc);
+  bool isShared;
+  uint8_t* data = JS_GetUint8ClampedArrayData(darray, &isShared, nogc);
+  MOZ_ASSERT(!isShared);        // Should not happen, data was created above
   if (!readback) {
     src = data;
     srcStride = aWidth * 4;
   }
 
   uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
 
   if (mOpaque) {
--- a/dom/canvas/ImageData.cpp
+++ b/dom/canvas/ImageData.cpp
@@ -84,16 +84,21 @@ ImageData::Constructor(const GlobalObjec
     return nullptr;
   }
   uint32_t height = length / aWidth;
   if (length != aWidth * height ||
       (aHeight.WasPassed() && aHeight.Value() != height)) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
+  if (JS_GetTypedArraySharedness(aData.Obj())) {
+    // Throw if the object is mapping shared memory (must opt in).
+    aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of ImageData constructor"));
+    return nullptr;
+  }
   RefPtr<ImageData> imageData = new ImageData(aWidth, height, *aData.Obj());
   return imageData.forget();
 }
 
 void
 ImageData::HoldData()
 {
   mozilla::HoldJSObjects(this);
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -13,17 +13,16 @@ namespace mozilla {
 class ErrorResult;
 class WebGLSampler;
 class WebGLSync;
 class WebGLTransformFeedback;
 class WebGLVertexArrayObject;
 namespace dom {
 class OwningUnsignedLongOrUint32ArrayOrBoolean;
 class OwningWebGLBufferOrLongLong;
-class ArrayBufferViewOrSharedArrayBufferView;
 } // namespace dom
 
 class WebGL2Context
     : public WebGLContext
 {
 public:
 
     virtual ~WebGL2Context();
@@ -92,21 +91,21 @@ public:
 
     void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height);
     void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height, GLsizei depth);
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
                     GLenum unpackType,
-                    const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels);
+                    const dom::Nullable<dom::ArrayBufferView>& pixels);
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
+                       const dom::Nullable<dom::ArrayBufferView>& pixels,
                        ErrorResult& out_rv);
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
                        dom::ImageData* data, ErrorResult& out_rv);
 protected:
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
                        dom::Element* elem, ErrorResult* const out_rv);
@@ -121,21 +120,21 @@ public:
     }
 
     void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                            GLint zOffset, GLint x, GLint y, GLsizei width,
                            GLsizei height);
     void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLsizei depth,
                               GLint border,
-                              const dom::ArrayBufferViewOrSharedArrayBufferView& data);
+                              const dom::ArrayBufferView& data);
     void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLint zOffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum sizedUnpackFormat,
-                                 const dom::ArrayBufferViewOrSharedArrayBufferView& data);
+                                 const dom::ArrayBufferView& data);
 
 
     // -------------------------------------------------------------------------
     // Programs and shaders - WebGL2ContextPrograms.cpp
     GLint GetFragDataLocation(WebGLProgram* program, const nsAString& name);
 
 
     // -------------------------------------------------------------------------
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -166,17 +166,17 @@ WebGL2Context::GetBufferSubDataT(GLenum 
     WebGLBuffer* boundBuffer = bufferSlot.get();
     if (!boundBuffer)
         return ErrorInvalidOperation("getBufferSubData: no buffer bound");
 
     // If offset + returnedData.byteLength would extend beyond the end
     // of the buffer an INVALID_VALUE error is generated.
     data.ComputeLengthAndData();
 
-    CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.Length();
+    CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
     if (!neededByteLength.isValid()) {
         ErrorInvalidValue("getBufferSubData: Integer overflow computing the needed"
                           " byte length.");
         return;
     }
 
     if (neededByteLength.value() > boundBuffer->ByteLength()) {
         ErrorInvalidValue("getBufferSubData: Not enough data. Operation requires"
@@ -208,18 +208,19 @@ WebGL2Context::GetBufferSubDataT(GLenum 
 
     /* If the buffer is written and read sequentially by other
      * operations and getBufferSubData, it is the responsibility of
      * the WebGL API to ensure that data are access
      * consistently. This applies even if the buffer is currently
      * bound to a transform feedback binding point.
      */
 
-    void* ptr = gl->fMapBufferRange(target, offset, data.Length(), LOCAL_GL_MAP_READ_BIT);
-    memcpy(data.Data(), ptr, data.Length());
+    void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(), LOCAL_GL_MAP_READ_BIT);
+    // Warning: Possibly shared memory.  See bug 1225033.
+    memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
     gl->fUnmapBuffer(target);
 
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
         BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
     }
 }
 
 void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -40,17 +40,17 @@ WebGL2Context::TexStorage3D(GLenum rawTe
 
     tex->TexStorage(funcName, target, levels, internalFormat, width, height, depth);
 }
 
 void
 WebGL2Context::TexImage3D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
                           GLsizei width, GLsizei height, GLsizei depth, GLint border,
                           GLenum unpackFormat, GLenum unpackType,
-                          const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
+                          const dom::Nullable<dom::ArrayBufferView>& maybeView)
 {
     const char funcName[] = "texImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -66,17 +66,17 @@ WebGL2Context::TexImage3D(GLenum rawTexI
                        yOffset, zOffset, width, height, depth, border, unpackFormat,
                        unpackType, maybeView);
 }
 
 void
 WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                              GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
                              GLsizei depth, GLenum unpackFormat, GLenum unpackType,
-                             const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+                             const dom::Nullable<dom::ArrayBufferView>& maybeView,
                              ErrorResult& /*out_rv*/)
 {
     const char funcName[] = "texSubImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
@@ -138,17 +138,17 @@ WebGL2Context::TexSubImage3D(GLenum rawT
     tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
                        yOffset, zOffset, unpackFormat, unpackType, elem, out_rv);
 }
 
 void
 WebGL2Context::CompressedTexImage3D(GLenum rawTexImageTarget, GLint level,
                                     GLenum internalFormat, GLsizei width, GLsizei height,
                                     GLsizei depth, GLint border,
-                                    const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                    const dom::ArrayBufferView& view)
 {
     const char funcName[] = "compressedTexImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -160,17 +160,17 @@ WebGL2Context::CompressedTexImage3D(GLen
                             border, view);
 }
 
 void
 WebGL2Context::CompressedTexSubImage3D(GLenum rawTexImageTarget, GLint level,
                                        GLint xOffset, GLint yOffset, GLint zOffset,
                                        GLsizei width, GLsizei height, GLsizei depth,
                                        GLenum sizedUnpackFormat,
-                                       const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                       const dom::ArrayBufferView& view)
 {
     const char funcName[] = "compressedTexSubImage3D";
     const uint8_t funcDims = 3;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -649,16 +649,17 @@ WebGLContext::CreateAndInitGL(bool force
     bool disableANGLE = gfxPrefs::WebGLDisableANGLE();
 
     if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
         disableANGLE = true;
 
     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);
 
     MOZ_ASSERT(!gl);
 
     if (preferEGL) {
         if (CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags))
             return true;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -43,17 +43,16 @@
 // Generated
 #include "nsIDOMEventListener.h"
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsIObserver.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsWrapperCache.h"
 #include "nsLayoutUtils.h"
-#include "mozilla/dom/UnionTypes.h"
 
 class nsIDocShell;
 
 /*
  * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
  *   https://bugzilla.mozilla.org/show_bug.cgi?id=686732
  *
  * Exceptions: some of the following values are set to higher values than in the spec because
@@ -106,17 +105,16 @@ class WebGLTransformFeedback;
 class WebGLUniformLocation;
 class WebGLVertexArray;
 
 namespace dom {
 class Element;
 class ImageData;
 class OwningHTMLCanvasElementOrOffscreenCanvas;
 struct WebGLContextAttributes;
-class ArrayBufferViewOrSharedArrayBufferView;
 template<typename> struct Nullable;
 } // namespace dom
 
 namespace gfx {
 class SourceSurface;
 } // namespace gfx
 
 namespace webgl {
@@ -540,17 +538,17 @@ public:
     void PolygonOffset(GLfloat factor, GLfloat units);
 protected:
     bool DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
                                 GLenum destFormat, GLenum destType, void* destBytes,
                                 GLenum auxReadFormat, GLenum auxReadType);
 public:
     void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
                     GLenum format, GLenum type,
-                    const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
+                    const dom::Nullable<dom::ArrayBufferView>& pixels,
                     ErrorResult& rv);
     void RenderbufferStorage(GLenum target, GLenum internalFormat,
                              GLsizei width, GLsizei height);
 protected:
     void RenderbufferStorage_base(const char* funcName, GLenum target,
                                   GLsizei samples, GLenum internalformat,
                                   GLsizei width, GLsizei height);
 public:
@@ -772,33 +770,29 @@ private:
 public:
     void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
     void BufferData(GLenum target, const dom::ArrayBufferView& data,
                     GLenum usage);
     void BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeData,
                     GLenum usage);
     void BufferData(GLenum target, const dom::SharedArrayBuffer& data,
                     GLenum usage);
-    void BufferData(GLenum target, const dom::SharedArrayBufferView& data,
-                    GLenum usage);
 
 private:
     template<typename BufferT>
     void BufferSubDataT(GLenum target, WebGLsizeiptr byteOffset,
                         const BufferT& data);
 
 public:
     void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                        const dom::ArrayBufferView& data);
     void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                        const dom::Nullable<dom::ArrayBuffer>& maybeData);
     void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                        const dom::SharedArrayBuffer& data);
-    void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                       const dom::SharedArrayBufferView& data);
     already_AddRefed<WebGLBuffer> CreateBuffer();
     void DeleteBuffer(WebGLBuffer* buf);
     bool IsBuffer(WebGLBuffer* buf);
 
 protected:
     // bound buffer state
     WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
     WebGLRefPtr<WebGLBuffer> mBoundCopyReadBuffer;
@@ -885,43 +879,43 @@ protected:
                            GLfloat* maybeFloatParam);
 
     virtual bool IsTexParamValid(GLenum pname) const;
 
     // Upload funcs
 public:
     void CompressedTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLint border,
-                              const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+                              const dom::ArrayBufferView& view);
     void CompressedTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
                                  GLint yOffset, GLsizei width, GLsizei height,
-                                 GLenum unpackFormat, const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+                                 GLenum unpackFormat, const dom::ArrayBufferView& view);
 
     void CopyTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                         GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
     void CopyTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
                            GLint yOffset, GLint x, GLint y, GLsizei width,
                            GLsizei height);
 
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                     GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
                     GLenum unpackType,
-                    const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+                    const dom::Nullable<dom::ArrayBufferView>& maybeView,
                     ErrorResult&);
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                     GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
                     ErrorResult&);
     void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
                     GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
                     ErrorResult* const out_error);
 
     void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
                        GLsizei width, GLsizei height, GLenum unpackFormat,
                        GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+                       const dom::Nullable<dom::ArrayBufferView>& maybeView,
                        ErrorResult&);
     void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
                        GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
                        ErrorResult&);
     void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
                        GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
                        ErrorResult* const out_error);
 
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -181,17 +181,16 @@ WebGLContext::BufferData(GLenum target, 
         return ErrorOutOfMemory("bufferData: out of memory");
     }
 }
 
 // BufferT may be one of
 // const dom::ArrayBuffer&
 // const dom::SharedArrayBuffer&
 // const dom::ArrayBufferView&
-// const dom::SharedArrayBufferView&
 template<typename BufferT>
 void
 WebGLContext::BufferDataT(GLenum target,
                           const BufferT& data,
                           GLenum usage)
 {
     if (IsContextLost())
         return;
@@ -200,39 +199,41 @@ WebGLContext::BufferDataT(GLenum target,
         return;
 
     const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     data.ComputeLengthAndData();
 
     // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
     // is like intptr_t.
-    if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
+    if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
         return ErrorOutOfMemory("bufferData: bad size");
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
     WebGLBuffer* boundBuffer = bufferSlot.get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
-    GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
+    // Warning: Possibly shared memory.  See bug 1225033.
+    GLenum error = CheckedBufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
 
     if (error) {
         GenerateWarning("bufferData generated error %s", ErrorName(error));
         return;
     }
 
-    boundBuffer->SetByteLength(data.Length());
-    if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length()))
+    boundBuffer->SetByteLength(data.LengthAllowShared());
+    // Warning: Possibly shared memory.  See bug 1225033.
+    if (!boundBuffer->ElementArrayCacheBufferData(data.DataAllowShared(), data.LengthAllowShared()))
         return ErrorOutOfMemory("bufferData: out of memory");
 }
 
 void
 WebGLContext::BufferData(GLenum target,
                          const dom::SharedArrayBuffer& data,
                          GLenum usage)
 {
@@ -253,28 +254,20 @@ WebGLContext::BufferData(GLenum target,
 
 void
 WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
                          GLenum usage)
 {
     BufferDataT(target, data, usage);
 }
 
-void
-WebGLContext::BufferData(GLenum target, const dom::SharedArrayBufferView& data,
-                         GLenum usage)
-{
-    BufferDataT(target, data, usage);
-}
-
 // BufferT may be one of
 // const dom::ArrayBuffer&
 // const dom::SharedArrayBuffer&
 // const dom::ArrayBufferView&
-// const dom::SharedArrayBufferView&
 template<typename BufferT>
 void
 WebGLContext::BufferSubDataT(GLenum target,
                              WebGLsizeiptr byteOffset,
                              const BufferT& data)
 {
     if (IsContextLost())
         return;
@@ -289,37 +282,39 @@ WebGLContext::BufferSubDataT(GLenum targ
 
     WebGLBuffer* boundBuffer = bufferSlot.get();
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     data.ComputeLengthAndData();
 
     CheckedInt<WebGLsizeiptr> checked_neededByteLength =
-        CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
+        CheckedInt<WebGLsizeiptr>(byteOffset) + data.LengthAllowShared();
 
     if (!checked_neededByteLength.isValid()) {
         ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
                           " byte length.");
         return;
     }
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
         ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
                           " %d bytes, but buffer only has %d bytes.",
                           checked_neededByteLength.value(),
                           boundBuffer->ByteLength());
         return;
     }
 
-    boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(),
-                                                data.Length());
+    // Warning: Possibly shared memory.  See bug 1225033.
+    boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
+                                                data.LengthAllowShared());
 
     MakeContextCurrent();
-    gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
+    // Warning: Possibly shared memory.  See bug 1225033.
+    gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared());
 }
 
 void
 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                             const dom::Nullable<dom::ArrayBuffer>& maybeData)
 {
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
@@ -337,23 +332,16 @@ WebGLContext::BufferSubData(GLenum targe
 
 void
 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                             const dom::ArrayBufferView& data)
 {
     BufferSubDataT(target, byteOffset, data);
 }
 
-void
-WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                            const dom::SharedArrayBufferView& data)
-{
-    BufferSubDataT(target, byteOffset, data);
-}
-
 already_AddRefed<WebGLBuffer>
 WebGLContext::CreateBuffer()
 {
     if (IsContextLost())
         return nullptr;
 
     GLuint buf = 0;
     MakeContextCurrent();
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1364,43 +1364,20 @@ WebGLContext::GetPackSize(uint32_t width
 
     const auto bytesNeeded = startOffset + rowStride * (height - 1) + usedBytesPerRow;
 
     *out_startOffset = startOffset;
     *out_rowStride = rowStride;
     return bytesNeeded;
 }
 
-// This function is temporary, and will be removed once https://bugzilla.mozilla.org/show_bug.cgi?id=1176214 lands, which will
-// collapse the SharedArrayBufferView and ArrayBufferView into one.
-void
-ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
-                     void** const out_data, size_t* const out_length,
-                     js::Scalar::Type* const out_type)
-{
-    if (view.IsArrayBufferView()) {
-        const auto& view2 = view.GetAsArrayBufferView();
-        view2.ComputeLengthAndData();
-
-        *out_length = view2.Length();
-        *out_data = view2.Data();
-        *out_type = JS_GetArrayBufferViewType(view2.Obj());
-    } else {
-        const auto& view2 = view.GetAsSharedArrayBufferView();
-        view2.ComputeLengthAndData();
-        *out_length = view2.Length();
-        *out_data = view2.Data();
-        *out_type = JS_GetSharedArrayBufferViewType(view2.Obj());
-    }
-}
-
 void
 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                          GLenum type,
-                         const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
+                         const dom::Nullable<dom::ArrayBufferView>& pixels,
                          ErrorResult& out_error)
 {
     if (IsContextLost())
         return;
 
     if (mCanvasElement &&
         mCanvasElement->IsWriteOnly() &&
         !nsContentUtils::IsCallerChrome())
@@ -1464,22 +1441,23 @@ WebGLContext::ReadPixels(GLint x, GLint 
         requiredDataType = js::Scalar::Uint16;
         break;
 
     default:
         MOZ_CRASH("bad `type`");
     }
 
     const auto& view = pixels.Value();
+
     // Compute length and data.  Don't reenter after this point, lest the
     // precomputed go out of sync with the instant length/data.
-    void* data;
-    size_t bytesAvailable;
-    js::Scalar::Type dataType;
-    ComputeLengthAndData(view, &data, &bytesAvailable, &dataType);
+    view.ComputeLengthAndData();
+    void* data = view.DataAllowShared();
+    size_t bytesAvailable = view.LengthAllowShared();
+    js::Scalar::Type dataType = JS_GetArrayBufferViewType(view.Obj());
 
     // Check the pixels param type
     if (dataType != requiredDataType)
         return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
 
     CheckedUint32 startOffset;
     CheckedUint32 rowStride;
     const auto bytesNeeded = GetPackSize(width, height, bytesPerPixel, &startOffset,
@@ -1540,16 +1518,17 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     uint32_t readX, readY;
     uint32_t writeX, writeY;
     uint32_t rwWidth, rwHeight;
     Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
     Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
 
     if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
+        // Warning: Possibly shared memory.  See bug 1225033.
         DoReadPixelsAndConvert(x, y, width, height, format, type, data, auxReadFormat,
                                auxReadType);
         return;
     }
 
     // Read request contains out-of-bounds pixels. Unfortunately:
     // GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer":
     // "If any of these pixels lies outside of the window allocated to the current GL
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -310,17 +310,17 @@ WebGLContext::TexParameter_base(GLenum r
 
 ////////////////////
 // TexImage
 
 void
 WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
                          GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
                          GLenum unpackType,
-                         const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+                         const dom::Nullable<dom::ArrayBufferView>& maybeView,
                          ErrorResult&)
 {
     const char funcName[] = "texImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
@@ -389,17 +389,17 @@ WebGLContext::TexImage2D(GLenum rawTexIm
 
 ////////////////////////////////////////
 // TexSubImage
 
 void
 WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
                             GLint yOffset, GLsizei width, GLsizei height,
                             GLenum unpackFormat, GLenum unpackType,
-                            const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+                            const dom::Nullable<dom::ArrayBufferView>& maybeView,
                             ErrorResult&)
 {
     const char funcName[] = "texSubImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
@@ -466,17 +466,17 @@ WebGLContext::TexSubImage2D(GLenum rawTe
 
 ////////////////////////////////////////
 // CompressedTex(Sub)Image
 
 void
 WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
                                    GLenum internalFormat, GLsizei width, GLsizei height,
                                    GLint border,
-                                   const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                   const dom::ArrayBufferView& view)
 {
     const char funcName[] = "compressedTexImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
@@ -489,17 +489,17 @@ WebGLContext::CompressedTexImage2D(GLenu
     tex->CompressedTexImage(funcName, target, level, internalFormat, width, height, depth,
                             border, view);
 }
 
 void
 WebGLContext::CompressedTexSubImage2D(GLenum rawTexImageTarget, GLint level,
                                       GLint xOffset, GLint yOffset, GLsizei width,
                                       GLsizei height, GLenum sizedUnpackFormat,
-                                      const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                      const dom::ArrayBufferView& view)
 {
     const char funcName[] = "compressedTexSubImage2D";
     const uint8_t funcDims = 2;
 
     TexImageTarget target;
     WebGLTexture* tex;
     if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
                                 &tex))
--- a/dom/canvas/WebGLElementArrayCache.cpp
+++ b/dom/canvas/WebGLElementArrayCache.cpp
@@ -483,16 +483,19 @@ WebGLElementArrayCache::BufferData(const
 bool
 WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr,
                                       size_t updateByteLength)
 {
     MOZ_ASSERT(pos + updateByteLength <= mBytes.Length());
     if (!updateByteLength)
         return true;
 
+    // Note, using memcpy on shared racy data is not well-defined, this
+    // will need to use safe-for-races operations when those become available.
+    // See bug 1225033.
     if (ptr)
         memcpy(mBytes.Elements() + pos, ptr, updateByteLength);
     else
         memset(mBytes.Elements() + pos, 0, updateByteLength);
     return UpdateTrees(pos, pos + updateByteLength - 1);
 }
 
 bool
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -219,17 +219,17 @@ public:
 
     ////////////////////////////////////
     // WebGLTextureUpload.cpp
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLint border, GLenum unpackFormat, GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView);
+                       const dom::Nullable<dom::ArrayBufferView>& maybeView);
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLenum unpackFormat, GLenum unpackType,
                        dom::ImageData* imageData);
 
     void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                        GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
@@ -261,21 +261,21 @@ protected:
                   GLenum unpackType, webgl::TexUnpackBlob* blob);
     void TexSubImage(const char* funcName, TexImageTarget target, GLint level,
                      GLint xOffset, GLint yOffset, GLint zOffset, GLenum unpackFormat,
                      GLenum unpackType, webgl::TexUnpackBlob* blob);
 public:
     void CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
                             GLenum internalFormat, GLsizei width, GLsizei height,
                             GLsizei depth, GLint border,
-                            const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+                            const dom::ArrayBufferView& view);
     void CompressedTexSubImage(const char* funcName, TexImageTarget target, GLint level,
                                GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
                                GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
-                               const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+                               const dom::ArrayBufferView& view);
     void CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
                         GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
     void CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
                          GLint xOffset, GLint yOffset, GLint zOffset, GLint x, GLint y,
                          GLsizei width, GLsizei height);
 
     ////////////////////////////////////
 
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -114,46 +114,46 @@ ValidateUnpackArrayType(WebGLContext* we
     webgl->ErrorInvalidOperation("%s: `pixels` be compatible with unpack `type`.",
                                  funcName);
     return false;
 }
 
 static UniquePtr<webgl::TexUnpackBlob>
 UnpackBlobFromMaybeView(WebGLContext* webgl, const char* funcName, GLsizei width,
                         GLsizei height, GLsizei depth, GLenum unpackType,
-                        const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
+                        const dom::Nullable<dom::ArrayBufferView>& maybeView)
 {
     size_t dataSize;
     const void* data;
     if (maybeView.IsNull()) {
         dataSize = 0;
         data = nullptr;
     } else {
         const auto& view = maybeView.Value();
-        void* mutData;
-        js::Scalar::Type jsType;
-        ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
-        data = mutData;
-
+        view.ComputeLengthAndData();
+        data = view.DataAllowShared();
+        dataSize = view.LengthAllowShared();
+        js::Scalar::Type jsType = JS_GetArrayBufferViewType(view.Obj());
         if (!ValidateUnpackArrayType(webgl, funcName, unpackType, jsType))
             return nullptr;
     }
 
     UniquePtr<webgl::TexUnpackBlob> ret;
+    // Warning: Possibly shared memory.  See bug 1225033.
     ret.reset(new webgl::TexUnpackBytes(width, height, depth, dataSize, data));
     return Move(ret);
 }
 
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
                             GLsizei depth, GLint border, GLenum unpackFormat,
                             GLenum unpackType,
-                            const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
+                            const dom::Nullable<dom::ArrayBufferView>& maybeView)
 {
     UniquePtr<webgl::TexUnpackBlob> blob;
     blob = UnpackBlobFromMaybeView(mContext, funcName, width, height, depth, unpackType,
                                    maybeView);
     if (!blob)
         return;
 
     TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
@@ -1241,17 +1241,17 @@ WebGLTexture::TexSubImage(const char* fu
 
 ////////////////////////////////////////
 // CompressedTex(Sub)Image
 
 void
 WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
                                  GLenum internalFormat, GLsizei width, GLsizei height,
                                  GLsizei depth, GLint border,
-                                 const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                 const dom::ArrayBufferView& view)
 {
     ////////////////////////////////////
     // Get dest info
 
     WebGLTexture::ImageInfo* imageInfo;
     if (!ValidateTexImageSpecification(funcName, target, level, width, height, depth,
                                        border, &imageInfo))
     {
@@ -1274,21 +1274,19 @@ WebGLTexture::CompressedTexImage(const c
     }
 
     if (!ValidateTargetForFormat(funcName, mContext, target, format))
         return;
 
     ////////////////////////////////////
     // Get source info
 
-    void* mutData;
-    size_t dataSize;
-    js::Scalar::Type jsType;
-    ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
-    const void* data = mutData;
+    view.ComputeLengthAndData();
+    const void* data = view.DataAllowShared();
+    size_t dataSize = view.LengthAllowShared();
 
     if (!ValidateCompressedTexUnpack(mContext, funcName, width, height, depth, format,
                                      dataSize))
     {
         return;
     }
 
     ////////////////////////////////////
@@ -1300,16 +1298,17 @@ WebGLTexture::CompressedTexImage(const c
         return;
     }
 
     ////////////////////////////////////
     // Do the thing!
 
     mContext->gl->MakeCurrent();
 
+    // Warning: Possibly shared memory.  See bug 1225033.
     GLenum error = DoCompressedTexImage(mContext->gl, target, level, internalFormat,
                                         width, height, depth, border, dataSize, data);
     if (error == LOCAL_GL_OUT_OF_MEMORY) {
         mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
         return;
     }
     if (error) {
         MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
@@ -1348,17 +1347,17 @@ IsSubImageBlockAligned(const webgl::Comp
     return true;
 }
 
 void
 WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target,
                                     GLint level, GLint xOffset, GLint yOffset,
                                     GLint zOffset, GLsizei width, GLsizei height,
                                     GLsizei depth, GLenum sizedUnpackFormat,
-                                    const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+                                    const dom::ArrayBufferView& view)
 {
     ////////////////////////////////////
     // Get dest info
 
     WebGLTexture::ImageInfo* imageInfo;
     if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
                                    width, height, depth, &imageInfo))
     {
@@ -1367,21 +1366,19 @@ WebGLTexture::CompressedTexSubImage(cons
     MOZ_ASSERT(imageInfo);
 
     auto dstUsage = imageInfo->mFormat;
     auto dstFormat = dstUsage->format;
 
     ////////////////////////////////////
     // Get source info
 
-    void* mutData;
-    size_t dataSize;
-    js::Scalar::Type jsType;
-    ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
-    const void* data = mutData;
+    view.ComputeLengthAndData();
+    size_t dataSize = view.LengthAllowShared();
+    const void* data = view.DataAllowShared();
 
     auto srcUsage = mContext->mFormatUsage->GetSizedTexUsage(sizedUnpackFormat);
     if (!srcUsage->format->compression) {
         mContext->ErrorInvalidEnum("%s: Specified format must be compressed.", funcName);
         return;
     }
 
     if (srcUsage != dstUsage) {
@@ -1445,16 +1442,17 @@ WebGLTexture::CompressedTexSubImage(cons
     bool uploadWillInitialize;
     if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
                                              yOffset, zOffset, width, height, depth,
                                              imageInfo, &uploadWillInitialize))
     {
         return;
     }
 
+    // Warning: Possibly shared memory.  See bug 1225033.
     GLenum error = DoCompressedTexSubImage(mContext->gl, target, level, xOffset, yOffset,
                                            zOffset, width, height, depth,
                                            sizedUnpackFormat, dataSize, data);
     if (error == LOCAL_GL_OUT_OF_MEMORY) {
         mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
         return;
     }
     if (error) {
--- a/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
+++ b/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
@@ -16,17 +16,17 @@ function RGBAToString(arr) {
   return '[' + arr[0].toPrecision(4) + ', ' +
                arr[1].toPrecision(4) + ', ' +
                arr[2].toPrecision(4) + ', ' +
                arr[3].toPrecision(4) + ']';
 }
 
 function TestScreenColor(gl, r, g, b, a) {
   var arr = new SharedArrayBuffer(4);
-  var view = new SharedUint8Array(arr);
+  var view = new Uint8Array(arr);
   gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view);
 
   var err = gl.getError();
   ok(err == 0, 'Should be no errors.');
   if (err)
     return;
 
   var floatArr;
@@ -59,20 +59,16 @@ function TestScreenColor(gl, r, g, b, a)
   if (!gl) {
     todo(false, 'WebGL is unavailable.');
     return;
   }
   if (typeof SharedArrayBuffer === 'undefined') {
     todo(false, 'SharedArrayBuffer is unavailable.');
     return;
   }
-  if (SharedFloat32Array === 'undefined') {
-    todo(false, 'SharedFloat32Array is unavailable.');
-    return;
-  }
 
   var vs = gl.createShader(gl.VERTEX_SHADER);
   gl.shaderSource(vs, "attribute vec2 aVertCoord; void main(void) { gl_Position = vec4(aVertCoord, 0.0, 1.0); }");
   gl.compileShader(vs);
   var fs = gl.createShader(gl.FRAGMENT_SHADER);
   gl.shaderSource(fs, "precision mediump float; uniform vec4 uFragColor; void main(void) { gl_FragColor = uFragColor; }");
   gl.compileShader(fs);
   var prog = gl.createProgram();
@@ -94,17 +90,17 @@ function TestScreenColor(gl, r, g, b, a)
 
   prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
   prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
 
   gl.useProgram(prog);
 
   // Test gl.bufferData(), gl.bufferSubData() and gl.readPixels() APIs with SAB as input.
   var arr = new SharedArrayBuffer(8*4);
-  var view = new SharedFloat32Array(arr);
+  var view = new Float32Array(arr);
   view.set(new Float32Array([-1, -1, 1, -1, -1,  1, 1,  1]));
   var vb = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, vb);
   gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
   ok(gl.getError() == 0, 'bufferData with SAB as input parameter works ok.');
   gl.bufferSubData(gl.ARRAY_BUFFER, 0, arr);
   ok(gl.getError() == 0, 'bufferSubData with SAB as input parameter works ok.');
   gl.enableVertexAttribArray(0);
@@ -118,17 +114,17 @@ function TestScreenColor(gl, r, g, b, a)
 
   // Test gl.texImage2D() and gl.texSubImage2D() APIs with SAB as input.
   var tex = gl.createTexture();
   gl.bindTexture(gl.TEXTURE_2D, tex);
   var width = 4;
   var height = 4;
   var numChannels = 4;
   var sab = new SharedArrayBuffer(width * height * numChannels);
-  var data = new SharedUint8Array(sab);
+  var data = new Uint8Array(sab);
   for (var i = 0; i < data.length; ++i) {
     data[i] = i;
   }
   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
   ok(gl.getError() == 0, 'texImage2D() with SAB as input parameter works ok.');
   gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
   ok(gl.getError() == 0, 'texSubImage2D() with SAB as input parameter works ok.');
 
@@ -146,46 +142,42 @@ function TestScreenColor(gl, r, g, b, a)
   if (!gl) {
     todo(false, 'WebGL 2 is unavailable.');
     return;
   }
   if (typeof SharedArrayBuffer === 'undefined') {
     todo(false, 'SharedArrayBuffer is unavailable.');
     return;
   }
-  if (SharedFloat32Array === 'undefined') {
-    todo(false, 'SharedFloat32Array is unavailable.');
-    return;
-  }
 
   var arr = new SharedArrayBuffer(8*4);
-  var view = new SharedFloat32Array(arr);
+  var view = new Float32Array(arr);
   view.set(new Float32Array([-1, -1, 1, -1, -1,  1, 1,  1]));
   var vb = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, vb);
   gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
 
   var arr2 = new SharedArrayBuffer(8*4);
   gl.getBufferSubData(gl.ARRAY_BUFFER, 0, arr2);
-  var view2 = new SharedFloat32Array(arr2);
+  var view2 = new Float32Array(arr2);
   var equal = true;
   for(var i = 0; i < 8; ++i) {
     if (view[i] != view2[i]) equal = false;
   }
   ok(equal, 'getBufferSubData with SAB as input parameter works ok.');
 
   // Test gl.texImage3D() and gl.texSubImage3D() APIs with SAB as input.
   var tex = gl.createTexture();
   gl.bindTexture(gl.TEXTURE_3D, tex);
   var width = 4;
   var height = 4;
   var depth = 4;
   var numChannels = 4;
   var sab = new SharedArrayBuffer(width * height * depth* numChannels);
-  var data = new SharedUint8Array(sab);
+  var data = new Uint8Array(sab);
   for (var i = 0; i < data.length; ++i) {
     data[i] = i;
   }
   gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
   ok(gl.getError() == 0, 'texImage3D() with SAB as input parameter works ok.');
   gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, width, height, depth, gl.RGBA, gl.UNSIGNED_BYTE, data);
   ok(gl.getError() == 0, 'texSubImage3D() with SAB as input parameter works ok.');
 
--- a/dom/crypto/CryptoBuffer.h
+++ b/dom/crypto/CryptoBuffer.h
@@ -25,18 +25,19 @@ public:
   uint8_t* Assign(const SECItem* aItem);
   uint8_t* Assign(const ArrayBuffer& aData);
   uint8_t* Assign(const ArrayBufferView& aData);
   uint8_t* Assign(const ArrayBufferViewOrArrayBuffer& aData);
   uint8_t* Assign(const OwningArrayBufferViewOrArrayBuffer& aData);
 
   template<typename T,
            JSObject* UnwrapArray(JSObject*),
-           void GetLengthAndData(JSObject*, uint32_t*, T**)>
-  uint8_t* Assign(const TypedArray_base<T, UnwrapArray, GetLengthAndData>& aArray)
+           void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*, T**)>
+  uint8_t* Assign(const TypedArray_base<T, UnwrapArray,
+                                        GetLengthAndDataAndSharedness>& aArray)
   {
     aArray.ComputeLengthAndData();
     return Assign(aArray.Data(), aArray.Length());
   }
 
   nsresult FromJwkBase64(const nsString& aBase64);
   nsresult ToJwkBase64(nsString& aBase64);
   bool ToSECItem(PLArenaPool* aArena, SECItem* aItem) const;
--- a/dom/datastore/DataStore.cpp
+++ b/dom/datastore/DataStore.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/DataStoreCursor.h"
 #include "mozilla/dom/DataStoreBinding.h"
 #include "mozilla/dom/DataStoreImplBinding.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "AccessCheck.h"
+#include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ADDREF_INHERITED(DataStore, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(DataStore, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DataStore)
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -316,17 +316,19 @@ FMRadio::GetRdsgroup(JSContext* cx, JS::
 {
   uint64_t group;
   if (!IFMRadioService::Singleton()->GetRdsgroup(group)) {
     return;
   }
 
   JSObject *rdsgroup = Uint16Array::Create(cx, this, 4);
   JS::AutoCheckCannotGC nogc;
-  uint16_t *data = JS_GetUint16ArrayData(rdsgroup, nogc);
+  bool isShared = false;
+  uint16_t *data = JS_GetUint16ArrayData(rdsgroup, &isShared, nogc);
+  MOZ_ASSERT(!isShared);  // Because created above.
   data[3] = group & 0xFFFF;
   group >>= 16;
   data[2] = group & 0xFFFF;
   group >>= 16;
   data[1] = group & 0xFFFF;
   group >>= 16;
   data[0] = group & 0xFFFF;
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3759,17 +3759,22 @@ HTMLMediaElement::UpdateReadyStateIntern
       mediaInfo.EnableAudio();
     }
     if (hasVideo) {
       mediaInfo.EnableVideo();
     }
     MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
   }
 
-  if (NextFrameStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
+  enum NextFrameStatus nextFrameStatus = NextFrameStatus();
+  if (mDecoder && nextFrameStatus == NEXT_FRAME_UNAVAILABLE) {
+    nextFrameStatus = mDecoder->NextFrameBufferedStatus();
+  }
+
+  if (nextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
     LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
                           "NEXT_FRAME_UNAVAILABLE_SEEKING; Forcing HAVE_METADATA", this));
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
     return;
   }
 
   if (IsVideo() && HasVideo() && !IsPlaybackEnded() &&
         GetImageContainer() && !GetImageContainer()->HasCurrentImage()) {
@@ -3795,23 +3800,23 @@ HTMLMediaElement::UpdateReadyStateIntern
     // Note that this state transition includes the case where we finished
     // downloaded the whole data stream.
     LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
                           "Decoder download suspended by cache", this));
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
     return;
   }
 
-  if (NextFrameStatus() != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
+  if (nextFrameStatus != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
     LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
                           "Next frame not available", this));
     if (mFirstFrameLoaded) {
       ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
     }
-    if (!mWaitingFired && NextFrameStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
+    if (!mWaitingFired && nextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
       FireTimeUpdate(false);
       DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
       mWaitingFired = true;
     }
     return;
   }
 
   if (!mFirstFrameLoaded) {
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -62,17 +62,17 @@ interface nsIServiceWorkerRegistrationIn
 [scriptable, uuid(9e523e7c-ad6f-4df0-8077-c74aebbc679d)]
 interface nsIServiceWorkerManagerListener : nsISupports
 {
   void onRegister(in nsIServiceWorkerRegistrationInfo aInfo);
 
   void onUnregister(in nsIServiceWorkerRegistrationInfo aInfo);
 };
 
-[scriptable, builtinclass, uuid(c945e2e6-30c2-48e6-a282-e69de0c7ebb1)]
+[scriptable, builtinclass, uuid(a03f2b64-7aaf-423a-97b0-e1f733cce0f6)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -101,17 +101,17 @@ interface nsIServiceWorkerManager : nsIS
   void removeReadyPromise(in nsIDOMWindow aWindow);
 
   /**
    * Call this to request that document `aDoc` be controlled by a ServiceWorker
    * if a registration exists for it's scope.
    *
    * This MUST only be called once per document!
    */
-  [notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
+  [notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc, in DOMString aDocumentId);
 
   /**
    * Documents that have called MaybeStartControlling() should call this when
    * they are destroyed. This function may be called multiple times, and is
    * idempotent.
    */
   [notxpcom,nostdcall] void MaybeStopControlling(in nsIDocument aDoc);
 
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -9,16 +9,17 @@
 #ifdef MOZ_CHILD_PERMISSIONS
 #include "ContentParent.h"
 #include "mozIApplication.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "nsIAppsService.h"
 #include "nsIPrincipal.h"
 #include "nsPrintfCString.h"
 #include "nsIURI.h"
+#include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "TabParent.h"
 
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::hal_sandbox;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -752,17 +752,17 @@ TabChild::Init()
   nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this);
   mPuppetWidget = static_cast<PuppetWidget*>(widget.get());
   if (!mPuppetWidget) {
     NS_ERROR("couldn't create fake widget");
     return NS_ERROR_FAILURE;
   }
   mPuppetWidget->Create(
     nullptr, 0,              // no parents
-    gfx::IntRect(gfx::IntPoint(0, 0), gfx::IntSize(0, 0)),
+    LayoutDeviceIntRect(0, 0, 0, 0),
     nullptr                  // HandleWidgetEvent
   );
 
   baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0);
   baseWindow->Create();
 
   NotifyTabContextUpdated();
 
@@ -2833,18 +2833,19 @@ TabChild::CreatePluginWidget(nsIWidget* 
     return NS_ERROR_UNEXPECTED;
   }
 
   nsWidgetInitData initData;
   initData.mWindowType = eWindowType_plugin_ipc_content;
   initData.mUnicode = false;
   initData.clipChildren = true;
   initData.clipSiblings = true;
-  nsresult rv = pluginWidget->Create(aParent, nullptr, gfx::IntRect(gfx::IntPoint(0, 0),
-                                     nsIntSize(0, 0)), &initData);
+  nsresult rv = pluginWidget->Create(aParent, nullptr,
+                                     LayoutDeviceIntRect(0, 0, 0, 0),
+                                     &initData);
   if (NS_FAILED(rv)) {
     NS_WARNING("Creating native plugin widget on the chrome side failed.");
   }
   pluginWidget.forget(aOut);
   return rv;
 }
 
 ScreenIntSize
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -574,16 +574,19 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   mWatchManager.Watch(mStateMachineDuration, &MediaDecoder::DurationChanged);
 
   // mStateMachineIsShutdown
   mWatchManager.Watch(mStateMachineIsShutdown, &MediaDecoder::ShutdownBitChanged);
 
   // readyState
   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateReadyState);
   mWatchManager.Watch(mNextFrameStatus, &MediaDecoder::UpdateReadyState);
+  // ReadyState computation depends on MediaDecoder::CanPlayThrough, which
+  // depends on the download rate.
+  mWatchManager.Watch(mBuffered, &MediaDecoder::UpdateReadyState);
 
   // mLogicalPosition
   mWatchManager.Watch(mCurrentPosition, &MediaDecoder::UpdateLogicalPosition);
   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
 
   // mIgnoreProgressData
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
@@ -1521,20 +1524,16 @@ MediaDecoder::NotifyDataArrived() {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Don't publish events since task queues might be shutting down.
   if (mShuttingDown) {
     return;
   }
 
   mDataArrivedEvent.Notify();
-
-  // ReadyState computation depends on MediaDecoder::CanPlayThrough, which
-  // depends on the download rate.
-  UpdateReadyState();
 }
 
 // Provide access to the state machine object
 MediaDecoderStateMachine*
 MediaDecoder::GetStateMachine() const {
   MOZ_ASSERT(NS_IsMainThread());
   return mDecoderStateMachine;
 }
@@ -1812,16 +1811,31 @@ MediaDecoder::RemoveMediaTracks()
   VideoTrackList* videoList = element->VideoTracks();
   if (videoList) {
     videoList->RemoveTracks();
   }
 
   mMediaTracksConstructed = false;
 }
 
+MediaDecoderOwner::NextFrameStatus
+MediaDecoder::NextFrameBufferedStatus()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Next frame hasn't been decoded yet.
+  // Use the buffered range to consider if we have the next frame available.
+  media::TimeUnit currentPosition =
+    media::TimeUnit::FromMicroseconds(CurrentPosition());
+  media::TimeInterval interval(currentPosition,
+                               currentPosition + media::TimeUnit::FromMicroseconds(DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED));
+  return GetBuffered().Contains(interval)
+    ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
+    : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
+}
+
 MediaMemoryTracker::MediaMemoryTracker()
 {
 }
 
 void
 MediaMemoryTracker::InitMemoryReporter()
 {
   RegisterWeakAsyncMemoryReporter(this);
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -714,16 +714,17 @@ private:
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (!mShuttingDown) {
       mOwner->UpdateReadyState();
     }
   }
 
   virtual MediaDecoderOwner::NextFrameStatus NextFrameStatus() { return mNextFrameStatus; }
+  virtual MediaDecoderOwner::NextFrameStatus NextFrameBufferedStatus();
 
 protected:
   virtual ~MediaDecoder();
 
   // Called when the first audio and/or video from the media file has been loaded
   // by the state machine. Call on the main thread only.
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility);
@@ -787,16 +788,21 @@ protected:
 
   /******
    * The following member variables can be accessed from any thread.
    ******/
 
   // Media data resource.
   RefPtr<MediaResource> mResource;
 
+  // Amount of buffered data ahead of current time required to consider that
+  // the next frame is available.
+  // An arbitrary value of 250ms is used.
+  static const int DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED = 250000;
+
 private:
   // Called when the metadata from the media file has been loaded by the
   // state machine. Call on the main thread only.
   void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
                       nsAutoPtr<MetadataTags> aTags,
                       MediaDecoderEventVisibility aEventVisibility);
 
   MediaEventSource<void>*
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/TestVPXDecoding.cpp
@@ -0,0 +1,103 @@
+/* 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 "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "nsTArray.h"
+#include "VPXDecoder.h"
+
+#include <stdio.h>
+
+using namespace mozilla;
+
+static void
+ReadVPXFile(const char* aPath, nsTArray<uint8_t>& aBuffer)
+{
+  FILE* f = fopen(aPath, "rb");
+  ASSERT_NE(f, (FILE *) nullptr);
+
+  int r = fseek(f, 0, SEEK_END);
+  ASSERT_EQ(r, 0);
+
+  long size = ftell(f);
+  ASSERT_NE(size, -1);
+  aBuffer.SetLength(size);
+
+  r = fseek(f, 0, SEEK_SET);
+  ASSERT_EQ(r, 0);
+
+  size_t got = fread(aBuffer.Elements(), 1, size, f);
+  ASSERT_EQ(got, size_t(size));
+
+  r = fclose(f);
+  ASSERT_EQ(r, 0);
+}
+
+static
+vpx_codec_iface_t*
+ParseIVFConfig(nsTArray<uint8_t>& data, vpx_codec_dec_cfg_t& config)
+{
+  if (data.Length() < 32 + 12) {
+    // Not enough data for file & first frame headers.
+    return nullptr;
+  }
+  if (data[0] != 'D' || data[1] != 'K' || data[2] != 'I' || data[3] != 'F') {
+    // Expect 'DKIP'
+    return nullptr;
+  }
+  if (data[4] != 0 || data[5] != 0) {
+    // Expect version==0.
+    return nullptr;
+  }
+  if (data[8] != 'V' || data[9] != 'P'
+      || (data[10] != '8' && data[10] != '9')
+      || data[11] != '0') {
+    // Expect 'VP80' or 'VP90'.
+    return nullptr;
+  }
+  config.w = uint32_t(data[12]) || (uint32_t(data[13]) << 8);
+  config.h = uint32_t(data[14]) || (uint32_t(data[15]) << 8);
+  vpx_codec_iface_t* codec = (data[10] == '8')
+                             ? vpx_codec_vp8_dx()
+                             : vpx_codec_vp9_dx();
+  // Remove headers, to just leave raw VPx data to be decoded.
+  data.RemoveElementsAt(0, 32 + 12);
+  return codec;
+}
+
+struct TestFileData {
+  const char* mFilename;
+  vpx_codec_err_t mDecodeResult;
+};
+static const TestFileData testFiles[] = {
+  { "test_case_1224361.vp8.ivf", VPX_CODEC_OK },
+  { "test_case_1224363.vp8.ivf", VPX_CODEC_CORRUPT_FRAME },
+  { "test_case_1224369.vp8.ivf", VPX_CODEC_CORRUPT_FRAME }
+};
+
+TEST(libvpx, test_cases)
+{
+  for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
+    nsTArray<uint8_t> data;
+    ReadVPXFile(testFiles[test].mFilename, data);
+    ASSERT_GT(data.Length(), 0u);
+
+    vpx_codec_dec_cfg_t config;
+    vpx_codec_iface_t* dx = ParseIVFConfig(data, config);
+    ASSERT_TRUE(dx);
+    config.threads = 2;
+
+    vpx_codec_ctx_t ctx;
+    PodZero(&ctx);
+    vpx_codec_err_t r = vpx_codec_dec_init(&ctx, dx, &config, 0);
+    ASSERT_EQ(VPX_CODEC_OK, r);
+
+    r = vpx_codec_decode(&ctx, data.Elements(), data.Length(), nullptr, 0);
+    // This test case is known to be corrupt.
+    EXPECT_EQ(testFiles[test].mDecodeResult, r);
+
+    r = vpx_codec_destroy(&ctx);
+    EXPECT_EQ(VPX_CODEC_OK, r);
+  }
+}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -14,16 +14,17 @@ UNIFIED_SOURCES += [
     'TestMediaEventSource.cpp',
     'TestMediaFormatReader.cpp',
     'TestMozPromise.cpp',
     'TestMP3Demuxer.cpp',
     'TestMP4Demuxer.cpp',
     # 'TestMP4Reader.cpp', disabled so we can turn check tests back on (bug 1175752)
     'TestTrackEncoder.cpp',
     'TestVideoSegment.cpp',
+    'TestVPXDecoding.cpp',
     'TestWebMBuffered.cpp',
 ]
 
 if CONFIG['MOZ_EME']:
     UNIFIED_SOURCES += [
         'TestEME.cpp',
     ]
 
@@ -45,16 +46,19 @@ TEST_HARNESS_FILES.gtest += [
     'dash_dashinit.mp4',
     'id3v2header.mp3',
     'mediasource_test.mp4',
     'noise.mp3',
     'noise_vbr.mp3',
     'short-zero-in-moov.mp4',
     'small-shot.mp3',
     'test.webm',
+    'test_case_1224361.vp8.ivf',
+    'test_case_1224363.vp8.ivf',
+    'test_case_1224369.vp8.ivf',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/media',
     '/dom/media/eme',
     '/dom/media/encoder',
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e2fe942f0e66e7ff18b2626ae0250a02e04ef7b7
GIT binary patch
literal 1497
zc$@**1t$7LOG!om03ZNXP&hC^03-k&0000100003000000000z1poj5000000002+
z7yz9CDnI}v0Du1og@uTPgopwH0>pe@3qIxf0nbkocQk%a6!#kSHTjGEk4$H)@7Hfq
zKd67=Ke>Cs`YHcCzRBnV<$wDD@S*#c>05Kd>I2ok8-CW3#lZb8{IARh#=qjcFZdPw
zr;=aozmz|fe$x9%@;~|j000m;_9KJ+=ckYS-dg^l_6Ge_|8dys(J%H_+VuWiw6nor
zai1SDsPtfVKt*9^{luh6#O+{9SnDZ0tz!-_^9=i+>T#iY-NUt^R`ynpY_oX8dbzs5
z{?_aHpu4Uu&fg$^;QDRm?yV`T<!|ySf{i=<_ZrfE#vbursv5eFJwr;D!K7E8-sc%o
z-+r9CX|aRtCZ*s1XdvC+|7W`W%*ZkG!edm+)S0*Rh2FIP;!ij0>%_pb|3C9{ijn8x
z#Ev1L?f>&cvC&gjZx>nu_=Ldj72|*JB_;7k-5ao*p1HUPJe)0P>f~RF%BL<~Q_RM7
z)y9pTJ%`#{b)2WnuU>kx-`21B3>+_8+O$nZ1$7kqddWQu$0MS9+Oa{v%Zf6=V;Tzt
zpfrmI0c`!Ir?R9!nPj!i`GLM|k<)#xu=aOkK4wb(h!}QAvg_4U)!epd>&{ctgh+VN
z++-?#m4BQ{Q>}EGM?=-h{rXE;w1#giyPpH`Yz0Z#iG+shs%JiFylB=0mTsme%U#<9
z0=noe>1|(D6$=`|MZmw^*{+K4l>yMJO4$H?)4d<9{EtqO?Fcu3zO3MO0`qIn=ha!A
z^Sncu!wPKqB*aoWSFA9r<Zl7MRQ(+s0%4lwLg7~n`0o+lHopUTL4U8zX{^GDaOEdk
z?1F$v$p6!s@TeucNk1q=!Ug7F07N-GhWW2Ke4jLbf!b<*w}zQfpnRayui}8)*s=fl
zbR=@}VbLybO(`zxM#-=GVR>v3EB!&osaQ;lXDtX>7)hh5q{RKg9_Np{lgYno`G3T6
zg`U^ot^bnc@#vy#hN4(R-m#XH_D>?mxcMvmphPaK{M)WDE*{iFy^yYP8trxz;0(pX
z6rEKOGO{P3>vDRot6u%nBFCHZB|LwJ`duDTWLA_fg&WCOs8~zl^wGgxRLd2uvH6es
zXr)W{vonEP@OuC>?9v*3@LsyrBL96J#?<9SaTV7G{HL4vFm@PM(sw8Ma-H4Ts5ZwQ
zaLUT^{r~gEFyy;$H&cnph!C?nnwlAW3k<=l<<SP=1@*n!XF&-CqT99cLtT>CuC*nG
zkG*E9?#w^Sn*J-~`jez+9p{^nqWLwM@*cdo+x;O4?xW`C-z@BS?}7ZNC)Ax_0PVg>
zw1E$UXENr<;7D?JeJ4QNm!Y?&BNtoqt%Cs|`n-4}(cXTFlTzQ`ds@+~Nu`!M|Hp6q
zNvxRh*9Ry$)pY$KYkXdYW=ZI(U#_}W&2=Vm)AEsbTZDv4*0*zebbTi-4H%*Ud1qO-
z;h)=FmO7E=+;GRsPp!+0XjGV_Z-{Y)AfQRM37+lddh=bw-AgsEy>Ywa7-}Ve89dvc
zN(Dg4shc_C0pKCeq!(UAoF+}koHLF%Jle_K<!OtL$9vvI)OqFI{`m`w7b}#Ed0Mf!
z;xpMxdC%U*S3n)HE(wYEI(cOS;1RuT;94p^Q6XP#IL#WNDvF_VYv#v{%u$Qe`eKQg
zL;_=vIDhOurC`!r=6k})5LJ|%)20ZSW{V{+oTV6W2Brt!{W)ERjDz7Rhh{ylI2_U9
zqd2FS`6~`P&d_+0xpuzyuWKMMesitwNF@||=j{1U1ddQIgOUIMWB>pF0RR9100000
zaRUI&&CSit&CSit&CSit&CSit&CSit8m{$UT_>!4_%9cE*IQ1MDq(dS7GY%tBGJ)O
za%v{;hqwc6CVPO&=4R#ryp8T8O#<6Kkbys>1d4~B067H!00IC22MC3Qh=qiR#=r`G
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6d2e4e02063b750d7ee9a349acedc517e7e8a83d
GIT binary patch
literal 1388
zc$@)j1(W(jOG!om03ZNXP&hC^03-k&0000100003000000000z1poj5000000002+
z7yz9CDnI}v?EeP{g@wweE?!g2#&y-kjh#J+g@lL#0s_Q*Ukg6v`2o*Q5_dFyPZakW
z^)>m6{f|s%tMAuuQa`AF;y<~2!TKrxJ-*541Lc4F0q~*wm+4z`!|DUozZ-tmlEuLN
zF8r^|2gbkRyf63_{HKy%?Z1>im44FuN%BAX{x|z(IQAoh{pY8T{N7srq4oy-RR3|<
z>(MXvSK9Rc5%*Vle4kir)KBJah|gC4uKuKdQNO@{U9_{oU~!)xGN|-mc0fg8XZ=47
z;Q#;tWO%W4J*{I7F!K!ipXza;dELXcp;q=*k8HDe#Co~9!0^`V`JlV5I?mr9f8hFU
z=I*U2tmSX=DT0kV{r4Kue#Rd0UaA_pk3B<5m%*f0pWf#gQr~`@yJ@k5?Ixw)|7alH
z-~VU2{mjTQ^TK0P%hZ{-^o8EE|Kd+K>+8h8v;RNybBdAY;lz$1pzZ(jM6uCR!0r{}
zfA1wF@kiYou$!K_xClI)EjsGtUy917E?!g2#&y-kjh#J*+FW&<r_8Tjda~cvulWod
zFI(EQO-2QE6#9C}Jq*VqqI=r0LBPw3GQndS3k0Aviw6O0{idg~q(7Ntwaxi~zHO1y
zeXX$ecVs?hO8$r#c1W`8)l}8owrK0lQ`3Y<c+uQsDt?uJoJv!zbecy)^~(MFOIgK+
zZ!Ei?1MzGHN!f{nhU=<lK54vY)&!PrrYFl?+XMo-=q>4OUse?h8p1`uzunocitv>I
z(5p(>0DaTFAFce4PLk~iH-NsZ;C2G@YtQG^S)KE|Lz%-0Z22U_QaV?xFstNm0l-xK
z9UKB-n&v{`R}1*>5#Khy19?Gzugqzz!ijL@CtK`-fJw;z(}(b=CA>*LD4^4?;(*)O
zvH$pVBy#eo(JpRHDK6_q$*=lhd2A6Y{Xxg6SWJs&EeKf{Nu#Qy#Qnk^=a0LS$-ip(
zf5dWyp4Z^5|B~hL=%Q?fqF6-Uv6htfPa?;-`78XOL@ulR+paJ!9@Im<kgjnW?RFI4
z48_9~omCMsvL~VIa(b?-Uj5S|$D8scJb#D!T^><nR+KM=8_8Ix6|J%PkNRk(OZT%g
zfm`r<05t5<8h-Fzy4528eICZt<wbE7*9ZKkoA@wx7+2DFC;4)n-Px!%#~yIX%JTjH
z^TsgbyKgsBiOGl%vpSlZ8GH*2!K>xb2H^$uz1n9%2?e6twedq;lGv`bC5Df^W~%PY
zKg*j5E9Cl<q-Y)In~<XUHJS3;{UHhNqvq$|EbMsif&8c^)SX}e?Y>F0fe(XcGUmwO
zNOE_5CqUenp|_?Z7hChKg8?A=ym%wg-hPUcQs3WuTG6aYrItJY$8Y>eteElF2Piq!
zbp0V~d|rlTN$9FyuDVyvbtZAs@{xC2goH}gw{v@ReJ3sr7@`4rCt0`QpW9rPI+5qx
zaL3C}t;>vPRG6fH0000Wph>m~p6%v(^IgN;OEs^(al7LfY9)XfJlmg21whHEn>peE
z;33bX7hXl2CQZnkGnqI%+R5GJX^W4?d)`IVdF9>y`3s8|E0m0RTCup|Gucad&)&yZ
zKpn9z35oYQd1V9O5xs5TS}HzKAzy7c%^IO9ilK9B=Esc8QH#_1Vu_eU0%MOjf9yV`
zVA5RXd&0>ORg|35rU;p4izP3dr5JDqrU&2sIbDW~gW)}gW<9Pr9MR&VIH#ETD-Ju(
u(0G!$cE0zojvz38bFJ@4B@}z-?D<awj!-Xyk^lf?00001000000001lt=KC7
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2f8deb1148b29b4bce415488219c1ea664f9a1bd
GIT binary patch
literal 204
zc${<b_H<)lP+$lPurP37{J<c`z`(!=#7qnjuz&#p41^fwGHMAhNHEk#=zn40Xk;;t
qXJTLzWBJb3m@+^6_H1>FY9R6elO&^h26A+PP}LWPfBzTX{RjXDpEPU$
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -85,44 +85,44 @@ IsTypeSupported(const nsAString& aType)
 {
   if (aType.IsEmpty()) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
   nsContentTypeParser parser(aType);
   nsAutoString mimeType;
   nsresult rv = parser.GetType(mimeType);
   if (NS_FAILED(rv)) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
   NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
 
   nsAutoString codecs;
   bool hasCodecs = NS_SUCCEEDED(parser.GetParameter("codecs", codecs));
 
   for (uint32_t i = 0; gMediaSourceTypes[i]; ++i) {
     if (mimeType.EqualsASCII(gMediaSourceTypes[i])) {
       if (DecoderTraits::IsMP4TypeAndEnabled(mimeTypeUTF8)) {
         if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
-          return NS_ERROR_DOM_INVALID_STATE_ERR;
+          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         return NS_OK;
       } else if (DecoderTraits::IsWebMTypeAndEnabled(mimeTypeUTF8)) {
         if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
               IsWebMForced())) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
-          return NS_ERROR_DOM_INVALID_STATE_ERR;
+          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         return NS_OK;
       }
     }
   }
 
   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -97,16 +97,20 @@ MediaSourceDecoder::GetSeekable()
 }
 
 media::TimeIntervals
 MediaSourceDecoder::GetBuffered()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   dom::SourceBufferList* sourceBuffers = mMediaSource->ActiveSourceBuffers();
+  if (!sourceBuffers) {
+    // Media source object is shutting down.
+    return TimeIntervals();
+  }
   media::TimeUnit highestEndTime;
   nsTArray<media::TimeIntervals> activeRanges;
   media::TimeIntervals buffered;
 
   for (uint32_t i = 0; i < sourceBuffers->Length(); i++) {
     bool found;
     dom::SourceBuffer* sb = sourceBuffers->IndexedGetter(i, found);
     MOZ_ASSERT(found);
--- a/dom/media/webaudio/AudioBuffer.cpp
+++ b/dom/media/webaudio/AudioBuffer.cpp
@@ -114,17 +114,19 @@ AudioBuffer::RestoreJSChannelData(JSCont
     if (!array) {
       return false;
     }
     if (mSharedChannels) {
       // "4. Attach ArrayBuffers containing copies of the data to the
       // AudioBuffer, to be returned by the next call to getChannelData."
       const float* data = mSharedChannels->GetData(i);
       JS::AutoCheckCannotGC nogc;
-      mozilla::PodCopy(JS_GetFloat32ArrayData(array, nogc), data, mLength);
+      bool isShared;
+      mozilla::PodCopy(JS_GetFloat32ArrayData(array, &isShared, nogc), data, mLength);
+      MOZ_ASSERT(!isShared); // Was created as unshared above
     }
     mJSChannels[i] = array;
   }
 
   mSharedChannels = nullptr;
 
   return true;
 }
@@ -149,17 +151,21 @@ AudioBuffer::CopyFromChannel(const Float
   const float* sourceData = nullptr;
   if (channelArray) {
     if (JS_GetTypedArrayLength(channelArray) != mLength) {
       // The array was probably neutered
       aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
       return;
     }
 
-    sourceData = JS_GetFloat32ArrayData(channelArray, nogc);
+    bool isShared = false;
+    sourceData = JS_GetFloat32ArrayData(channelArray, &isShared, nogc);
+    // The sourceData arrays should all have originated in
+    // RestoreJSChannelData, where they are created unshared.
+    MOZ_ASSERT(!isShared);
   } else if (mSharedChannels) {
     sourceData = mSharedChannels->GetData(aChannelNumber);
   }
 
   if (sourceData) {
     PodMove(aDestination.Data(), sourceData + aStartInChannel, length);
   } else {
     PodZero(aDestination.Data(), length);
@@ -190,18 +196,22 @@ AudioBuffer::CopyToChannel(JSContext* aJ
   JS::AutoCheckCannotGC nogc;
   JSObject* channelArray = mJSChannels[aChannelNumber];
   if (JS_GetTypedArrayLength(channelArray) != mLength) {
     // The array was probably neutered
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
-  PodMove(JS_GetFloat32ArrayData(channelArray, nogc) + aStartInChannel,
-          aSource.Data(), length);
+  bool isShared = false;
+  float* channelData = JS_GetFloat32ArrayData(channelArray, &isShared, nogc);
+  // The channelData arrays should all have originated in
+  // RestoreJSChannelData, where they are created unshared.
+  MOZ_ASSERT(!isShared);
+  PodMove(channelData + aStartInChannel, aSource.Data(), length);
 }
 
 void
 AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
                             JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& aRv)
 {
   if (aChannel >= NumberOfChannels()) {
@@ -237,18 +247,24 @@ AudioBuffer::StealJSArrayDataIntoSharedC
   // "2. Neuter all ArrayBuffers for arrays previously returned by
   // getChannelData on this AudioBuffer."
   // "3. Retain the underlying data buffers from those ArrayBuffers and return
   // references to them to the invoker."
   RefPtr<ThreadSharedFloatArrayBufferList> result =
     new ThreadSharedFloatArrayBufferList(mJSChannels.Length());
   for (uint32_t i = 0; i < mJSChannels.Length(); ++i) {
     JS::Rooted<JSObject*> arrayBufferView(aJSContext, mJSChannels[i]);
+    bool isSharedMemory;
     JS::Rooted<JSObject*> arrayBuffer(aJSContext,
-                                      JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView));
+                                      JS_GetArrayBufferViewBuffer(aJSContext,
+                                                                  arrayBufferView,
+                                                                  &isSharedMemory));
+    // The channel data arrays should all have originated in
+    // RestoreJSChannelData, where they are created unshared.
+    MOZ_ASSERT(!isSharedMemory);
     auto stolenData = arrayBuffer
       ? static_cast<float*>(JS_StealArrayBufferContents(aJSContext,
                                                         arrayBuffer))
       : nullptr;
     if (stolenData) {
       result->SetData(i, stolenData, js_free, stolenData);
     } else {
       NS_ASSERTION(i == 0, "some channels lost when contents not acquired");
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -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/. */
 
 #include "AudioBufferSourceNode.h"
 #include "mozilla/dom/AudioBufferSourceNodeBinding.h"
 #include "mozilla/dom/AudioParam.h"
 #include "mozilla/FloatingPoint.h"
+#include "nsContentUtils.h"
 #include "nsMathUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
 #include "AudioParamTimeline.h"
 #include <limits>
 #include <algorithm>
 
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -29,16 +29,17 @@
 #include "ConvolverNode.h"
 #include "DelayNode.h"
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
 #include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "MediaStreamAudioSourceNode.h"
 #include "MediaStreamGraph.h"
+#include "nsContentUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "OscillatorNode.h"
 #include "PannerNode.h"
 #include "PeriodicWave.h"
 #include "ScriptProcessorNode.h"
 #include "StereoPannerNode.h"
@@ -567,16 +568,22 @@ AudioContext::DecodeAudioData(const Arra
 
   promise = Promise::Create(parentObject, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   aBuffer.ComputeLengthAndData();
 
+  if (aBuffer.IsShared()) {
+    // Throw if the object is mapping shared memory (must opt in).
+    aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of AudioContext.decodeAudioData"));
+    return nullptr;
+  }
+
   // Neuter the array buffer
   size_t length = aBuffer.Length();
   JS::RootedObject obj(cx, aBuffer.Obj());
 
   uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
 
   // Sniff the content of the media.
   // Failed type sniffing will be handled by AsyncDecodeWebAudio.
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -12,16 +12,17 @@
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
 #include "MediaDecoderReader.h"
 #include "BufferMediaResource.h"
 #include "DecoderTraits.h"
 #include "AudioContext.h"
 #include "AudioBuffer.h"
 #include "nsAutoPtr.h"
+#include "nsContentUtils.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsMimeTypes.h"
 #include "VideoUtils.h"
 #include "WebAudioUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/Telemetry.h"
 #include "nsPrintfCString.h"
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -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/. */
 
 #include "OscillatorNode.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
+#include "nsContentUtils.h"
 #include "WebAudioUtils.h"
 #include "blink/PeriodicWave.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(OscillatorNode, AudioNode,
                                    mPeriodicWave, mFrequency, mDetune)
--- a/dom/media/webaudio/WaveShaperNode.cpp
+++ b/dom/media/webaudio/WaveShaperNode.cpp
@@ -322,16 +322,21 @@ WaveShaperNode::WrapObject(JSContext *aC
 void
 WaveShaperNode::SetCurve(const Nullable<Float32Array>& aCurve, ErrorResult& aRv)
 {
   nsTArray<float> curve;
   if (!aCurve.IsNull()) {
     const Float32Array& floats = aCurve.Value();
 
     floats.ComputeLengthAndData();
+    if (floats.IsShared()) {
+      // Throw if the object is mapping shared memory (must opt in).
+      aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve"));
+      return;
+    }
 
     uint32_t argLength = floats.Length();
     if (argLength < 2) {
       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
 
     if (!curve.SetLength(argLength, fallible)) {
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "nsError.h"
 #include "MediaDecoderStateMachine.h"
 #include "AbstractMediaDecoder.h"
 #include "SoftwareWebMVideoDecoder.h"
+#include "nsContentUtils.h"
 #include "WebMReader.h"
 #include "WebMBufferedParser.h"
 #include "gfx2DGlue.h"
 #include "Layers.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SharedThreadPool.h"
 
 #include <algorithm>
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -270,17 +270,23 @@ nsSpeechTask::SendAudio(JS::Handle<JS::V
   if (!tsrc) {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
   uint32_t dataLen = JS_GetTypedArrayLength(tsrc);
   RefPtr<mozilla::SharedBuffer> samples;
   {
     JS::AutoCheckCannotGC nogc;
-    samples = makeSamples(JS_GetInt16ArrayData(tsrc, nogc), dataLen);
+    bool isShared;
+    int16_t* data = JS_GetInt16ArrayData(tsrc, &isShared, nogc);
+    if (isShared) {
+      // Must opt in to using shared data.
+      return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
+    }
+    samples = makeSamples(data, dataLen);
   }
   SendAudioImpl(samples, dataLen);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -9,16 +9,17 @@
 #include "TCPSocketChild.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/TCPSocketBinding.h"
 #include "mozilla/dom/TCPSocketErrorEvent.h"
 #include "mozilla/dom/TCPSocketErrorEventBinding.h"
 #include "mozilla/dom/TCPSocketEvent.h"
 #include "mozilla/dom/TCPSocketEventBinding.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "nsContentUtils.h"
 #include "nsIArrayBufferInputStream.h"
 #include "nsISocketTransportService.h"
 #include "nsISocketTransport.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIAsyncStreamCopier.h"
 #include "nsIInputStream.h"
 #include "nsIBinaryInputStream.h"
 #include "nsIScriptableInputStream.h"
--- a/dom/nfc/MozNDEFRecord.cpp
+++ b/dom/nfc/MozNDEFRecord.cpp
@@ -158,51 +158,68 @@ void
 MozNDEFRecord::GetAsURI(nsAString& aRetVal)
 {
   aRetVal.SetIsVoid(true);
   if (mTnf != TNF::Well_known) {
     return;
   }
 
   JS::AutoCheckCannotGC nogc;
-  uint8_t* typeData = JS_GetUint8ArrayData(mType, nogc);
+  bool isShared = false;
+  uint8_t* typeData = JS_GetUint8ArrayData(mType, &isShared, nogc);
+  if (isShared) {
+    return;                     // Must opt in to shared memory
+  }
   const char* uVal = RTDValues::strings[static_cast<uint32_t>(RTD::U)].value;
   if (typeData[0] != uVal[0]) {
     return;
   }
 
   uint32_t payloadLen;
   uint8_t* payloadData;
-  js::GetUint8ArrayLengthAndData(mPayload, &payloadLen, &payloadData);
+  js::GetUint8ArrayLengthAndData(mPayload, &payloadLen, &isShared, &payloadData);
+  if (isShared) {
+    return;                     // Must opt in to shared memory
+  }
   uint8_t id = payloadData[0];
   if (id >= static_cast<uint8_t>(WellKnownURIPrefix::EndGuard_)) {
     return;
   }
 
   using namespace mozilla::dom::WellKnownURIPrefixValues;
   aRetVal.AssignASCII(strings[id].value);
   aRetVal.Append(NS_ConvertUTF8toUTF16(
     nsDependentCSubstring(reinterpret_cast<char*>(&payloadData[1]), payloadLen - 1)));
 }
 
 bool
 MozNDEFRecord::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter) const
 {
   uint8_t* dummy;
   uint32_t typeLen = 0, idLen = 0, payloadLen = 0;
+  bool isShared;
   if (mType) {
-    js::GetUint8ArrayLengthAndData(mType, &typeLen, &dummy);
+    js::GetUint8ArrayLengthAndData(mType, &typeLen, &isShared, &dummy);
+    if (isShared) {
+      return false;             // Must opt in to shared memory
+    }
   }
 
   if (mId) {
-    js::GetUint8ArrayLengthAndData(mId, &idLen, &dummy);
+    js::GetUint8ArrayLengthAndData(mId, &idLen, &isShared, &dummy);
+    if (isShared) {
+      return false;             // Must opt in to shared memory
+    }
   }
 
   if (mPayload) {
-    js::GetUint8ArrayLengthAndData(mPayload, &payloadLen, &dummy);
+    js::GetUint8ArrayLengthAndData(mPayload, &payloadLen, &isShared, &dummy);
+    if (isShared) {
+      return false;             // Must opt in to shared memory
+    }
   }
 
   return JS_WriteUint32Pair(aWriter, static_cast<uint32_t>(mTnf), typeLen) &&
          JS_WriteUint32Pair(aWriter, idLen, payloadLen) &&
          WriteUint8Array(aCx, aWriter, mType, typeLen) &&
          WriteUint8Array(aCx, aWriter, mId, idLen) &&
          WriteUint8Array(aCx, aWriter, mPayload, payloadLen);
 }
@@ -317,17 +334,19 @@ MozNDEFRecord::InitPayload(JSContext* aC
   using namespace mozilla::dom::WellKnownURIPrefixValues;
 
   nsCString uri = NS_ConvertUTF16toUTF8(aUri);
   uint8_t id = GetURIIdentifier(uri);
   uri = Substring(uri, strings[id].length);
   mPayload = Uint8Array::Create(aCx, this, uri.Length() + 1);
 
   JS::AutoCheckCannotGC nogc;
-  uint8_t* data = JS_GetUint8ArrayData(mPayload, nogc);
+  bool isShared = false;
+  uint8_t* data = JS_GetUint8ArrayData(mPayload, &isShared, nogc);
+  MOZ_ASSERT(!isShared);         // Created as unshared above
   data[0] = id;
   memcpy(&data[1], reinterpret_cast<const uint8_t*>(uri.Data()), uri.Length());
   IncSizeForPayload(uri.Length() + 1);
 }
 
 void
 MozNDEFRecord::InitPayload(JSContext* aCx, JSObject& aPayload, uint32_t aLen)
 {
--- a/dom/plugins/base/PluginPRLibrary.h
+++ b/dom/plugins/base/PluginPRLibrary.h
@@ -116,16 +116,17 @@ public:
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP aInstance, bool* aDrawing) override;
     virtual nsresult ContentsScaleFactorChanged(NPP aInstance, double aContentsScaleFactor) override;
 #endif
     virtual nsresult SetBackgroundUnknown(NPP instance) override;
     virtual nsresult BeginUpdateBackground(NPP instance,
                                            const nsIntRect&, gfxContext** aCtx) override;
     virtual nsresult EndUpdateBackground(NPP instance,
                                          gfxContext* aCtx, const nsIntRect&) override;
+    virtual void DidComposite(NPP aInstance) override { }
     virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); }
     virtual nsresult GetRunID(uint32_t* aRunID) override { return NS_ERROR_NOT_IMPLEMENTED; }
     virtual void SetHasLocalInstance() override { }
 
 private:
     NP_InitializeFunc mNP_Initialize;
     NP_ShutdownFunc mNP_Shutdown;
     NP_GetMIMEDescriptionFunc mNP_GetMIMEDescription;
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -54,17 +54,17 @@
 #include <QRegion>
 #endif
 
 /*----------------------------------------------------------------------*/
 /*                        Plugin Version Constants                      */
 /*----------------------------------------------------------------------*/
 
 #define NP_VERSION_MAJOR 0
-#define NP_VERSION_MINOR 28
+#define NP_VERSION_MINOR 29
 
 
 /* The OS/2 version of Netscape uses RC_DATA to define the
    mime types, file extensions, etc that are required.
    Use a vertical bar to separate types, end types with \0.
    FileVersion and ProductVersion are 32bit ints, all other
    entries are strings that MUST be terminated with a \0.
 
@@ -181,16 +181,43 @@ typedef struct _NPSize
   int32_t height;
 } NPSize;
 
 typedef enum {
   NPFocusNext = 0,
   NPFocusPrevious = 1
 } NPFocusDirection;
 
+/* These formats describe the format in the memory byte-order. This means if
+ * a 32-bit value of a pixel is viewed on a little-endian system the layout will
+ * be 0xAARRGGBB. The Alpha channel will be stored in the most significant
+ * bits. */
+typedef enum {
+  /* 32-bit per pixel 8-bit per channel - premultiplied alpha */
+  NPImageFormatBGRA32     = 0x1,
+  /* 32-bit per pixel 8-bit per channel - 1 unused channel */
+  NPImageFormatBGRX32     = 0x2
+} NPImageFormat;
+
+typedef struct _NPAsyncSurface
+{
+  uint32_t version;
+  NPSize size;
+  NPImageFormat format;
+  union {
+    struct {
+      uint32_t stride;
+      void *data;
+    } bitmap;
+#if defined(XP_WIN)
+    HANDLE sharedHandle;
+#endif
+  };
+} NPAsyncSurface;
+
 /* Return values for NPP_HandleEvent */
 #define kNPEventNotHandled 0
 #define kNPEventHandled 1
 /* Exact meaning must be spec'd in event model. */
 #define kNPEventStartIME 2
 
 #if defined(XP_UNIX)
 /*
@@ -243,21 +270,19 @@ typedef enum {
   , NPDrawingModelInvalidatingCoreAnimation = 4
 #endif
 #if defined(XP_WIN)
   , NPDrawingModelSyncWin = 5
 #endif
 #if defined(MOZ_X11)
   , NPDrawingModelSyncX = 6
 #endif
-#if 0 /* OBSOLETE */
-  , NPDrawingModelAsyncBitmapSurfaceOBSOLETE = 7
+  , NPDrawingModelAsyncBitmapSurface = 7
 #if defined(XP_WIN)
-  , NPDrawingModelAsyncWindowsDXGISurfaceOBSOLETE = 8
-#endif
+  , NPDrawingModelAsyncWindowsDXGISurface = 8
 #endif
 } NPDrawingModel;
 
 #ifdef XP_MACOSX
 typedef enum {
 #ifndef NP_NO_CARBON
   NPEventModelCarbon = 0,
 #endif
@@ -393,21 +418,20 @@ typedef enum {
 #ifndef NP_NO_QUICKDRAW
   , NPNVsupportsQuickDrawBool = 2000
 #endif
   , NPNVsupportsCoreGraphicsBool = 2001
   , NPNVsupportsOpenGLBool = 2002
   , NPNVsupportsCoreAnimationBool = 2003
   , NPNVsupportsInvalidatingCoreAnimationBool = 2004
 #endif
-#if 0 /* OBSOLETE */
-  , NPNVsupportsAsyncBitmapSurfaceBoolOBSOLETE = 2007
+  , NPNVsupportsAsyncBitmapSurfaceBool = 2007
 #if defined(XP_WIN)
-  , NPNVsupportsAsyncWindowsDXGISurfaceBoolOBSOLETE = 2008
-#endif
+  , NPNVsupportsAsyncWindowsDXGISurfaceBool = 2008
+  , NPNVpreferredDXGIAdapter = 2009
 #endif
 #if defined(XP_MACOSX)
 #ifndef NP_NO_CARBON
   , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
 #endif
   , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
   , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
                                                     Cocoa text input specification. */
@@ -845,16 +869,21 @@ NPError     NPN_GetAuthenticationInfo(NP
                                       uint32_t *plen);
 uint32_t    NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 void        NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
 NPError     NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
 NPBool      NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 NPBool      NPN_HandleEvent(NPP instance, void *event, NPBool handled);
 NPBool      NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
 void        NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
+NPError     NPN_InitAsyncSurface(NPP instance, NPSize *size,
+                                 NPImageFormat format, void *initData,
+                                 NPAsyncSurface *surface);
+NPError     NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface);
+void        NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
 
 #ifdef __cplusplus
 }  /* end extern "C" */
 #endif
 
 #endif /* RC_INVOKED */
 
 #endif /* npapi_h_ */
--- a/dom/plugins/base/npfunctions.h
+++ b/dom/plugins/base/npfunctions.h
@@ -87,16 +87,19 @@ typedef NPError      (*NPN_SetValueForUR
 typedef NPError      (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen);
 typedef uint32_t     (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 typedef void         (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
 typedef NPError      (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
 typedef NPBool       (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 typedef NPBool       (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
 typedef NPBool       (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
 typedef void         (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
+typedef NPError      (*NPN_InitAsyncSurfacePtr)(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
+typedef NPError      (*NPN_FinalizeAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface);
+typedef void         (*NPN_SetCurrentAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface, NPRect *changed);
 
 typedef void         (*NPN_DummyPtr)(void);
 
 typedef struct _NPPluginFuncs {
   uint16_t size;
   uint16_t version;
   NPP_NewProcPtr newp;
   NPP_DestroyProcPtr destroy;
@@ -173,19 +176,19 @@ typedef struct _NPNetscapeFuncs {
   NPN_GetAuthenticationInfoPtr getauthenticationinfo;
   NPN_ScheduleTimerPtr scheduletimer;
   NPN_UnscheduleTimerPtr unscheduletimer;
   NPN_PopUpContextMenuPtr popupcontextmenu;
   NPN_ConvertPointPtr convertpoint;
   NPN_HandleEventPtr handleevent;
   NPN_UnfocusInstancePtr unfocusinstance;
   NPN_URLRedirectResponsePtr urlredirectresponse;
-  NPN_DummyPtr initasyncsurfaceOBSOLETE;
-  NPN_DummyPtr finalizeasyncsurfaceOBSOLETE;
-  NPN_DummyPtr setcurrentasyncsurfaceOBSOLETE;
+  NPN_InitAsyncSurfacePtr initasyncsurface;
+  NPN_FinalizeAsyncSurfacePtr finalizeasyncsurface;
+  NPN_SetCurrentAsyncSurfacePtr setcurrentasyncsurface;
 } NPNetscapeFuncs;
 
 #ifdef XP_MACOSX
 /*
  * Mac OS X version(s) of NP_GetMIMEDescription(const char *)
  * These can be called to retreive MIME information from the plugin dynamically
  *
  * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -21,17 +21,17 @@ enum nsPluginTagType {
   nsPluginTagType_Applet
 };
 %}
 
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 // Do not make this interface scriptable, because the virtual functions in C++
 // blocks will make script call the wrong functions.
-[uuid(518e7465-e1bc-4490-a30e-0ba9d791aaa8)]
+[uuid(7d65452e-c167-4cba-a0e3-ddc61bdde8c3)]
 interface nsIPluginInstanceOwner : nsISupports
 {
   /**
    * Let the owner know what its instance is
    */
   void setInstance(in nsNPAPIPluginInstancePtr aInstance);
 
   /**
@@ -96,16 +96,20 @@ interface nsIPluginInstanceOwner : nsISu
   void getNetscapeWindow(in voidPtr aValue);
 
   /**
    * Convert between plugin, window, and screen coordinate spaces.
    */
 %{C++
   virtual NPBool  ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                                double *destX, double *destY, NPCoordinateSpace destSpace) = 0;
+  virtual NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                   void *initData, NPAsyncSurface *surface) = 0;
+  virtual NPError FinalizeAsyncSurface(NPAsyncSurface *surface) = 0;
+  virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) = 0;
 %}
 
   void setEventModel(in int32_t eventModel);
 
   /**
    * Call NPP_SetWindow on the plugin.
    */
   void callSetWindow();
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -164,17 +164,20 @@ static NPNetscapeFuncs sBrowserFuncs = {
   _setvalueforurl,
   _getauthenticationinfo,
   _scheduletimer,
   _unscheduletimer,
   _popupcontextmenu,
   _convertpoint,
   nullptr, // handleevent, unimplemented
   nullptr, // unfocusinstance, unimplemented
-  _urlredirectresponse
+  _urlredirectresponse,
+  _initasyncsurface,
+  _finalizeasyncsurface,
+  _setcurrentasyncsurface
 };
 
 static Mutex *sPluginThreadAsyncCallLock = nullptr;
 static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls);
 
 // POST/GET stream type
 enum eNPPStreamTypeInternal {
   eNPPStreamTypeInternal_Get,
@@ -2775,11 +2778,44 @@ void
   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
   if (!inst) {
     return;
   }
 
   inst->URLRedirectResponse(notifyData, allow);
 }
 
+NPError
+_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface)
+{
+  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
+  if (!inst) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  return inst->InitAsyncSurface(size, format, initData, surface);
+}
+
+NPError
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
+{
+  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
+  if (!inst) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  return inst->FinalizeAsyncSurface(surface);
+}
+
+void
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
+{
+  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
+  if (!inst) {
+    return;
+  }
+
+  inst->SetCurrentAsyncSurface(surface, changed);
+}
+
 } /* namespace parent */
 } /* namespace plugins */
 } /* namespace mozilla */
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -315,16 +315,25 @@ void* /* OJI type: JRIEnv* */
 _getJavaEnv();
 
 void* /* OJI type: jref */
 _getJavaPeer(NPP npp);
 
 void
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
 
+NPError
+_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
+
+NPError
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
+
+void
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
+
 } /* namespace parent */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 const char *
 PeekException();
 
 void
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1062,22 +1062,18 @@ nsNPAPIPluginInstance* nsNPAPIPluginInst
 
   return it->second;
 }
 
 #endif
 
 nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel)
 {
-#if defined(XP_MACOSX)
   *aModel = (int32_t)mDrawingModel;
   return NS_OK;
-#else
-  return NS_ERROR_FAILURE;
-#endif
 }
 
 nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
 {
 #ifdef XP_MACOSX
   if (!mPlugin)
       return NS_ERROR_FAILURE;
 
@@ -1206,16 +1202,26 @@ nsNPAPIPluginInstance::GetImageSize(nsIn
 
   if (RUNNING != mRunning)
     return NS_OK;
 
   AutoPluginLibraryCall library(this);
   return !library ? NS_ERROR_FAILURE : library->GetImageSize(&mNPP, aSize);
 }
 
+void
+nsNPAPIPluginInstance::DidComposite()
+{
+  if (RUNNING != mRunning)
+    return;
+
+  AutoPluginLibraryCall library(this);
+  library->DidComposite(&mNPP);
+}
+
 nsresult
 nsNPAPIPluginInstance::NotifyPainted(void)
 {
   NS_NOTREACHED("Dead code, shouldn't be called.");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
@@ -1620,16 +1626,45 @@ nsNPAPIPluginInstance::URLRedirectRespon
   for (uint32_t i = 0; i < listenerCount; i++) {
     nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
     if (currentListener->GetNotifyData() == notifyData) {
       currentListener->URLRedirectResponse(allow);
     }
   }
 }
 
+NPError
+nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                        void *initData, NPAsyncSurface *surface)
+{
+  if (mOwner) {
+    return mOwner->InitAsyncSurface(size, format, initData, surface);
+  }
+
+  return NPERR_GENERIC_ERROR;
+}
+
+NPError
+nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface)
+{
+  if (mOwner) {
+    return mOwner->FinalizeAsyncSurface(surface);
+  }
+
+  return NPERR_GENERIC_ERROR;
+}
+
+void
+nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
+{
+  if (mOwner) {
+    mOwner->SetCurrentAsyncSurface(surface, changed);
+  }
+}
+
 class CarbonEventModelFailureEvent : public nsRunnable {
 public:
   nsCOMPtr<nsIContent> mContent;
 
   explicit CarbonEventModelFailureEvent(nsIContent* aContent)
     : mContent(aContent)
   {}
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -116,16 +116,17 @@ public:
   nsresult PopPopupsEnabledState();
   nsresult GetPluginAPIVersion(uint16_t* version);
   nsresult InvalidateRect(NPRect *invalidRect);
   nsresult InvalidateRegion(NPRegion invalidRegion);
   nsresult GetMIMEType(const char* *result);
   nsresult GetJSContext(JSContext* *outContext);
   nsPluginInstanceOwner* GetOwner();
   void SetOwner(nsPluginInstanceOwner *aOwner);
+  void DidComposite();
 
   bool HasAudioChannelAgent() const
   {
     return !!mAudioChannelAgent;
   }
 
   nsresult GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent);
 
@@ -287,16 +288,21 @@ public:
   nsTArray<nsNPAPIPluginStreamListener*> *StreamListeners();
 
   nsTArray<nsPluginStreamListenerPeer*> *FileCachedStreamListeners();
 
   nsresult AsyncSetWindow(NPWindow& window);
 
   void URLRedirectResponse(void* notifyData, NPBool allow);
 
+  NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
+                           void *initData, NPAsyncSurface *surface);
+  NPError FinalizeAsyncSurface(NPAsyncSurface *surface);
+  void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
+
   // Called when the instance fails to instantiate beceause the Carbon
   // event model is not supported.
   void CarbonNPAPIFailure();
 
   // Returns the contents scale factor of the screen the plugin is drawn on.
   double GetContentsScaleFactor();
 
   nsresult GetRunID(uint32_t *aRunID);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -245,16 +245,24 @@ nsPluginInstanceOwner::GetImageContainer
 #else
   mInstance->GetImageContainer(getter_AddRefs(container));
 #endif
 
   return container.forget();
 }
 
 void
+nsPluginInstanceOwner::DidComposite()
+{
+  if (mInstance) {
+    mInstance->DidComposite();
+  }
+}
+
+void
 nsPluginInstanceOwner::SetBackgroundUnknown()
 {
   if (mInstance) {
     mInstance->SetBackgroundUnknown();
   }
 }
 
 already_AddRefed<gfxContext>
@@ -595,19 +603,20 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
   RefPtr<ImageContainer> container;
   mInstance->GetImageContainer(getter_AddRefs(container));
 #endif
 
 #ifndef XP_MACOSX
   // Windowed plugins should not be calling NPN_InvalidateRect, but
   // Silverlight does and expects it to "work"
   if (mWidget) {
-    mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
-                                  invalidRect->right - invalidRect->left,
-                                  invalidRect->bottom - invalidRect->top));
+    mWidget->Invalidate(
+      LayoutDeviceIntRect(invalidRect->left, invalidRect->top,
+                          invalidRect->right - invalidRect->left,
+                          invalidRect->bottom - invalidRect->top));
     return NS_OK;
   }
 #endif
   nsIntRect rect(invalidRect->left,
                  invalidRect->top,
                  invalidRect->right - invalidRect->left,
                  invalidRect->bottom - invalidRect->top);
   // invalidRect is in "display pixels".  In non-HiDPI modes "display pixels"
@@ -1031,16 +1040,31 @@ NPBool nsPluginInstanceOwner::ConvertPoi
   return ConvertPointNoPuppet(mPluginFrame->GetNearestWidget(),
                               mPluginFrame, sourceX, sourceY, sourceSpace,
                               destX, destY, destSpace);
 #else
   return false;
 #endif
 }
 
+NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                                void *initData, NPAsyncSurface *surface)
+{
+  return NPERR_INCOMPATIBLE_VERSION_ERROR;
+}
+
+NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
+{
+  return NPERR_INCOMPATIBLE_VERSION_ERROR;
+}
+
+void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
+{
+}
+
 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
 {
   NS_ENSURE_ARG_POINTER(result);
 
   *result = nsPluginTagType_Unknown;
 
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
   if (content->IsHTMLElement(nsGkAtoms::applet))
@@ -2932,18 +2956,18 @@ NS_IMETHODIMP nsPluginInstanceOwner::Cre
     if (!mWidget) {
       // native (single process)
       mWidget = do_CreateInstance(kWidgetCID, &rv);
       nsWidgetInitData initData;
       initData.mWindowType = eWindowType_plugin;
       initData.mUnicode = false;
       initData.clipChildren = true;
       initData.clipSiblings = true;
-      rv = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0),
-                           &initData);
+      rv = mWidget->Create(parentWidget.get(), nullptr,
+                           LayoutDeviceIntRect(0, 0, 0, 0), &initData);
       if (NS_FAILED(rv)) {
         mWidget->Destroy();
         mWidget = nullptr;
         return rv;
       }
     }
 
 
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -61,17 +61,22 @@ public:
   
   NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
                     nsIInputStream *aPostStream, 
                     void *aHeadersData, uint32_t aHeadersDataLen,
                     bool aDoCheckLoadURIChecks) override;
   
   NPBool     ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                           double *destX, double *destY, NPCoordinateSpace destSpace) override;
-  
+
+  NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
+                           void *initData, NPAsyncSurface *surface) override;
+  NPError FinalizeAsyncSurface(NPAsyncSurface *surface) override;
+  void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) override;
+
   /**
    * Get the type of the HTML tag that was used ot instantiate this
    * plugin.  Currently supported tags are EMBED, OBJECT and APPLET.
    */
   NS_IMETHOD GetTagType(nsPluginTagType *aResult);
 
   void GetParameters(nsTArray<mozilla::dom::MozPluginParameter>& parameters);
   void GetAttributes(nsTArray<mozilla::dom::MozPluginParameter>& attributes);
@@ -208,16 +213,18 @@ public:
     return strncmp(GetPluginName(), aPluginName, strlen(aPluginName)) == 0;
   }
   
   void NotifyPaintWaiter(nsDisplayListBuilder* aBuilder);
 
   // Returns the image container that has our currently displayed image.
   already_AddRefed<mozilla::layers::ImageContainer> GetImageContainer();
 
+  void DidComposite();
+
   /**
    * Returns the bounds of the current async-rendered surface. This can only
    * change in response to messages received by the event loop (i.e. not during
    * painting).
    */
   nsIntSize GetCurrentImageSize();
   
   // Methods to update the background image we send to async plugins.
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/D3D11SurfaceHolder.cpp
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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 "nsDebug.h"
+#include "D3D11SurfaceHolder.h"
+#include "gfxWindowsPlatform.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/TextureD3D11.h"
+#include <d3d11.h>
+
+namespace mozilla {
+namespace plugins {
+
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+D3D11SurfaceHolder::D3D11SurfaceHolder(ID3D11Texture2D* back,
+                                       SurfaceFormat format,
+                                       const IntSize& size)
+ : mDevice11(gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice()),
+   mBack(back),
+   mFormat(format),
+   mSize(size)
+{
+}
+
+D3D11SurfaceHolder::~D3D11SurfaceHolder()
+{
+}
+
+bool
+D3D11SurfaceHolder::IsValid()
+{
+  // If a TDR occurred, platform devices will be recreated.
+  if (gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice() != mDevice11) {
+     return false;
+  }
+  return true;
+}
+
+bool
+D3D11SurfaceHolder::CopyToTextureClient(TextureClient* aClient)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  D3D11TextureData* data = aClient->GetInternalData()->AsD3D11TextureData();
+  if (!data) {
+    // We don't support this yet. We expect to have a D3D11 compositor, and
+    // therefore D3D11 surfaces.
+    NS_WARNING("Plugin DXGI surface has unsupported TextureClient");
+    return false;
+  }
+
+  RefPtr<ID3D11DeviceContext> context;
+  mDevice11->GetImmediateContext(getter_AddRefs(context));
+  if (!context) {
+    NS_WARNING("Could not get an immediate D3D11 context");
+    return false;
+  }
+
+  TextureClientAutoLock autoLock(aClient, OpenMode::OPEN_WRITE_ONLY);
+  if (!autoLock.Succeeded()) {
+    return false;
+  }
+
+  RefPtr<IDXGIKeyedMutex> mutex;
+  HRESULT hr = mBack->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)getter_AddRefs(mutex));
+  if (FAILED(hr) || !mutex) {
+    NS_WARNING("Could not acquire an IDXGIKeyedMutex");
+    return false;
+  }
+
+  hr = mutex->AcquireSync(0, 0);
+  if (hr == WAIT_ABANDONED || hr == WAIT_TIMEOUT || FAILED(hr)) {
+    NS_WARNING("Could not acquire DXGI surface lock - plugin forgot to release?");
+    return false;
+  }
+
+  context->CopyResource(data->GetD3D11Texture(), mBack);
+
+  mutex->ReleaseSync(0);
+  return true;
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/D3D11SurfaceHolder.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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 _include_dom_plugins_ipc_D3D11SurfaceHolder_h__
+#define _include_dom_plugins_ipc_D3D11SurfaceHolder_h__
+
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/gfx/Types.h"
+
+namespace mozilla {
+namespace layers {
+class D3D11ShareHandleImage;
+class TextureClient;
+} // namespace layers
+
+namespace plugins {
+
+class D3D11SurfaceHolder
+{
+public:
+  D3D11SurfaceHolder(ID3D11Texture2D* back, gfx::SurfaceFormat format, const gfx::IntSize& size);
+
+  NS_INLINE_DECL_REFCOUNTING(D3D11SurfaceHolder);
+
+  bool IsValid();
+  bool CopyToTextureClient(layers::TextureClient* aClient);
+
+  gfx::SurfaceFormat GetFormat() const {
+    return mFormat;
+  }
+  const gfx::IntSize& GetSize() const {
+    return mSize;
+  }
+
+private:
+  ~D3D11SurfaceHolder();
+
+private:
+  RefPtr<ID3D11Device> mDevice11;
+  RefPtr<ID3D11Texture2D> mBack;
+  gfx::SurfaceFormat mFormat;
+  gfx::IntSize mSize;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // _include_dom_plugins_ipc_D3D11nSurfaceHolder_h__
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -18,20 +18,24 @@ using struct mozilla::plugins::NPRemoteW
 using struct mozilla::plugins::NPRemoteEvent from "mozilla/plugins/PluginMessageUtils.h";
 using NPRect from "npapi.h";
 using NPNURLVariable from "npapi.h";
 using NPCoordinateSpace from "npapi.h";
 using NPNVariable from "npapi.h";
 using mozilla::plugins::NativeWindowHandle from "mozilla/plugins/PluginMessageUtils.h";
 using gfxSurfaceType from "gfxTypes.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
+using mozilla::gfx::IntRect from "mozilla/gfx/2D.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using mozilla::plugins::WindowsSharedMemoryHandle from "mozilla/plugins/PluginMessageUtils.h";
 using mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
 using nsIntRect from "nsRect.h";
+using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
+using struct DxgiAdapterDesc from "mozilla/D3DMessageUtils.h";
 
 namespace mozilla {
 namespace plugins {
 
 struct IOSurfaceDescriptor {
   uint32_t surfaceId;
   double contentsScaleFactor;
 };
@@ -141,16 +145,22 @@ parent:
   intr NPN_GetValue_NPNVprivateModeBool()
     returns (bool value, NPError result);
   intr NPN_GetValue_NPNVnetscapeWindow()
     returns (NativeWindowHandle value, NPError result);
   intr NPN_GetValue_NPNVdocumentOrigin()
     returns (nsCString value, NPError result);
   intr NPN_GetValue_DrawingModelSupport(NPNVariable model)
     returns (bool value);
+  intr NPN_GetValue_SupportsAsyncBitmapSurface()
+    returns (bool value);
+  intr NPN_GetValue_SupportsAsyncDXGISurface()
+    returns (bool value);
+  intr NPN_GetValue_PreferredDXGIAdapter()
+    returns (DxgiAdapterDesc desc);
 
   intr NPN_SetValue_NPPVpluginWindow(bool windowed)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginTransparent(bool transparent)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginUsesDOMForCursor(bool useDOMForCursor)
     returns (NPError result);
   intr NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
@@ -171,18 +181,42 @@ parent:
    *       but IPDL doesn't allow that for constructors.
    */
   intr PStreamNotify(nsCString url, nsCString target, bool post,
                     nsCString buffer, bool file)
     returns (NPError result);
 
   async NPN_InvalidateRect(NPRect rect);
 
+  // Clear the current plugin image.
+  sync RevokeCurrentDirectSurface();
+
+  // Create a new DXGI shared surface with the given format and size. The
+  // returned handle, on success, can be opened as an ID3D10Texture2D or
+  // ID3D11Texture2D on a corresponding device.
+  sync InitDXGISurface(SurfaceFormat format, IntSize size)
+    returns (WindowsHandle handle, NPError result);
+
+  // Destroy a surface previously allocated with InitDXGISurface().
+  sync FinalizeDXGISurface(WindowsHandle handle);
+
+  // Set the current plugin image to the bitmap in the given shmem buffer. The
+  // format must be B8G8R8A8 or B8G8R8X8.
+  sync ShowDirectBitmap(Shmem buffer,
+                        SurfaceFormat format,
+                        uint32_t stride,
+                        IntSize size,
+                        IntRect dirty);
+
+  // Set the current plugin image to the DXGI surface in |handle|.
+  sync ShowDirectDXGISurface(WindowsHandle handle,
+                              IntRect dirty);
+
   // Give |newSurface|, containing this instance's updated pixels, to
-  // the browser for compositing.  When this method returns, any surface 
+  // the browser for compositing.  When this method returns, any surface
   // previously passed to Show may be destroyed.
   //
   // @param rect - actually updated rectangle, comparing to prevSurface content
   //               could be used for partial render of layer to topLevel context
   // @param newSurface - remotable surface
   // @param prevSurface - if the previous surface was shared-memory, returns
   //                      the shmem for reuse
   sync Show(NPRect updatedRect, SurfaceDescriptor newSurface)
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -15,18 +15,20 @@
 #include "gfxPlatform.h"
 #include "gfx2DGlue.h"
 #include "nsNPAPIPluginInstance.h"
 #include "mozilla/gfx/2D.h"
 #ifdef MOZ_X11
 #include "gfxXlibSurface.h"
 #endif
 #ifdef XP_WIN
+#include "mozilla/D3DMessageUtils.h"
 #include "mozilla/gfx/SharedDIBSurface.h"
 #include "nsCrashOnException.h"
+#include "gfxWindowsPlatform.h"
 extern const wchar_t* kFlashFullscreenClass;
 using mozilla::gfx::SharedDIBSurface;
 #endif
 #include "gfxSharedImageSurface.h"
 #include "gfxUtils.h"
 #include "gfxAlphaRecovery.h"
 
 #include "mozilla/ArrayUtils.h"
@@ -126,16 +128,17 @@ PluginInstanceChild::PluginInstanceChild
     , mMimeType(aMimeType)
     , mMode(aMode)
     , mNames(aNames)
     , mValues(aValues)
 #if defined(XP_DARWIN)
     , mContentsScaleFactor(1.0)
 #endif
     , mDrawingModel(kDefaultDrawingModel)
+    , mCurrentDirectSurface(nullptr)
     , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
     , mAsyncInvalidateTask(0)
     , mCachedWindowActor(nullptr)
     , mCachedElementActor(nullptr)
 #ifdef MOZ_WIDGET_GTK
     , mXEmbed(false)
 #endif // MOZ_WIDGET_GTK
 #if defined(OS_WIN)
@@ -437,16 +440,43 @@ PluginInstanceChild::NPN_GetValue(NPNVar
         NPError result;
         CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result);
         return result;
 #else
         return NPERR_GENERIC_ERROR;
 #endif
     }
 
+    case NPNVsupportsAsyncBitmapSurfaceBool: {
+        bool value = false;
+        CallNPN_GetValue_SupportsAsyncBitmapSurface(&value);
+        *((NPBool*)aValue) = value;
+        return NPERR_NO_ERROR;
+    }
+
+#ifdef XP_WIN
+    case NPNVsupportsAsyncWindowsDXGISurfaceBool: {
+        bool value = false;
+        CallNPN_GetValue_SupportsAsyncDXGISurface(&value);
+        *((NPBool*)aValue) = value;
+        return NPERR_NO_ERROR;
+    }
+#endif
+
+#ifdef XP_WIN
+    case NPNVpreferredDXGIAdapter: {
+        DxgiAdapterDesc desc;
+        if (!CallNPN_GetValue_PreferredDXGIAdapter(&desc)) {
+            return NPERR_GENERIC_ERROR;
+        }
+        *reinterpret_cast<DXGI_ADAPTER_DESC*>(aValue) = desc.ToDesc();
+        return NPERR_NO_ERROR;
+    }
+#endif
+
 #ifdef XP_MACOSX
    case NPNVsupportsCoreGraphicsBool: {
         *((NPBool*)aValue) = true;
         return NPERR_NO_ERROR;
     }
 
     case NPNVsupportsCoreAnimationBool: {
         *((NPBool*)aValue) = true;
@@ -2526,16 +2556,262 @@ PluginInstanceChild::NPN_URLRedirectResp
         if (sn->mClosure == notifyData) {
             sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
             return;
         }
     }
     NS_ASSERTION(false, "Couldn't find stream for redirect response!");
 }
 
+bool
+PluginInstanceChild::IsUsingDirectDrawing()
+{
+    return IsDrawingModelDirect(mDrawingModel);
+}
+
+PluginInstanceChild::DirectBitmap::DirectBitmap(PluginInstanceChild* aOwner, const Shmem& shmem,
+                                                const IntSize& size, uint32_t stride, SurfaceFormat format)
+  : mOwner(aOwner),
+    mShmem(shmem),
+    mFormat(format),
+    mSize(size),
+    mStride(stride)
+{
+}
+
+PluginInstanceChild::DirectBitmap::~DirectBitmap()
+{
+    mOwner->DeallocShmem(mShmem);
+}
+
+static inline SurfaceFormat
+NPImageFormatToSurfaceFormat(NPImageFormat aFormat)
+{
+    switch (aFormat) {
+    case NPImageFormatBGRA32:
+        return SurfaceFormat::B8G8R8A8;
+    case NPImageFormatBGRX32:
+        return SurfaceFormat::B8G8R8X8;
+    default:
+        MOZ_ASSERT_UNREACHABLE("unknown NPImageFormat");
+        return SurfaceFormat::UNKNOWN;
+    }
+}
+
+static inline gfx::IntRect
+NPRectToIntRect(const NPRect& in)
+{
+    return IntRect(in.left, in.top, in.right - in.left, in.bottom - in.top);
+}
+
+NPError
+PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                          void *initData, NPAsyncSurface *surface)
+{
+    AssertPluginThread();
+
+    if (!IsUsingDirectDrawing()) {
+        return NPERR_INVALID_PARAM;
+    }
+    if (format != NPImageFormatBGRA32 && format != NPImageFormatBGRX32) {
+        return NPERR_INVALID_PARAM;
+    }
+
+    PodZero(surface);
+
+    // NPAPI guarantees that the SetCurrentAsyncSurface call will release the
+    // previous surface if it was different. However, no functionality exists
+    // within content to synchronize a non-shadow-layers transaction with the
+    // compositor.
+    //
+    // To get around this, we allocate two surfaces: a child copy, which we
+    // hand off to the plugin, and a parent copy, which we will hand off to
+    // the compositor. Each call to SetCurrentAsyncSurface will copy the
+    // invalid region from the child surface to its parent.
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+        // Validate that the caller does not expect initial data to be set.
+        if (initData) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        // Validate that we're not double-allocating a surface.
+        RefPtr<DirectBitmap> holder;
+        if (mDirectBitmaps.Get(surface, getter_AddRefs(holder))) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        SurfaceFormat mozformat = NPImageFormatToSurfaceFormat(format);
+        int32_t bytesPerPixel = BytesPerPixel(mozformat);
+
+        if (size->width <= 0 || size->height <= 0) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        CheckedInt<uint32_t> nbytes = SafeBytesForBitmap(size->width, size->height, bytesPerPixel);
+        if (!nbytes.isValid()) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        Shmem shmem;
+        if (!AllocUnsafeShmem(nbytes.value(), SharedMemory::TYPE_BASIC, &shmem)) {
+            return NPERR_OUT_OF_MEMORY_ERROR;
+        }
+        MOZ_ASSERT(shmem.Size<uint8_t>() == nbytes.value());
+
+        surface->version = 0;
+        surface->size = *size;
+        surface->format = format;
+        surface->bitmap.data = shmem.get<unsigned char>();
+        surface->bitmap.stride = size->width * bytesPerPixel;
+
+        // Hold the shmem alive until Finalize() is called or this actor dies.
+        holder = new DirectBitmap(this, shmem,
+                                  IntSize(size->width, size->height),
+                                  surface->bitmap.stride, mozformat);
+        mDirectBitmaps.Put(surface, holder);
+        return NPERR_NO_ERROR;
+    }
+#if defined(XP_WIN)
+    case NPDrawingModelAsyncWindowsDXGISurface: {
+        // Validate that the caller does not expect initial data to be set.
+        if (initData) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        // Validate that we're not double-allocating a surface.
+        WindowsHandle handle = 0;
+        if (mDxgiSurfaces.Get(surface, &handle)) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        NPError error = NPERR_NO_ERROR;
+        SurfaceFormat mozformat = NPImageFormatToSurfaceFormat(format);
+        if (!SendInitDXGISurface(mozformat,
+                                  IntSize(size->width, size->height),
+                                  &handle,
+                                  &error))
+        {
+            return NPERR_GENERIC_ERROR;
+        }
+        if (error != NPERR_NO_ERROR) {
+            return error;
+        }
+
+        surface->version = 0;
+        surface->size = *size;
+        surface->format = format;
+        surface->sharedHandle = reinterpret_cast<HANDLE>(handle);
+
+        mDxgiSurfaces.Put(surface, handle);
+        return NPERR_NO_ERROR;
+    }
+#endif
+    default:
+        MOZ_ASSERT_UNREACHABLE("unknown drawing model");
+    }
+
+    return NPERR_INVALID_PARAM;
+}
+
+NPError
+PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
+{
+    AssertPluginThread();
+
+    if (!IsUsingDirectDrawing()) {
+        return NPERR_GENERIC_ERROR;
+    }
+
+    // The API forbids this. If it becomes a problem we can revoke the current
+    // surface instead.
+    MOZ_ASSERT(!surface || mCurrentDirectSurface != surface);
+
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+        RefPtr<DirectBitmap> bitmap;
+        if (!mDirectBitmaps.Get(surface, getter_AddRefs(bitmap))) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        PodZero(surface);
+        mDirectBitmaps.Remove(surface);
+        return NPERR_NO_ERROR;
+    }
+#if defined(XP_WIN)
+    case NPDrawingModelAsyncWindowsDXGISurface: {
+        WindowsHandle handle;
+        if (!mDxgiSurfaces.Get(surface, &handle)) {
+            return NPERR_INVALID_PARAM;
+        }
+
+        SendFinalizeDXGISurface(handle);
+        mDxgiSurfaces.Remove(surface);
+        return NPERR_NO_ERROR;
+    }
+#endif
+    default:
+        MOZ_ASSERT_UNREACHABLE("unknown drawing model");
+    }
+
+    return NPERR_INVALID_PARAM;
+}
+
+void
+PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
+{
+    AssertPluginThread();
+
+    if (!IsUsingDirectDrawing()) {
+        return;
+    }
+
+    mCurrentDirectSurface = surface;
+
+    if (!surface) {
+        SendRevokeCurrentDirectSurface();
+        return;
+    }
+
+    switch (mDrawingModel) {
+    case NPDrawingModelAsyncBitmapSurface: {
+        RefPtr<DirectBitmap> bitmap;
+        if (!mDirectBitmaps.Get(surface, getter_AddRefs(bitmap))) {
+            return;
+        }
+
+        IntRect dirty = changed
+                        ? NPRectToIntRect(*changed)
+                        : IntRect(IntPoint(0, 0), bitmap->mSize);
+
+        // Need a holder since IPDL zaps the object for mysterious reasons.
+        Shmem shmemHolder = bitmap->mShmem;
+        SendShowDirectBitmap(shmemHolder, bitmap->mFormat, bitmap->mStride, bitmap->mSize, dirty);
+        break;
+    }
+#if defined(XP_WIN)
+    case NPDrawingModelAsyncWindowsDXGISurface: {
+        WindowsHandle handle;
+        if (!mDxgiSurfaces.Get(surface, &handle)) {
+            return;
+        }
+
+        IntRect dirty = changed
+                        ? NPRectToIntRect(*changed)
+                        : IntRect(IntPoint(0, 0), IntSize(surface->size.width, surface->size.height));
+
+        SendShowDirectDXGISurface(handle, dirty);
+        break;
+    }
+#endif
+    default:
+        MOZ_ASSERT_UNREACHABLE("unknown drawing model");
+    }
+}
+
 void
 PluginInstanceChild::DoAsyncRedraw()
 {
     {
         MutexAutoLock autoLock(mAsyncInvalidateMutex);
         mAsyncInvalidateTask = nullptr;
     }
 
@@ -2949,16 +3225,19 @@ PluginInstanceChild::UpdateWindowAttribu
 }
 
 void
 PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
                                                 gfxASurface* aSurface)
 {
     UpdateWindowAttributes();
 
+    // We should not send an async surface if we're using direct rendering.
+    MOZ_ASSERT(!IsUsingDirectDrawing());
+
 #ifdef MOZ_X11
     {
         NS_ASSERTION(aSurface->GetType() == gfxSurfaceType::Xlib,
                      "Non supported platform surface type");
 
         NPEvent pluginEvent;
         XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
         exposeEvent.type = GraphicsExpose;
@@ -3184,16 +3463,20 @@ PluginInstanceChild::ShowPluginFrame()
     // mLayersRendering can be false if we somehow get here without
     // receiving AsyncSetWindow() first.  mPendingPluginCall is our
     // re-entrancy guard; we can't paint while nested inside another
     // paint.
     if (!mLayersRendering || mPendingPluginCall) {
         return false;
     }
 
+    // We should not attempt to asynchronously show the plugin if we're using
+    // direct rendering.
+    MOZ_ASSERT(!IsUsingDirectDrawing());
+
     AutoRestore<bool> pending(mPendingPluginCall);
     mPendingPluginCall = true;
 
     bool temporarilyMakeVisible = !IsVisible() && !mHasPainted;
     if (temporarilyMakeVisible && mWindow.width && mWindow.height) {
         mWindow.clipRect.right = mWindow.width;
         mWindow.clipRect.bottom = mWindow.height;
     } else if (!IsVisible()) {
@@ -3463,16 +3746,23 @@ PluginInstanceChild::InvalidateRectDelay
 
 void
 PluginInstanceChild::AsyncShowPluginFrame(void)
 {
     if (mCurrentInvalidateTask) {
         return;
     }
 
+    // When the plugin is using direct surfaces to draw, it is not driving
+    // paints via paint events - it will drive painting via its own events
+    // and/or DidComposite callbacks.
+    if (IsUsingDirectDrawing()) {
+        return;
+    }
+
     mCurrentInvalidateTask =
         NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed);
     MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask);
 }
 
 void
 PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
 {
@@ -3484,16 +3774,21 @@ PluginInstanceChild::InvalidateRect(NPRe
       NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!");
       RECT rect = { aInvalidRect->left, aInvalidRect->top,
                     aInvalidRect->right, aInvalidRect->bottom };
       ::InvalidateRect(mPluginWindowHWND, &rect, FALSE);
       return;
     }
 #endif
 
+    if (IsUsingDirectDrawing()) {
+        NS_ASSERTION(false, "Should not call InvalidateRect() in direct surface mode!");
+        return;
+    }
+
     if (mLayersRendering) {
         nsIntRect r(aInvalidRect->left, aInvalidRect->top,
                     aInvalidRect->right - aInvalidRect->left,
                     aInvalidRect->bottom - aInvalidRect->top);
 
         mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect);
         // If we are able to paint and invalidate sent, then reset
         // accumulated rectangle
@@ -3823,16 +4118,17 @@ PluginInstanceChild::Destroy()
         MutexAutoLock autoLock(mAsyncInvalidateMutex);
         if (mAsyncInvalidateTask) {
             mAsyncInvalidateTask->Cancel();
             mAsyncInvalidateTask = nullptr;
         }
     }
 
     ClearAllSurfaces();
+    mDirectBitmaps.Clear();
 
     mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
     PluginScriptableObjectChild::NotifyOfInstanceShutdown(this);
 
     InvalidateObjects(*mDeletingHash);
     DeleteObjects(*mDeletingHash);
 
     // Null out our cached actors as they should have been killed in the
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -7,17 +7,17 @@
 #ifndef dom_plugins_PluginInstanceChild_h
 #define dom_plugins_PluginInstanceChild_h 1
 
 #include "mozilla/plugins/PPluginInstanceChild.h"
 #include "mozilla/plugins/PluginScriptableObjectChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/PPluginSurfaceChild.h"
 #include "mozilla/ipc/CrossProcessMutex.h"
-#include "nsClassHashtable.h"
+#include "nsRefPtrHashtable.h"
 #if defined(OS_WIN)
 #include "mozilla/gfx/SharedDIBWin.h"
 #elif defined(MOZ_WIDGET_COCOA)
 #include "PluginUtilsOSX.h"
 #include "mozilla/gfx/QuartzSupport.h"
 #include "base/timer.h"
 
 #endif
@@ -25,16 +25,17 @@
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "ChildAsyncCall.h"
 #include "ChildTimer.h"
 #include "nsRect.h"
 #include "nsTHashtable.h"
 #include "mozilla/PaintTracker.h"
+#include "mozilla/gfx/Types.h"
 
 #include <map>
 
 #ifdef MOZ_WIDGET_GTK
 #include "gtk2xtbin.h"
 #endif
 
 class gfxASurface;
@@ -256,25 +257,32 @@ public:
     void AsyncCall(PluginThreadCallback aFunc, void* aUserData);
     // This function is a more general version of AsyncCall
     void PostChildAsyncCall(ChildAsyncCall* aTask);
 
     int GetQuirks();
 
     void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
 
+
+    NPError NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
+                                 void *initData, NPAsyncSurface *surface);
+    NPError NPN_FinalizeAsyncSurface(NPAsyncSurface *surface);
+
+    void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
+
     void DoAsyncRedraw();
 private:
     friend class PluginModuleChild;
 
     NPError
     InternalGetNPObjectForValue(NPNVariable aValue,
                                 NPObject** aObject);
 
-    bool IsAsyncDrawing();
+    bool IsUsingDirectDrawing();
 
     virtual bool RecvUpdateBackground(const SurfaceDescriptor& aBackground,
                                       const nsIntRect& aRect) override;
 
     virtual PPluginBackgroundDestroyerChild*
     AllocPPluginBackgroundDestroyerChild() override;
 
     virtual bool
@@ -382,16 +390,43 @@ private:
     InfallibleTArray<nsCString> mValues;
     NPP_t mData;
     NPWindow mWindow;
 #if defined(XP_DARWIN)
     double mContentsScaleFactor;
 #endif
     int16_t               mDrawingModel;
 
+    NPAsyncSurface* mCurrentDirectSurface;
+
+    // The surface hashtables below serve a few purposes. They let us verify
+    // and retain extra information about plugin surfaces, and they let us
+    // free shared memory that the plugin might forget to release.
+    struct DirectBitmap {
+        DirectBitmap(PluginInstanceChild* aOwner, const Shmem& shmem,
+                     const gfx::IntSize& size, uint32_t stride, SurfaceFormat format);
+
+      private:
+        ~DirectBitmap();
+
+      public:
+        NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DirectBitmap);
+
+        PluginInstanceChild* mOwner;
+        Shmem mShmem;
+        gfx::SurfaceFormat mFormat;
+        gfx::IntSize mSize;
+        uint32_t mStride;
+    };
+    nsRefPtrHashtable<nsPtrHashKey<NPAsyncSurface>, DirectBitmap> mDirectBitmaps;
+
+#if defined(XP_WIN)
+    nsDataHashtable<nsPtrHashKey<NPAsyncSurface>, WindowsHandle> mDxgiSurfaces;
+#endif
+
     mozilla::Mutex mAsyncInvalidateMutex;
     CancelableTask *mAsyncInvalidateTask;
 
     // Cached scriptable actors to avoid IPC churn
     PluginScriptableObjectChild* mCachedWindowActor;
     PluginScriptableObjectChild* mCachedElementActor;
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -32,16 +32,25 @@
 #endif
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "Layers.h"
 #include "ImageContainer.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
+#include "gfxPrefs.h"
+#include "LayersLogging.h"
+#include "mozilla/layers/TextureWrapperImage.h"
+#include "mozilla/layers/TextureClientRecycleAllocator.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#if defined(XP_WIN)
+# include "mozilla/layers/D3D11ShareHandleImage.h"
+# include "mozilla/layers/TextureD3D11.h"
+#endif
 
 #ifdef XP_MACOSX
 #include "MacIOSurfaceImage.h"
 #endif
 
 #if defined(OS_WIN)
 #include <windowsx.h>
 #include "gfxWindowsPlatform.h"
@@ -111,16 +120,17 @@ PluginInstanceParent::PluginInstancePare
     : mParent(parent)
     , mSurrogate(PluginAsyncSurrogate::Cast(npp))
     , mUseSurrogate(true)
     , mNPP(npp)
     , mNPNIface(npniface)
     , mIsWhitelistedForShumway(false)
     , mWindowType(NPWindowTypeWindow)
     , mDrawingModel(kDefaultDrawingModel)
+    , mFrameID(0)
 #if defined(OS_WIN)
     , mPluginHWND(nullptr)
     , mChildPluginHWND(nullptr)
     , mChildPluginsParentHWND(nullptr)
     , mPluginWndProc(nullptr)
     , mNestedEventState(false)
 #endif // defined(XP_WIN)
 #if defined(XP_MACOSX)
@@ -184,16 +194,19 @@ PluginInstanceParent::ActorDestroy(Actor
         mFrontSurface = nullptr;
         if (mImageContainer) {
             mImageContainer->ClearAllImages();
         }
 #ifdef MOZ_X11
         FinishX(DefaultXDisplay());
 #endif
     }
+    if (IsUsingDirectDrawing() && mImageContainer) {
+        mImageContainer->ClearAllImages();
+    }
 }
 
 NPError
 PluginInstanceParent::Destroy()
 {
     NPError retval;
     {   // Scope for timer
         Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_INSTANCE_DESTROY_MS>
@@ -205,16 +218,22 @@ PluginInstanceParent::Destroy()
 
 #if defined(OS_WIN)
     UnsubclassPluginWindow();
 #endif
 
     return retval;
 }
 
+bool
+PluginInstanceParent::IsUsingDirectDrawing()
+{
+    return IsDrawingModelDirect(mDrawingModel);
+}
+
 PBrowserStreamParent*
 PluginInstanceParent::AllocPBrowserStreamParent(const nsCString& url,
                                                 const uint32_t& length,
                                                 const uint32_t& lastmodified,
                                                 PStreamNotifyParent* notifyData,
                                                 const nsCString& headers)
 {
     NS_RUNTIMEABORT("Not reachable");
@@ -337,16 +356,85 @@ PluginInstanceParent::AnswerNPN_GetValue
     void *v = nullptr;
     *result = mNPNIface->getvalue(mNPP, NPNVdocumentOrigin, &v);
     if (*result == NPERR_NO_ERROR && v) {
         value->Adopt(static_cast<char*>(v));
     }
     return true;
 }
 
+static inline bool
+AllowDirectBitmapSurfaceDrawing()
+{
+    if (!gfxPrefs::PluginAsyncDrawingEnabled()) {
+        return false;
+    }
+    return gfxPlatform::GetPlatform()->SupportsPluginDirectBitmapDrawing();
+}
+
+static inline bool
+AllowDirectDXGISurfaceDrawing()
+{
+    if (!gfxPrefs::PluginAsyncDrawingEnabled()) {
+        return false;
+    }
+#if defined(XP_WIN)
+    return gfxWindowsPlatform::GetPlatform()->SupportsPluginDirectDXGIDrawing();
+#else
+    return false;
+#endif
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_SupportsAsyncBitmapSurface(bool* value)
+{
+    *value = AllowDirectBitmapSurfaceDrawing();
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_SupportsAsyncDXGISurface(bool* value)
+{
+    *value = AllowDirectDXGISurfaceDrawing();
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_PreferredDXGIAdapter(DxgiAdapterDesc* aOutDesc)
+{
+    PodZero(aOutDesc);
+#ifdef XP_WIN
+    if (!AllowDirectDXGISurfaceDrawing()) {
+        return false;
+    }
+
+    ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
+    if (!device) {
+        return false;
+    }
+
+    RefPtr<IDXGIDevice> dxgi;
+    if (FAILED(device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgi))) || !dxgi) {
+        return false;
+    }
+    RefPtr<IDXGIAdapter> adapter;
+    if (FAILED(dxgi->GetAdapter(getter_AddRefs(adapter))) || !adapter) {
+        return false;
+    }
+
+    DXGI_ADAPTER_DESC desc;
+    if (FAILED(adapter->GetDesc(&desc))) {
+         return false;
+    }
+
+    *aOutDesc = DxgiAdapterDesc::From(desc);
+#endif
+    return true;
+}
+
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
     const bool& windowed, NPError* result)
 {
     // Yes, we are passing a boolean as a void*.  We have to cast to intptr_t
     // first to avoid gcc warnings about casting to a pointer from a
     // non-pointer-sized integer.
     *result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
@@ -371,45 +459,68 @@ PluginInstanceParent::AnswerNPN_SetValue
                                   (void*)(intptr_t)useDOMForCursor);
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
     const int& drawingModel, NPError* result)
 {
+    bool allowed = false;
+
+    switch (drawingModel) {
+#if defined(XP_MACOSX)
+        case NPDrawingModelCoreAnimation:
+        case NPDrawingModelInvalidatingCoreAnimation:
+        case NPDrawingModelOpenGL:
+        case NPDrawingModelCoreGraphics:
+            allowed = true;
+            break;
+#elif defined(XP_WIN)
+        case NPDrawingModelSyncWin:
+            allowed = true;
+            break;
+        case NPDrawingModelAsyncWindowsDXGISurface:
+            allowed = AllowDirectDXGISurfaceDrawing();
+            break;
+#elif defined(MOZ_X11)
+        case NPDrawingModelSyncX:
+            allowed = true;
+            break;
+#endif
+        case NPDrawingModelAsyncBitmapSurface:
+            allowed = AllowDirectBitmapSurfaceDrawing();
+            break;
+        default:
+            allowed = false;
+            break;
+    }
+
+    if (!allowed) {
+        *result = NPERR_GENERIC_ERROR;
+        return true;
+    }
+
+    mDrawingModel = drawingModel;
+
+    int requestModel = drawingModel;
+
 #ifdef XP_MACOSX
     if (drawingModel == NPDrawingModelCoreAnimation ||
         drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
         // We need to request CoreGraphics otherwise
         // the nsPluginFrame will try to draw a CALayer
         // that can not be shared across process.
-        mDrawingModel = drawingModel;
-        *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
-                                  (void*)NPDrawingModelCoreGraphics);
-    } else
+        requestModel = NPDrawingModelCoreGraphics;
+    }
 #endif
-    if (
-#if defined(XP_WIN)
-               drawingModel == NPDrawingModelSyncWin
-#elif defined(XP_MACOSX)
-               drawingModel == NPDrawingModelOpenGL ||
-               drawingModel == NPDrawingModelCoreGraphics
-#elif defined(MOZ_X11)
-               drawingModel == NPDrawingModelSyncX
-#else
-               false
-#endif
-               ) {
-        mDrawingModel = drawingModel;
-        *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
-                                      (void*)(intptr_t)drawingModel);
-    } else {
-        *result = NPERR_GENERIC_ERROR;
-    }
+
+    *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
+                                  (void*)(intptr_t)requestModel);
+
     return true;
 }
 
 bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
     const int& eventModel, NPError* result)
 {
 #ifdef XP_MACOSX
@@ -517,27 +628,253 @@ PluginInstanceParent::DeallocPStreamNoti
 
 bool
 PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
 {
     mNPNIface->invalidaterect(mNPP, const_cast<NPRect*>(&rect));
     return true;
 }
 
+static inline NPRect
+IntRectToNPRect(const gfx::IntRect& rect)
+{
+    NPRect r;
+    r.left = rect.x;
+    r.top = rect.y;
+    r.right = rect.x + rect.width;
+    r.bottom = rect.y + rect.height;
+    return r;
+}
+
+bool
+PluginInstanceParent::RecvRevokeCurrentDirectSurface()
+{
+    ImageContainer *container = GetImageContainer();
+    if (!container) {
+        return true;
+    }
+
+    container->ClearAllImages();
+
+    PLUGIN_LOG_DEBUG(("   (RecvRevokeCurrentDirectSurface)"));
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvInitDXGISurface(const gfx::SurfaceFormat& format,
+                                           const gfx::IntSize& size,
+                                           WindowsHandle* outHandle,
+                                           NPError* outError)
+{
+    *outHandle = 0;
+    *outError = NPERR_GENERIC_ERROR;
+
+#if defined(XP_WIN)
+    if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
+        *outError = NPERR_INVALID_PARAM;
+        return true;
+    }
+    if (size.width <= 0 || size.height <= 0) {
+        *outError = NPERR_INVALID_PARAM;
+        return true;
+    }
+
+    ImageContainer *container = GetImageContainer();
+    if (!container) {
+        return true;
+    }
+
+    ImageBridgeChild* forwarder = ImageBridgeChild::GetSingleton();
+    if (!forwarder) {
+        return true;
+    }
+
+    RefPtr<ID3D11Device> d3d11 = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
+    if (!d3d11) {
+        return true;
+    }
+
+    // Create the texture we'll give to the plugin process.
+    HANDLE sharedHandle = 0;
+    RefPtr<ID3D11Texture2D> back;
+    {
+        CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, size.width, size.height, 1, 1);
+        desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+        if (FAILED(d3d11->CreateTexture2D(&desc, nullptr, getter_AddRefs(back))) || !back) {
+            return true;
+        }
+
+        RefPtr<IDXGIResource> resource;
+        if (FAILED(back->QueryInterface(IID_IDXGIResource, getter_AddRefs(resource))) || !resource) {
+            return true;
+        }
+        if (FAILED(resource->GetSharedHandle(&sharedHandle) || !sharedHandle)) {
+            return true;
+        }
+    }
+
+    RefPtr<D3D11SurfaceHolder> holder = new D3D11SurfaceHolder(back, format, size);
+    mD3D11Surfaces.Put(reinterpret_cast<void*>(sharedHandle), holder);
+
+    *outHandle = reinterpret_cast<uintptr_t>(sharedHandle);
+    *outError = NPERR_NO_ERROR;
+#endif
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvFinalizeDXGISurface(const WindowsHandle& handle)
+{
+#if defined(XP_WIN)
+    mD3D11Surfaces.Remove(reinterpret_cast<void*>(handle));
+#endif
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvShowDirectBitmap(Shmem&& buffer,
+                                           const SurfaceFormat& format,
+                                           const uint32_t& stride,
+                                           const IntSize& size,
+                                           const IntRect& dirty)
+{
+    // Validate format.
+    if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
+        MOZ_ASSERT_UNREACHABLE("bad format type");
+        return false;
+    }
+    if (size.width <= 0 || size.height <= 0) {
+        MOZ_ASSERT_UNREACHABLE("bad image size");
+        return false;
+    }
+    if (mDrawingModel != NPDrawingModelAsyncBitmapSurface) {
+        MOZ_ASSERT_UNREACHABLE("plugin did not set a bitmap drawing model");
+        return false;
+    }
+
+    // Validate buffer and size.
+    CheckedInt<uint32_t> nbytes = CheckedInt<uint32_t>(uint32_t(size.height)) * stride;
+    if (!nbytes.isValid() || nbytes.value() != buffer.Size<uint8_t>()) {
+        MOZ_ASSERT_UNREACHABLE("bad shmem size");
+        return false;
+    }
+
+    ImageContainer* container = GetImageContainer();
+    if (!container) {
+        return false;
+    }
+
+    RefPtr<gfx::DataSourceSurface> source =
+        gfx::Factory::CreateWrappingDataSourceSurface(buffer.get<uint8_t>(), stride, size, format);
+    if (!source) {
+        return false;
+    }
+
+    // Allocate a texture for the compositor.
+    RefPtr<TextureClientRecycleAllocator> allocator = mParent->EnsureTextureAllocator();
+    RefPtr<TextureClient> texture = allocator->CreateOrRecycle(
+        format, size, BackendSelector::Content,
+        TextureFlags::NO_FLAGS,
+        ALLOC_FOR_OUT_OF_BAND_CONTENT);
+    if (!texture) {
+        NS_WARNING("Could not allocate a TextureClient for plugin!");
+        return false;
+    }
+
+    // Upload the plugin buffer.
+    {
+        TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
+        if (!autoLock.Succeeded()) {
+            return false;
+        }
+        texture->UpdateFromSurface(source);
+    }
+
+    // Wrap the texture in an image and ship it off.
+    RefPtr<TextureWrapperImage> image =
+        new TextureWrapperImage(texture, gfx::IntRect(gfx::IntPoint(0, 0), size));
+    SetCurrentImage(image);
+
+    PLUGIN_LOG_DEBUG(("   (RecvShowDirectBitmap received shmem=%p stride=%d size=%s dirty=%s)",
+        buffer.get<unsigned char>(), stride, Stringify(size).c_str(), Stringify(dirty).c_str()));
+    return true;
+}
+
+void
+PluginInstanceParent::SetCurrentImage(Image* aImage)
+{
+    MOZ_ASSERT(IsUsingDirectDrawing());
+    ImageContainer::NonOwningImage holder(aImage);
+    holder.mFrameID = ++mFrameID;
+
+    nsAutoTArray<ImageContainer::NonOwningImage,1> imageList;
+    imageList.AppendElement(holder);
+    mImageContainer->SetCurrentImages(imageList);
+}
+
+bool
+PluginInstanceParent::RecvShowDirectDXGISurface(const WindowsHandle& handle,
+                                                 const gfx::IntRect& dirty)
+{
+#if defined(XP_WIN)
+    RefPtr<D3D11SurfaceHolder> surface;
+    if (!mD3D11Surfaces.Get(reinterpret_cast<void*>(handle), getter_AddRefs(surface))) {
+        return false;
+    }
+    if (!surface->IsValid()) {
+        return false;
+    }
+
+    ImageContainer* container = GetImageContainer();
+    if (!container) {
+        return false;
+    }
+
+    RefPtr<TextureClientRecycleAllocator> allocator = mParent->EnsureTextureAllocator();
+    RefPtr<TextureClient> texture = allocator->CreateOrRecycle(
+        surface->GetFormat(), surface->GetSize(),
+        BackendSelector::Content,
+        TextureFlags::NO_FLAGS,
+        ALLOC_FOR_OUT_OF_BAND_CONTENT);
+    if (!texture) {
+        NS_WARNING("Could not allocate a TextureClient for plugin!");
+        return false;
+    }
+
+    surface->CopyToTextureClient(texture);
+
+    gfx::IntSize size(surface->GetSize());
+    gfx::IntRect pictureRect(gfx::IntPoint(0, 0), size);
+
+    // Wrap the texture in an image and ship it off.
+    RefPtr<TextureWrapperImage> image = new TextureWrapperImage(texture, pictureRect);
+    SetCurrentImage(image);
+
+    PLUGIN_LOG_DEBUG(("   (RecvShowDirect3D10Surface received handle=%p rect=%s)",
+        reinterpret_cast<void*>(handle), Stringify(dirty).c_str()));
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool
 PluginInstanceParent::RecvShow(const NPRect& updatedRect,
                                const SurfaceDescriptor& newSurface,
                                SurfaceDescriptor* prevSurface)
 {
     PLUGIN_LOG_DEBUG(
         ("[InstanceParent][%p] RecvShow for <x=%d,y=%d, w=%d,h=%d>",
          this, updatedRect.left, updatedRect.top,
          updatedRect.right - updatedRect.left,
          updatedRect.bottom - updatedRect.top));
 
+    MOZ_ASSERT(!IsUsingDirectDrawing());
+
     // XXXjwatt rewrite to use Moz2D
     RefPtr<gfxASurface> surface;
     if (newSurface.type() == SurfaceDescriptor::TShmem) {
         if (!newSurface.get_Shmem().IsReadable()) {
             NS_WARNING("back surface not readable");
             return false;
         }
         surface = gfxSharedImageSurface::Open(newSurface.get_Shmem());
@@ -666,16 +1003,26 @@ PluginInstanceParent::AsyncSetWindow(NPW
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 nsresult
 PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
 {
+    if (IsUsingDirectDrawing()) {
+        // Use the image container created by the most recent direct surface
+        // call, if any. We don't create one if no surfaces were presented
+        // yet.
+        ImageContainer *container = mImageContainer;
+        NS_IF_ADDREF(container);
+        *aContainer = container;
+        return NS_OK;
+    }
+
 #ifdef XP_MACOSX
     MacIOSurface* ioSurface = nullptr;
 
     if (mFrontIOSurface) {
       ioSurface = mFrontIOSurface;
     } else if (mIOSurface) {
       ioSurface = mIOSurface;
     }
@@ -706,16 +1053,24 @@ PluginInstanceParent::GetImageContainer(
     NS_IF_ADDREF(container);
     *aContainer = container;
     return NS_OK;
 }
 
 nsresult
 PluginInstanceParent::GetImageSize(nsIntSize* aSize)
 {
+    if (IsUsingDirectDrawing()) {
+        if (!mImageContainer) {
+            return NS_ERROR_NOT_AVAILABLE;
+        }
+        *aSize = mImageContainer->GetCurrentSize();
+        return NS_OK;
+    }
+
     if (mFrontSurface) {
         mozilla::gfx::IntSize size = mFrontSurface->GetSize();
         *aSize = nsIntSize(size.width, size.height);
         return NS_OK;
     }
 
 #ifdef XP_MACOSX
     if (mFrontIOSurface) {
@@ -725,16 +1080,25 @@ PluginInstanceParent::GetImageSize(nsInt
         *aSize = nsIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
         return NS_OK;
     }
 #endif
 
     return NS_ERROR_NOT_AVAILABLE;
 }
 
+void
+PluginInstanceParent::DidComposite()
+{
+    if (!IsUsingDirectDrawing()) {
+        return;
+    }
+    Unused << SendNPP_DidComposite();
+}
+
 #ifdef XP_MACOSX
 nsresult
 PluginInstanceParent::IsRemoteDrawingCoreAnimation(bool *aDrawing)
 {
     *aDrawing = (NPDrawingModelCoreAnimation == (NPDrawingModel)mDrawingModel ||
                  NPDrawingModelInvalidatingCoreAnimation == (NPDrawingModel)mDrawingModel);
     return NS_OK;
 }
@@ -899,17 +1263,21 @@ PluginInstanceParent::BackgroundDescript
 
 ImageContainer*
 PluginInstanceParent::GetImageContainer()
 {
   if (mImageContainer) {
     return mImageContainer;
   }
 
-  mImageContainer = LayerManager::CreateImageContainer();
+  if (IsUsingDirectDrawing()) {
+      mImageContainer = LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
+  } else {
+      mImageContainer = LayerManager::CreateImageContainer();
+  }
   return mImageContainer;
 }
 
 PPluginBackgroundDestroyerParent*
 PluginInstanceParent::AllocPPluginBackgroundDestroyerParent()
 {
     NS_RUNTIMEABORT("'Power-user' ctor is used exclusively");
     return nullptr;
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -27,22 +27,25 @@
 #include "mozilla/unused.h"
 
 class gfxASurface;
 class gfxContext;
 class nsPluginInstanceOwner;
 
 namespace mozilla {
 namespace layers {
+class Image;
 class ImageContainer;
+class TextureClientRecycleAllocator;
 } // namespace layers
 namespace plugins {
 
 class PBrowserStreamParent;
 class PluginModuleParent;
+class D3D11SurfaceHolder;
 
 class PluginInstanceParent : public PPluginInstanceParent
                            , public PluginDataResolver
 {
     friend class PluginModuleParent;
     friend class BrowserStreamParent;
     friend class PluginStreamParent;
     friend class StreamNotifyParent;
@@ -110,16 +113,25 @@ public:
 
     virtual bool
     AnswerNPN_GetValue_DrawingModelSupport(const NPNVariable& model, bool* value) override;
   
     virtual bool
     AnswerNPN_GetValue_NPNVdocumentOrigin(nsCString* value, NPError* result) override;
 
     virtual bool
+    AnswerNPN_GetValue_SupportsAsyncBitmapSurface(bool* value) override;
+
+    virtual bool
+    AnswerNPN_GetValue_SupportsAsyncDXGISurface(bool* value) override;
+
+    virtual bool
+    AnswerNPN_GetValue_PreferredDXGIAdapter(DxgiAdapterDesc* desc) override;
+
+    virtual bool
     AnswerNPN_SetValue_NPPVpluginWindow(const bool& windowed, NPError* result) override;
     virtual bool
     AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
                                              NPError* result) override;
     virtual bool
     AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(const bool& useDOMForCursor,
                                                   NPError* result) override;
     virtual bool
@@ -156,16 +168,38 @@ public:
                                    NPError* result) override;
 
     virtual bool
     DeallocPStreamNotifyParent(PStreamNotifyParent* notifyData) override;
 
     virtual bool
     RecvNPN_InvalidateRect(const NPRect& rect) override;
 
+    virtual bool
+    RecvRevokeCurrentDirectSurface() override;
+
+    virtual bool
+    RecvInitDXGISurface(const gfx::SurfaceFormat& format,
+                         const gfx::IntSize& size,
+                         WindowsHandle* outHandle,
+                         NPError* outError) override;
+    virtual bool
+    RecvFinalizeDXGISurface(const WindowsHandle& handle) override;
+
+    virtual bool
+    RecvShowDirectBitmap(Shmem&& buffer,
+                         const gfx::SurfaceFormat& format,
+                         const uint32_t& stride,
+                         const gfx::IntSize& size,
+                         const gfx::IntRect& dirty) override;
+
+    virtual bool
+    RecvShowDirectDXGISurface(const WindowsHandle& handle,
+                               const gfx::IntRect& rect) override;
+
     // Async rendering
     virtual bool
     RecvShow(const NPRect& updatedRect,
              const SurfaceDescriptor& newSurface,
              SurfaceDescriptor* prevSurface) override;
 
     virtual PPluginSurfaceParent*
     AllocPPluginSurfaceParent(const WindowsSharedMemoryHandle& handle,
@@ -302,17 +336,19 @@ public:
     nsresult IsRemoteDrawingCoreAnimation(bool *aDrawing);
     nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
 #endif
     nsresult SetBackgroundUnknown();
     nsresult BeginUpdateBackground(const nsIntRect& aRect,
                                    gfxContext** aCtx);
     nsresult EndUpdateBackground(gfxContext* aCtx,
                                  const nsIntRect& aRect);
-    void DidComposite() { Unused << SendNPP_DidComposite(); }
+    void DidComposite();
+
+    bool IsUsingDirectDrawing();
 
     virtual PluginAsyncSurrogate* GetAsyncSurrogate() override;
 
     virtual PluginInstanceParent* GetInstance() override { return this; }
 
     static PluginInstanceParent* Cast(NPP instance,
                                       PluginAsyncSurrogate** aSurrogate = nullptr);
 
@@ -333,29 +369,41 @@ private:
     DeallocPPluginBackgroundDestroyerParent(PPluginBackgroundDestroyerParent* aActor) override;
 
     bool InternalGetValueForNPObject(NPNVariable aVariable,
                                      PPluginScriptableObjectParent** aValue,
                                      NPError* aResult);
 
     nsPluginInstanceOwner* GetOwner();
 
+    void SetCurrentImage(layers::Image* aImage);
+
 private:
     PluginModuleParent* mParent;
     RefPtr<PluginAsyncSurrogate> mSurrogate;
     bool mUseSurrogate;
     NPP mNPP;
     const NPNetscapeFuncs* mNPNIface;
     nsCString mSrcAttribute;
     bool mIsWhitelistedForShumway;
     NPWindowType mWindowType;
-    int16_t            mDrawingModel;
+    int16_t mDrawingModel;
 
     nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects;
 
+    // This is used to tell the compositor that it should invalidate the ImageLayer.
+    uint32_t mFrameID;
+
+#if defined(XP_WIN)
+    // Note: DXGI 1.1 surface handles are global across all processes, and are not
+    // marshaled. As long as we haven't freed a texture its handle should be valid
+    // as a unique cross-process identifier for the texture.
+    nsRefPtrHashtable<nsPtrHashKey<void>, D3D11SurfaceHolder> mD3D11Surfaces;
+#endif
+
 #if defined(OS_WIN)
 private:
     // Used in handling parent/child forwarding of events.
     static LRESULT CALLBACK PluginWindowHookProc(HWND hWnd, UINT message,
                                                  WPARAM wParam, LPARAM lParam);
     void SubclassPluginWindow(HWND aWnd);
     void UnsubclassPluginWindow();
 
@@ -367,19 +415,16 @@ private:
     nsIntRect          mSharedSize;
     HWND               mPluginHWND;
     // This is used for the normal child plugin HWND for windowed plugins and,
     // if needed, also the child popup surrogate HWND for windowless plugins.
     HWND               mChildPluginHWND;
     HWND               mChildPluginsParentHWND;
     WNDPROC            mPluginWndProc;
     bool               mNestedEventState;
-
-    // This will automatically release the textures when this object goes away.
-    nsRefPtrHashtable<nsPtrHashKey<void>, ID3D10Texture2D> mTextureMap;
 #endif // defined(XP_WIN)
 #if defined(MOZ_WIDGET_COCOA)
 private:
     Shmem                  mShSurface; 
     uint16_t               mShWidth;
     uint16_t               mShHeight;
     CGColorSpaceRef        mShColorSpace;
     RefPtr<MacIOSurface> mIOSurface;
--- a/dom/plugins/ipc/PluginLibrary.h
+++ b/dom/plugins/ipc/PluginLibrary.h
@@ -72,16 +72,17 @@ public:
 
   virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
                                      uint64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback) = 0;
   virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) = 0;
 
   virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window) = 0;
   virtual nsresult GetImageContainer(NPP instance, mozilla::layers::ImageContainer** aContainer) = 0;
   virtual nsresult GetImageSize(NPP instance, nsIntSize* aSize) = 0;
+  virtual void DidComposite(NPP instance) = 0;
   virtual bool IsOOP() = 0;
 #if defined(XP_MACOSX)
   virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) = 0;
   virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) = 0;
 #endif
 
   /**
    * The next three methods are the third leg in the trip to
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -215,16 +215,25 @@ inline void AssertPluginThread()
       NS_WARNING("Not running on the plugin's main thread!"); \
       return; \
     } \
   PR_END_MACRO
 
 void DeferNPObjectLastRelease(const NPNetscapeFuncs* f, NPObject* o);
 void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v);
 
+inline bool IsDrawingModelDirect(int16_t aModel)
+{
+    return aModel == NPDrawingModelAsyncBitmapSurface
+#if defined(XP_WIN)
+           || aModel == NPDrawingModelAsyncWindowsDXGISurface
+#endif
+           ;
+}
+
 // in NPAPI, char* == nullptr is sometimes meaningful.  the following is
 // helper code for dealing with nullable nsCString's
 inline nsCString
 NullableString(const char* aString)
 {
     if (!aString) {
         nsCString str;
         str.SetIsVoid(true);
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1022,16 +1022,27 @@ static NPError
 static NPBool
 _convertpoint(NPP instance, 
               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
               double *destX, double *destY, NPCoordinateSpace destSpace);
 
 static void
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
 
+static NPError
+_initasyncsurface(NPP instance, NPSize *size,
+                  NPImageFormat format, void *initData,
+                  NPAsyncSurface *surface);
+
+static NPError
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
+
+static void
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
+
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
     sizeof(sBrowserFuncs),
     (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
     mozilla::plugins::child::_geturl,
@@ -1083,17 +1094,20 @@ const NPNetscapeFuncs PluginModuleChild:
     mozilla::plugins::child::_setvalueforurl,
     mozilla::plugins::child::_getauthenticationinfo,
     mozilla::plugins::child::_scheduletimer,
     mozilla::plugins::child::_unscheduletimer,
     mozilla::plugins::child::_popupcontextmenu,
     mozilla::plugins::child::_convertpoint,
     nullptr, // handleevent, unimplemented
     nullptr, // unfocusinstance, unimplemented
-    mozilla::plugins::child::_urlredirectresponse
+    mozilla::plugins::child::_urlredirectresponse,
+    mozilla::plugins::child::_initasyncsurface,
+    mozilla::plugins::child::_finalizeasyncsurface,
+    mozilla::plugins::child::_setcurrentasyncsurface,
 };
 
 PluginInstanceChild*
 InstCast(NPP aNPP)
 {
     MOZ_ASSERT(!!(aNPP->ndata), "nil instance");
     return static_cast<PluginInstanceChild*>(aNPP->ndata);
 }
@@ -1857,16 +1871,36 @@ NPBool
 }
 
 void
 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
 {
     InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
 }
 
+NPError
+_initasyncsurface(NPP instance, NPSize *size,
+                  NPImageFormat format, void *initData,
+                  NPAsyncSurface *surface)
+{
+    return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
+}
+
+NPError
+_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
+{
+    return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
+}
+
+void
+_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
+{
+    InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
+}
+
 } /* namespace child */
 } /* namespace plugins */
 } /* namespace mozilla */
 
 //-----------------------------------------------------------------------------
 
 bool
 PluginModuleChild::RecvSettingChanged(const PluginSettings& aSettings)
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -35,16 +35,17 @@
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
 #include "nsPrintfCString.h"
 #include "prsystem.h"
 #include "PluginQuirks.h"
 #include "GeckoProfiler.h"
 #include "nsPluginTags.h"
 #include "nsUnicharUtils.h"
+#include "mozilla/layers/TextureClientRecycleAllocator.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginSurfaceParent.h"
 #include "mozilla/widget/AudioSession.h"
 #include "PluginHangUIParent.h"
 #endif
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
@@ -1940,16 +1941,24 @@ PluginModuleParent::GetImageContainer(NP
 nsresult
 PluginModuleParent::GetImageSize(NPP instance,
                                  nsIntSize* aSize)
 {
     PluginInstanceParent* i = PluginInstanceParent::Cast(instance);
     return !i ? NS_ERROR_FAILURE : i->GetImageSize(aSize);
 }
 
+void
+PluginModuleParent::DidComposite(NPP aInstance)
+{
+    if (PluginInstanceParent* i = PluginInstanceParent::Cast(aInstance)) {
+        i->DidComposite();
+    }
+}
+
 nsresult
 PluginModuleParent::SetBackgroundUnknown(NPP instance)
 {
     PluginInstanceParent* i = PluginInstanceParent::Cast(instance);
     if (!i)
         return NS_ERROR_FAILURE;
 
     return i->SetBackgroundUnknown();
@@ -3011,16 +3020,25 @@ PluginModuleParent::RecvReturnSitesWithD
 
     if (!!mSitesWithDataCallbacks[aCallbackId]) {
         mSitesWithDataCallbacks[aCallbackId]->SitesWithData(aSites);
     }
     mSitesWithDataCallbacks.erase(aCallbackId);
     return true;
 }
 
+layers::TextureClientRecycleAllocator*
+PluginModuleParent::EnsureTextureAllocator()
+{
+    if (!mTextureAllocator) {
+        mTextureAllocator = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton());
+    }
+    return mTextureAllocator;
+}
+
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 
 // We only add the crash reporter to subprocess which have the filename
 // FlashPlayerPlugin*
 #define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
 
 static DWORD
 GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -38,16 +38,20 @@ namespace mozilla {
 #ifdef MOZ_ENABLE_PROFILER_SPS
 class ProfileGatherer;
 #endif
 namespace dom {
 class PCrashReporterParent;
 class CrashReporterParent;
 } // namespace dom
 
+namespace layers {
+class TextureClientRecycleAllocator;
+} // namespace layers
+
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 class BrowserStreamParent;
 class PluginAsyncSurrogate;
 class PluginInstanceParent;
 
 #ifdef XP_WIN
@@ -241,16 +245,17 @@ protected:
                                 void *value);
     static void NPP_URLRedirectNotify(NPP instance, const char* url,
                                       int32_t status, void* notifyData);
 
     virtual bool HasRequiredFunctions() override;
     virtual nsresult AsyncSetWindow(NPP aInstance, NPWindow* aWindow) override;
     virtual nsresult GetImageContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;
     virtual nsresult GetImageSize(NPP aInstance, nsIntSize* aSize) override;
+    virtual void DidComposite(NPP aInstance) override;
     virtual bool IsOOP() override { return true; }
     virtual nsresult SetBackgroundUnknown(NPP instance) override;
     virtual nsresult BeginUpdateBackground(NPP instance,
                                            const nsIntRect& aRect,
                                            gfxContext** aCtx) override;
     virtual nsresult EndUpdateBackground(NPP instance,
                                          gfxContext* aCtx,
                                          const nsIntRect& aRect) override;
@@ -288,16 +293,18 @@ public:
 
 #if defined(XP_MACOSX)
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) override;
     virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) override;
 #endif
 
     void InitAsyncSurrogates();
 
+    layers::TextureClientRecycleAllocator* EnsureTextureAllocator();
+
 protected:
     void NotifyFlashHang();
     void NotifyPluginCrashed();
     void OnInitFailure();
     bool MaybeRunDeferredShutdown();
     bool DoShutdown(NPError* error);
 
     bool GetSetting(NPNVariable aVariable);
@@ -334,16 +341,18 @@ protected:
     friend class mozilla::plugins::PluginAsyncSurrogate;
 
     bool              mIsStartingAsync;
     bool              mNPInitialized;
     bool              mIsNPShutdownPending;
     nsTArray<RefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
     nsresult          mAsyncNewRv;
     uint32_t          mRunID;
+
+    RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocator;
 };
 
 class PluginModuleContentParent : public PluginModuleParent
 {
   public:
     explicit PluginModuleContentParent(bool aAllowAsyncInit);
 
     static PluginLibrary* LoadModule(uint32_t aPluginId, nsPluginTag* aPluginTag);
--- a/dom/plugins/ipc/PluginWidgetParent.cpp
+++ b/dom/plugins/ipc/PluginWidgetParent.cpp
@@ -113,18 +113,18 @@ PluginWidgetParent::RecvCreate(nsresult*
     return true;
   }
 
   nsWidgetInitData initData;
   initData.mWindowType = eWindowType_plugin_ipc_chrome;
   initData.mUnicode = false;
   initData.clipChildren = true;
   initData.clipSiblings = true;
-  *aResult = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0),
-                             &initData);
+  *aResult = mWidget->Create(parentWidget.get(), nullptr,
+                             LayoutDeviceIntRect(0, 0, 0, 0), &initData);
   if (NS_FAILED(*aResult)) {
     KillWidget();
     // This should never fail, abort.
     return false;
   }
 
   DebugOnly<nsresult> drv;
   drv = mWidget->EnableDragDrop(true);
--- a/dom/plugins/ipc/moz.build
+++ b/dom/plugins/ipc/moz.build
@@ -102,16 +102,21 @@ SOURCES += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'PluginInterposeOSX.mm',
         'PluginUtilsOSX.mm',
     ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    UNIFIED_SOURCES += [
+        'D3D11SurfaceHolder.cpp',
+    ]
+
 IPDL_SOURCES += [
     'PBrowserStream.ipdl',
     'PluginTypes.ipdlh',
     'PPluginBackgroundDestroyer.ipdl',
     'PPluginInstance.ipdl',
     'PPluginModule.ipdl',
     'PPluginScriptableObject.ipdl',
     'PPluginStream.ipdl',
--- a/dom/plugins/test/testplugin/README
+++ b/dom/plugins/test/testplugin/README
@@ -18,16 +18,25 @@ This rendering method is not supported f
 
 The test plugin supports the following parameters:
 
 * drawmode="solid"
 The plugin will draw a solid color instead of the default rendering described
 above. The default solid color is completely transparent black (i.e., nothing).
 This should be specified when using one of the async models.
 
+* asyncmodel="bitmap"
+The plugin will use the NPAPI Async Bitmap drawing model extension. On
+unsupported platforms this will fallback to non-async rendering.
+
+* asyncmodel="dxgi"
+The plugin will use the NPAPI Async DXGI drawing model extension. Only
+supported on Windows Vista or higher. On unsupported platforms this will
+fallback to non-async rendering.
+
 * color
 This specifies the color to use for drawmode="solid". The value should be 8 hex
 digits, 2 per channel in AARRGGBB format.
 
 == Generic API Tests ==
 
 * setUndefinedValueTest
 Attempts to set the value of an undefined variable (0x0) via NPN_SetValue,
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -598,16 +598,47 @@ static bool bug813906(NPP npp, const cha
   if (err != NPERR_NO_ERROR) {
     err = NPN_GetURL(npp, "about:blank", frame);
     return false;
   }
 
   return true;
 }
 
+void
+drawAsyncBitmapColor(InstanceData* instanceData)
+{
+  NPP npp = instanceData->npp;
+
+  uint32_t *pixelData = (uint32_t*)instanceData->backBuffer->bitmap.data;
+
+  uint32_t rgba = instanceData->scriptableObject->drawColor;
+
+  unsigned char subpixels[4];
+  memcpy(subpixels, &rgba, sizeof(subpixels));
+
+  subpixels[0] = uint8_t(float(subpixels[3] * subpixels[0]) / 0xFF);
+  subpixels[1] = uint8_t(float(subpixels[3] * subpixels[1]) / 0xFF);
+  subpixels[2] = uint8_t(float(subpixels[3] * subpixels[2]) / 0xFF);
+  uint32_t premultiplied;
+  memcpy(&premultiplied, subpixels, sizeof(premultiplied));
+
+  for (uint32_t* lastPixel = pixelData + instanceData->backBuffer->size.width * instanceData->backBuffer->size.height;
+       pixelData < lastPixel;
+       ++pixelData)
+  {
+    *pixelData = premultiplied;
+  }
+
+  NPN_SetCurrentAsyncSurface(npp, instanceData->backBuffer, NULL);
+  NPAsyncSurface *oldFront = instanceData->frontBuffer;
+  instanceData->frontBuffer = instanceData->backBuffer;
+  instanceData->backBuffer = oldFront;
+}
+
 //
 // function signatures
 //
 
 NPObject* scriptableAllocate(NPP npp, NPClass* aClass);
 void scriptableDeallocate(NPObject* npobj);
 void scriptableInvalidate(NPObject* npobj);
 bool scriptableHasMethod(NPObject* npobj, NPIdentifier name);
@@ -808,16 +839,19 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->topLevelWindowActivationEventCount = 0;
   instanceData->focusState = ACTIVATION_STATE_UNKNOWN;
   instanceData->focusEventCount = 0;
   instanceData->eventModel = 0;
   instanceData->closeStream = false;
   instanceData->wantsAllStreams = false;
   instanceData->mouseUpEventCount = 0;
   instanceData->bugMode = -1;
+  instanceData->asyncDrawing = AD_NONE;
+  instanceData->frontBuffer = nullptr;
+  instanceData->backBuffer = nullptr;
   instance->pdata = instanceData;
 
   TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
   if (!scriptableObject) {
     printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
     delete instanceData;
     return NPERR_GENERIC_ERROR;
   }
@@ -829,31 +863,40 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->instanceCountWatchGeneration = sCurrentInstanceCountWatchGeneration;
 
   if (NP_FULL == mode) {
     instanceData->streamMode = NP_SEEK;
     instanceData->frame = "testframe";
     addRange(instanceData, "100,100");
   }
 
+  AsyncDrawing requestAsyncDrawing = AD_NONE;
+
   bool requestWindow = false;
   // handle extra params
   for (int i = 0; i < argc; i++) {
     if (strcmp(argn[i], "drawmode") == 0) {
       if (strcmp(argv[i], "solid") == 0)
         scriptableObject->drawMode = DM_SOLID_COLOR;
     }
     else if (strcmp(argn[i], "color") == 0) {
       scriptableObject->drawColor = parseHexColor(argv[i], strlen(argv[i]));
     }
     else if (strcmp(argn[i], "wmode") == 0) {
       if (strcmp(argv[i], "window") == 0) {
         requestWindow = true;
       }
     }
+    else if (strcmp(argn[i], "asyncmodel") == 0) {
+      if (strcmp(argv[i], "bitmap") == 0) {
+        requestAsyncDrawing = AD_BITMAP;
+      } else if (strcmp(argv[i], "dxgi") == 0) {
+        requestAsyncDrawing = AD_DXGI;
+      }
+    }
     if (strcmp(argn[i], "streammode") == 0) {
       if (strcmp(argv[i], "normal") == 0) {
         instanceData->streamMode = NP_NORMAL;
       }
       else if ((strcmp(argv[i], "asfile") == 0) &&
                 strlen(argv[i]) == strlen("asfile")) {
         instanceData->streamMode = NP_ASFILE;
       }
@@ -958,16 +1001,43 @@ NPP_New(NPMIMEType pluginType, NPP insta
     NPN_SetValue(instance, NPPVpluginWindowBool, (void*)false);
   }
 
   if (scriptableObject->drawMode == DM_SOLID_COLOR &&
       (scriptableObject->drawColor & 0xFF000000) != 0xFF000000) {
     NPN_SetValue(instance, NPPVpluginTransparentBool, (void*)true);
   }
 
+  if (requestAsyncDrawing == AD_BITMAP) {
+    NPBool supportsAsyncBitmap = false;
+    if ((NPN_GetValue(instance, NPNVsupportsAsyncBitmapSurfaceBool, &supportsAsyncBitmap) == NPERR_NO_ERROR) &&
+        supportsAsyncBitmap) {
+      if (NPN_SetValue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelAsyncBitmapSurface) == NPERR_NO_ERROR) {
+        instanceData->asyncDrawing = AD_BITMAP;
+      }
+    }
+  }
+#ifdef XP_WIN
+  else if (requestAsyncDrawing == AD_DXGI) {
+    NPBool supportsAsyncDXGI = false;
+    if ((NPN_GetValue(instance, NPNVsupportsAsyncWindowsDXGISurfaceBool, &supportsAsyncDXGI) == NPERR_NO_ERROR) &&
+        supportsAsyncDXGI) {
+      if (NPN_SetValue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelAsyncWindowsDXGISurface) == NPERR_NO_ERROR) {
+        instanceData->asyncDrawing = AD_DXGI;
+      }
+    }
+  }
+#endif
+
+  // If we can't get the right drawing mode, we fail, otherwise our tests might
+  // appear to be passing when they shouldn't. Real plugins should not do this.
+  if (instanceData->asyncDrawing != requestAsyncDrawing) {
+    return NPERR_GENERIC_ERROR;
+  }
+
   instanceData->lastReportedPrivateModeState = false;
   instanceData->lastMouseX = instanceData->lastMouseY = -1;
   instanceData->widthAtLastPaint = -1;
   instanceData->paintCount = 0;
 
   // do platform-specific initialization
   NPError err = pluginInstanceInit(instanceData);
   if (err != NPERR_NO_ERROR) {
@@ -1049,16 +1119,26 @@ NPP_Destroy(NPP instance, NPSavedData** 
   TestRange* currentrange = instanceData->testrange;
   TestRange* nextrange;
   while (currentrange != nullptr) {
     nextrange = reinterpret_cast<TestRange*>(currentrange->next);
     delete currentrange;
     currentrange = nextrange;
   }
 
+  if (instanceData->frontBuffer) {
+    NPN_SetCurrentAsyncSurface(instance, nullptr, nullptr);
+    NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
+    NPN_MemFree(instanceData->frontBuffer);
+  }
+  if (instanceData->backBuffer) {
+    NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
+    NPN_MemFree(instanceData->backBuffer);
+  }
+
   pluginInstanceShutdown(instanceData);
   NPN_ReleaseObject(instanceData->scriptableObject);
 
   if (sCurrentInstanceCountWatchGeneration == instanceData->instanceCountWatchGeneration) {
     --sInstanceCount;
   }
   delete instanceData;
 
@@ -1081,16 +1161,64 @@ NPP_SetWindow(NPP instance, NPWindow* wi
   }
 
   void* oldWindow = instanceData->window.window;
   pluginDoSetWindow(instanceData, window);
   if (instanceData->hasWidget && oldWindow != instanceData->window.window) {
     pluginWidgetInit(instanceData, oldWindow);
   }
 
+
+  if (instanceData->asyncDrawing != AD_NONE) {
+    if (instanceData->frontBuffer &&
+        instanceData->frontBuffer->size.width >= 0 &&
+        (uint32_t)instanceData->frontBuffer->size.width == window->width &&
+        instanceData ->frontBuffer->size.height >= 0 &&
+        (uint32_t)instanceData->frontBuffer->size.height == window->height)
+    {
+      return NPERR_NO_ERROR;
+    }
+    if (instanceData->frontBuffer) {
+      NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
+      NPN_MemFree(instanceData->frontBuffer);
+    }
+    if (instanceData->backBuffer) {
+      NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
+      NPN_MemFree(instanceData->backBuffer);
+    }
+    instanceData->frontBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
+    instanceData->backBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
+
+    NPSize size;
+    size.width = window->width;
+    size.height = window->height;
+
+    memcpy(instanceData->backBuffer, instanceData->frontBuffer, sizeof(NPAsyncSurface));
+
+    NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, nullptr, instanceData->frontBuffer);
+    NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, nullptr, instanceData->backBuffer);
+
+#if defined(XP_WIN)
+    if (instanceData->asyncDrawing == AD_DXGI) {
+      if (!setupDxgiSurfaces(instance, instanceData)) {
+        return NPERR_GENERIC_ERROR;
+      }
+    }
+#endif
+  }
+
+  if (instanceData->asyncDrawing == AD_BITMAP) {
+    drawAsyncBitmapColor(instanceData);
+  }
+#if defined(XP_WIN)
+  else if (instanceData->asyncDrawing == AD_DXGI) {
+    drawDxgiBitmapColor(instanceData);
+  }
+#endif
+
   return NPERR_NO_ERROR;
 }
 
 NPError
 NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
 {
   InstanceData* instanceData = (InstanceData*)(instance->pdata);
 
@@ -1838,16 +1966,35 @@ NPN_PluginThreadAsyncCall(NPP plugin, vo
 }
 
 void
 NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow)
 {
   return sBrowserFuncs->urlredirectresponse(instance, notifyData, allow);
 }
 
+NPError
+NPN_InitAsyncSurface(NPP instance, NPSize *size, NPImageFormat format,
+                     void *initData, NPAsyncSurface *surface)
+{
+  return sBrowserFuncs->initasyncsurface(instance, size, format, initData, surface);
+}
+
+NPError
+NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface)
+{
+  return sBrowserFuncs->finalizeasyncsurface(instance, surface);
+}
+
+void
+NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
+{
+  sBrowserFuncs->setcurrentasyncsurface(instance, surface, changed);
+}
+
 //
 // npruntime object functions
 //
 
 NPObject*
 scriptableAllocate(NPP npp, NPClass* aClass)
 {
   TestNPObject* object = (TestNPObject*)NPN_MemAlloc(sizeof(TestNPObject));
@@ -2751,17 +2898,21 @@ setColor(NPObject* npobj, const NPVarian
   id->scriptableObject->drawColor =
     parseHexColor(str->UTF8Characters, str->UTF8Length);
 
   NPRect r;
   r.left = 0;
   r.top = 0;
   r.right = id->window.width;
   r.bottom = id->window.height;
-  NPN_InvalidateRect(npp, &r);
+  if (id->asyncDrawing == AD_NONE) {
+    NPN_InvalidateRect(npp, &r);
+  } else if (id->asyncDrawing == AD_BITMAP) {
+    drawAsyncBitmapColor(id);
+  }
 
   VOID_TO_NPVARIANT(*result);
   return true;
 }
 
 void notifyDidPaint(InstanceData* instanceData)
 {
   ++instanceData->paintCount;
--- a/dom/plugins/test/testplugin/nptest.h
+++ b/dom/plugins/test/testplugin/nptest.h
@@ -57,16 +57,22 @@ typedef enum {
   FUNCTION_NPP_NEWSTREAM,
   FUNCTION_NPP_WRITEREADY,
   FUNCTION_NPP_WRITE,
   FUNCTION_NPP_DESTROYSTREAM,
   FUNCTION_NPP_WRITE_RPC
 } TestFunction;
 
 typedef enum {
+  AD_NONE,
+  AD_BITMAP,
+  AD_DXGI
+} AsyncDrawing;
+
+typedef enum {
   ACTIVATION_STATE_UNKNOWN,
   ACTIVATION_STATE_ACTIVATED,
   ACTIVATION_STATE_DEACTIVATED
 } ActivationState;
 
 typedef struct FunctionTable {
   TestFunction funcId;
   const char* funcName;
@@ -142,13 +148,21 @@ typedef struct InstanceData {
   int32_t focusEventCount;
   int32_t eventModel;
   bool closeStream;
   std::string lastKeyText;
   bool wantsAllStreams;
   int32_t mouseUpEventCount;
   int32_t bugMode;
   std::string javaCodebase;
+  AsyncDrawing asyncDrawing;
+  NPAsyncSurface *frontBuffer;
+  NPAsyncSurface *backBuffer;
 } InstanceData;
 
 void notifyDidPaint(InstanceData* instanceData);
 
+#if defined(XP_WIN)
+bool setupDxgiSurfaces(NPP npp, InstanceData* instanceData);
+void drawDxgiBitmapColor(InstanceData* instanceData);
+#endif
+
 #endif // nptest_h_
--- a/dom/plugins/test/testplugin/nptest_windows.cpp
+++ b/dom/plugins/test/testplugin/nptest_windows.cpp
@@ -34,28 +34,31 @@
 
 #include "nptest_platform.h"
 
 #include <windows.h>
 #include <windowsx.h>
 #include <stdio.h>
 
 #include <d3d10_1.h>
+#include <d2d1.h>
 
 using namespace std;
 
 void SetSubclass(HWND hWnd, InstanceData* instanceData);
 void ClearSubclass(HWND hWnd);
 LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
 struct _PlatformData {
   HWND childWindow;
+  IDXGIAdapter1 *adapter;
   ID3D10Device1 *device;
   ID3D10Texture2D *frontBuffer;
   ID3D10Texture2D *backBuffer;
+  ID2D1Factory *d2d1Factory;
 };
 
 bool
 pluginSupportsWindowMode()
 {
   return true;
 }
 
@@ -74,32 +77,250 @@ pluginInstanceInit(InstanceData* instanc
     (NPN_MemAlloc(sizeof(PlatformData)));
   if (!instanceData->platformData)
     return NPERR_OUT_OF_MEMORY_ERROR;
   
   instanceData->platformData->childWindow = nullptr;
   instanceData->platformData->device = nullptr;
   instanceData->platformData->frontBuffer = nullptr;
   instanceData->platformData->backBuffer = nullptr;
+  instanceData->platformData->adapter = nullptr;
+  instanceData->platformData->d2d1Factory = nullptr;
   return NPERR_NO_ERROR;
 }
 
+static inline bool
+openSharedTex2D(ID3D10Device* device, HANDLE handle, ID3D10Texture2D** out)
+{
+  HRESULT hr = device->OpenSharedResource(handle, __uuidof(ID3D10Texture2D), (void**)out);
+  if (FAILED(hr) || !*out) {
+    return false;
+  }
+  return true;
+}
+
+// This is overloaded in d2d1.h so we can't use decltype().
+typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
+    D2D1_FACTORY_TYPE factoryType,
+    REFIID iid,
+    CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
+    void **factory
+);
+
+static IDXGIAdapter1*
+FindDXGIAdapter(NPP npp, IDXGIFactory1* factory)
+{
+  DXGI_ADAPTER_DESC preferred;
+  if (NPN_GetValue(npp, NPNVpreferredDXGIAdapter, &preferred) != NPERR_NO_ERROR) {
+    return nullptr;
+  }
+
+  UINT index = 0;
+  for (;;) {
+    IDXGIAdapter1* adapter = nullptr;
+    if (FAILED(factory->EnumAdapters1(index, &adapter)) || !adapter) {
+      return nullptr;
+    }
+
+    DXGI_ADAPTER_DESC desc;
+    if (SUCCEEDED(adapter->GetDesc(&desc)) &&
+        desc.AdapterLuid.LowPart == preferred.AdapterLuid.LowPart &&
+        desc.AdapterLuid.HighPart == preferred.AdapterLuid.HighPart &&
+        desc.VendorId == preferred.VendorId &&
+        desc.DeviceId == preferred.DeviceId)
+    {
+      return adapter;
+    }
+
+    adapter->Release();
+    index++;
+  }
+}
+
+// Note: we leak modules since we need them anyway.
+bool
+setupDxgiSurfaces(NPP npp, InstanceData* instanceData)
+{
+  HMODULE dxgi = LoadLibraryA("dxgi.dll");
+  if (!dxgi) {
+    return false;
+  }
+  decltype(CreateDXGIFactory1)* createDXGIFactory1 =
+    (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgi, "CreateDXGIFactory1");
+  if (!createDXGIFactory1) {
+    return false;
+  }
+
+  IDXGIFactory1* factory1 = nullptr;
+  HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1);
+  if (FAILED(hr) || !factory1) {
+    return false;
+  }
+
+  instanceData->platformData->adapter = FindDXGIAdapter(npp, factory1);
+  if (!instanceData->platformData->adapter) {
+    return false;
+  }
+
+  HMODULE d3d10 = LoadLibraryA("d3d10_1.dll");
+  if (!d3d10) {
+    return false;
+  }
+
+  decltype(D3D10CreateDevice1)* createDevice =
+    (decltype(D3D10CreateDevice1)*)GetProcAddress(d3d10, "D3D10CreateDevice1");
+  if (!createDevice) {
+    return false;
+  }
+
+
+  hr = createDevice(
+    instanceData->platformData->adapter,
+    D3D10_DRIVER_TYPE_HARDWARE, nullptr,
+    D3D10_CREATE_DEVICE_BGRA_SUPPORT |
+      D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
+    D3D10_FEATURE_LEVEL_10_1,
+    D3D10_1_SDK_VERSION, &instanceData->platformData->device);
+  if (FAILED(hr) || !instanceData->platformData->device) {
+    return false;
+  }
+
+  if (!openSharedTex2D(instanceData->platformData->device,
+                       instanceData->frontBuffer->sharedHandle,
+                       &instanceData->platformData->frontBuffer))
+  {
+    return false;
+  }
+  if (!openSharedTex2D(instanceData->platformData->device,
+                       instanceData->backBuffer->sharedHandle,
+                       &instanceData->platformData->backBuffer))
+  {
+    return false;
+  }
+
+  HMODULE d2d1 = LoadLibraryA("D2d1.dll");
+  if (!d2d1) {
+    return false;
+  }
+  auto d2d1CreateFactory = (D2D1CreateFactoryFunc)GetProcAddress(d2d1, "D2D1CreateFactory");
+  if (!d2d1CreateFactory) {
+    return false;
+  }
+
+  D2D1_FACTORY_OPTIONS options;
+  options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
+
+  hr = d2d1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
+                         __uuidof(ID2D1Factory),
+                         &options,
+                         (void**)&instanceData->platformData->d2d1Factory);
+  if (FAILED(hr) || !instanceData->platformData->d2d1Factory) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+drawDxgiBitmapColor(InstanceData* instanceData)
+{
+  NPP npp = instanceData->npp;
+
+  HRESULT hr;
+
+  IDXGISurface* surface = nullptr;
+  hr = instanceData->platformData->backBuffer->QueryInterface(
+    __uuidof(IDXGISurface), (void **)&surface);
+  if (FAILED(hr) || !surface) {
+    return;
+  }
+
+  D2D1_RENDER_TARGET_PROPERTIES props =
+    D2D1::RenderTargetProperties(
+      D2D1_RENDER_TARGET_TYPE_DEFAULT,
+      D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
+
+  ID2D1RenderTarget* target = nullptr;
+  hr = instanceData->platformData->d2d1Factory->CreateDxgiSurfaceRenderTarget(
+    surface,
+    &props,
+    &target);
+  if (FAILED(hr) || !target) {
+    surface->Release();
+    return;
+  }
+
+  IDXGIKeyedMutex* mutex = nullptr;
+  hr = instanceData->platformData->backBuffer->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&mutex);
+  if (mutex) {
+    mutex->AcquireSync(0, 0);
+  }
+
+  target->BeginDraw();
+
+  unsigned char subpixels[4];
+  memcpy(subpixels,
+         &instanceData->scriptableObject->drawColor,
+         sizeof(subpixels));
+
+  auto rect = D2D1::RectF(
+    0, 0,
+    instanceData->backBuffer->size.width,
+    instanceData->backBuffer->size.height);
+  auto color = D2D1::ColorF(
+    float(subpixels[3] * subpixels[2]) / 0xFF,
+    float(subpixels[3] * subpixels[1]) / 0xFF,
+    float(subpixels[3] * subpixels[0]) / 0xFF,
+    float(subpixels[3]) / 0xff);
+
+  ID2D1SolidColorBrush* brush = nullptr;
+  hr = target->CreateSolidColorBrush(color, &brush);
+  if (SUCCEEDED(hr) && brush) {
+    target->FillRectangle(rect, brush);
+    brush->Release();
+    brush = nullptr;
+  }
+  hr = target->EndDraw();
+
+  if (mutex) {
+    mutex->ReleaseSync(0);
+    mutex->Release();
+    mutex = nullptr;
+  }
+
+  target->Release();
+  surface->Release();
+  target = nullptr;
+  surface = nullptr;
+
+  NPN_SetCurrentAsyncSurface(npp, instanceData->backBuffer, NULL);
+  std::swap(instanceData->backBuffer, instanceData->frontBuffer);
+  std::swap(instanceData->platformData->backBuffer,
+            instanceData->platformData->frontBuffer);
+}
+
 void
 pluginInstanceShutdown(InstanceData* instanceData)
 {
   PlatformData *pd = instanceData->platformData;
   if (pd->frontBuffer) {
     pd->frontBuffer->Release();
   }
   if (pd->backBuffer) {
     pd->backBuffer->Release();
   }
+  if (pd->d2d1Factory) {
+    pd->d2d1Factory->Release();
+  }
   if (pd->device) {
     pd->device->Release();
   }
+  if (pd->adapter) {
+    pd->adapter->Release();
+  }
   NPN_MemFree(instanceData->platformData);
   instanceData->platformData = 0;
 }
 
 void
 pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
 {
   instanceData->window = *newWindow;
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/MessageEvent.h"
+#include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPresentationService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringStream.h"
 #include "PresentationConnection.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLIFrameElementBinding.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Function.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
+#include "nsContentUtils.h"
 #include "nsIDocShell.h"
 #include "nsIFrameLoader.h"
 #include "nsIMutableArray.h"
 #include "nsINetAddr.h"
 #include "nsISocketTransport.h"
 #include "nsISupportsPrimitives.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
--- a/dom/presentation/PresentationSessionInfo.h
+++ b/dom/presentation/PresentationSessionInfo.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_PresentationSessionInfo_h
 #define mozilla_dom_PresentationSessionInfo_h
 
 #include "base/process.h"
+#include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIPresentationControlChannel.h"
 #include "nsIPresentationDevice.h"
 #include "nsIPresentationListener.h"
 #include "nsIPresentationService.h"
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -390,17 +390,17 @@ SVGContentUtils::GetNearestViewportEleme
   }
   return nullptr;
 }
 
 static gfx::Matrix
 GetCTMInternal(nsSVGElement *aElement, bool aScreenCTM, bool aHaveRecursed)
 {
   gfxMatrix matrix = aElement->PrependLocalTransformsTo(gfxMatrix(),
-    aHaveRecursed ? nsSVGElement::eAllTransforms : nsSVGElement::eUserSpaceToParent);
+    aHaveRecursed ? eAllTransforms : eUserSpaceToParent);
   nsSVGElement *element = aElement;
   nsIContent *ancestor = aElement->GetFlattenedTreeParent();
 
   while (ancestor && ancestor->IsSVGElement() &&
                      !ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
     element = static_cast<nsSVGElement*>(ancestor);
     matrix *= element->PrependLocalTransformsTo(gfxMatrix()); // i.e. *A*ppend
     if (!aScreenCTM && SVGContentUtils::EstablishesViewport(element)) {
@@ -853,8 +853,43 @@ SVGContentUtils::GetPath(const nsAString
   return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
 }
 
 bool
 SVGContentUtils::ShapeTypeHasNoCorners(const nsIContent* aContent) {
   return aContent && aContent->IsAnyOfSVGElements(nsGkAtoms::circle,
                                                   nsGkAtoms::ellipse);
 }
+
+gfxMatrix
+SVGContentUtils::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix,
+  SVGTransformTypes aWhich,
+  const gfx::Matrix* aAnimateMotionTransform,
+  const nsSVGAnimatedTransformList* aTransforms)
+{
+  gfxMatrix result(aMatrix);
+
+  if (aWhich == eChildToUserSpace) {
+    // We don't have anything to prepend.
+    // eChildToUserSpace is not the common case, which is why we return
+    // 'result' to benefit from NRVO rather than returning aMatrix before
+    // creating 'result'.
+    return result;
+  }
+
+  MOZ_ASSERT(aWhich == eAllTransforms || aWhich == eUserSpaceToParent,
+             "Unknown TransformTypes");
+
+  // animateMotion's resulting transform is supposed to apply *on top of*
+  // any transformations from the |transform| attribute. So since we're
+  // PRE-multiplying, we need to apply the animateMotion transform *first*.
+  if (aAnimateMotionTransform) {
+    result.PreMultiply(ThebesMatrix(*aAnimateMotionTransform));
+  }
+
+  if (aTransforms) {
+    result.PreMultiply(
+      aTransforms->GetAnimValue().GetConsolidationMatrix());
+  }
+
+  return result;
+}
--- a/dom/svg/SVGContentUtils.h
+++ b/dom/svg/SVGContentUtils.h
@@ -22,30 +22,60 @@ class gfxTextContextPaint;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsStyleContext;
 class nsStyleCoord;
 class nsSVGElement;
 
 namespace mozilla {
+class nsSVGAnimatedTransformList;
 class SVGAnimatedPreserveAspectRatio;
 class SVGPreserveAspectRatio;
 namespace dom {
 class Element;
 class SVGSVGElement;
 } // namespace dom
 
 namespace gfx {
 class Matrix;
 } // namespace gfx
 } // namespace mozilla
 
 #define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
 
+/**
+ * SVGTransformTypes controls the transforms that PrependLocalTransformsTo
+ * applies.
+ *
+ * If aWhich is eAllTransforms, then all the transforms from the coordinate
+ * space established by this element for its children to the coordinate
+ * space established by this element's parent element for this element, are
+ * included.
+ *
+ * If aWhich is eUserSpaceToParent, then only the transforms from this
+ * element's userspace to the coordinate space established by its parent is
+ * included. This includes any transforms introduced by the 'transform'
+ * attribute, transform animations and animateMotion, but not any offsets
+ * due to e.g. 'x'/'y' attributes, or any transform due to a 'viewBox'
+ * attribute. (SVG userspace is defined to be the coordinate space in which
+ * coordinates on an element apply.)
+ *
+ * If aWhich is eChildToUserSpace, then only the transforms from the
+ * coordinate space established by this element for its childre to this
+ * elements userspace are included. This includes any offsets due to e.g.
+ * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but
+ * does not include any transforms due to the 'transform' attribute.
+ */
+enum SVGTransformTypes {
+   eAllTransforms,
+   eUserSpaceToParent,
+   eChildToUserSpace
+};
+
 inline bool
 IsSVGWhitespace(char aChar)
 {
   return aChar == '\x20' || aChar == '\x9' ||
          aChar == '\xD'  || aChar == '\xA';
 }
 
 inline bool
@@ -344,11 +374,22 @@ public:
   static already_AddRefed<mozilla::gfx::Path>
   GetPath(const nsAString& aPathString);
 
   /**
    *  Returns true if aContent is one of the elements whose stroke is guaranteed
    *  to have no corners: circle or ellipse
    */
   static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
+
+  /**
+   *  Prepends an element's local transforms to the transform matrix.
+   *  This is a helper for nsSVGElement::PrependLocalTransformsTo.
+   *  Any callers probably really want to call that method instead of this one.
+   */
+  static gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix,
+    SVGTransformTypes aWhich,
+    const Matrix* aAnimateMotionTransform,
+    const mozilla::nsSVGAnimatedTransformList* aTransforms);
 };
 
 #endif
--- a/dom/svg/SVGForeignObjectElement.cpp
+++ b/dom/svg/SVGForeignObjectElement.cpp
@@ -68,18 +68,18 @@ SVGForeignObjectElement::Height()
 {
   return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-SVGForeignObjectElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                                                  TransformTypes aWhich) const
+SVGForeignObjectElement::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
 {
   // 'transform' attribute:
   gfxMatrix fromUserSpace =
     SVGGraphicsElement::PrependLocalTransformsTo(aMatrix, aWhich);
   if (aWhich == eUserSpaceToParent) {
     return fromUserSpace;
   }
   // our 'x' and 'y' attributes:
--- a/dom/svg/SVGForeignObjectElement.h
+++ b/dom/svg/SVGForeignObjectElement.h
@@ -25,18 +25,19 @@ class SVGForeignObjectElement final : pu
 protected:
   friend nsresult (::NS_NewSVGForeignObjectElement(nsIContent **aResult,
                                                    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGForeignObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                      TransformTypes aWhich = eAllTransforms) const override;
+  virtual gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix,
+    SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
 
--- a/dom/svg/SVGFragmentIdentifier.cpp
+++ b/dom/svg/SVGFragmentIdentifier.cpp
@@ -7,17 +7,19 @@
 #include "SVGFragmentIdentifier.h"
 
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGViewElement.h"
 #include "nsContentUtils.h" // for nsCharSeparatedTokenizerTemplate
 #include "nsSVGAnimatedTransformList.h"
 #include "nsCharSeparatedTokenizer.h"
 
-using namespace mozilla;
+namespace mozilla {
+
+using namespace dom;
 
 static bool
 IsMatchingParameter(const nsAString& aString, const nsAString& aParameterName)
 {
   // The first two tests ensure aString.Length() > aParameterName.Length()
   // so it's then safe to do the third test
   return StringBeginsWith(aString, aParameterName) &&
          aString.Last() == ')' &&
@@ -25,112 +27,112 @@ IsMatchingParameter(const nsAString& aSt
 }
 
 inline bool
 IgnoreWhitespace(char16_t aChar)
 {
   return false;
 }
 
-static dom::SVGViewElement*
+static SVGViewElement*
 GetViewElement(nsIDocument* aDocument, const nsAString& aId)
 {
-  dom::Element* element = aDocument->GetElementById(aId);
+  Element* element = aDocument->GetElementById(aId);
   return (element && element->IsSVGElement(nsGkAtoms::view)) ?
-            static_cast<dom::SVGViewElement*>(element) : nullptr;
+            static_cast<SVGViewElement*>(element) : nullptr;
 }
 
 void
-SVGFragmentIdentifier::SaveOldPreserveAspectRatio(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::SaveOldPreserveAspectRatio(SVGSVGElement* root)
 {
   if (root->mPreserveAspectRatio.IsExplicitlySet()) {
     root->SetPreserveAspectRatioProperty(root->mPreserveAspectRatio.GetBaseValue());
   }
 }
 
 void 
-SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(SVGSVGElement* root)
 {
   const SVGPreserveAspectRatio* oldPARPtr = root->GetPreserveAspectRatioProperty();
   if (oldPARPtr) {
     root->mPreserveAspectRatio.SetBaseValue(*oldPARPtr, root);
   } else if (root->mPreserveAspectRatio.IsExplicitlySet()) {
-    mozilla::ErrorResult error;
+    ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("preserveAspectRatio"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::SaveOldViewBox(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::SaveOldViewBox(SVGSVGElement* root)
 {
   if (root->mViewBox.IsExplicitlySet()) {
     root->SetViewBoxProperty(root->mViewBox.GetBaseValue());
   }
 }
 
 void 
-SVGFragmentIdentifier::RestoreOldViewBox(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::RestoreOldViewBox(SVGSVGElement* root)
 {
   const nsSVGViewBoxRect* oldViewBoxPtr = root->GetViewBoxProperty();
   if (oldViewBoxPtr) {
     root->mViewBox.SetBaseValue(*oldViewBoxPtr, root);
   } else if (root->mViewBox.IsExplicitlySet()) {
-    mozilla::ErrorResult error;
+    ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("viewBox"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::SaveOldZoomAndPan(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::SaveOldZoomAndPan(SVGSVGElement* root)
 {
-  if (root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
-    root->SetZoomAndPanProperty(root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].GetBaseValue());
+  if (root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
+    root->SetZoomAndPanProperty(root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].GetBaseValue());
   }
 }
 
 void
-SVGFragmentIdentifier::RestoreOldZoomAndPan(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::RestoreOldZoomAndPan(SVGSVGElement* root)
 {
   uint16_t oldZoomAndPan = root->GetZoomAndPanProperty();
   if (oldZoomAndPan != SVG_ZOOMANDPAN_UNKNOWN) {
-    root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].SetBaseValue(oldZoomAndPan, root);
-  } else if (root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
-    mozilla::ErrorResult error;
+    root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].SetBaseValue(oldZoomAndPan, root);
+  } else if (root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
+    ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("zoomAndPan"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::SaveOldTransform(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::SaveOldTransform(SVGSVGElement* root)
 {
   nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
 
   if (transformList && transformList->IsExplicitlySet()) {
     root->SetTransformProperty(transformList->GetBaseValue());
   }
 }
 
 void 
-SVGFragmentIdentifier::RestoreOldTransform(dom::SVGSVGElement* root)
+SVGFragmentIdentifier::RestoreOldTransform(SVGSVGElement* root)
 {
   const SVGTransformList* oldTransformPtr = root->GetTransformProperty();
   if (oldTransformPtr) {
     root->GetAnimatedTransformList(nsSVGElement::DO_ALLOCATE)->SetBaseValue(*oldTransformPtr);
   } else {
     nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
     if (transformList && transformList->IsExplicitlySet()) {
-      mozilla::ErrorResult error;
+      ErrorResult error;
       root->RemoveAttribute(NS_LITERAL_STRING("transform"), error);
     }
   }
 }
 
 bool
 SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
-                                          dom::SVGSVGElement* root)
+                                          SVGSVGElement* root)
 {
   if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
     return false;
   }
 
   // SVGViewAttributes may occur in any order, but each type may only occur
   // at most one time in a correctly formed SVGViewSpec.
   // If we encounter any attribute more than once or get any syntax errors
@@ -187,21 +189,21 @@ SVGFragmentIdentifier::ProcessSVGViewSpe
     } else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
       if (zoomAndPanFound) {
         return false;
       }
       nsIAtom* valAtom = NS_GetStaticAtom(params);
       if (!valAtom) {
         return false;
       }
-      const nsSVGEnumMapping* mapping = dom::SVGSVGElement::sZoomAndPanMap;
+      const nsSVGEnumMapping* mapping = SVGSVGElement::sZoomAndPanMap;
       while (mapping->mKey) {
         if (valAtom == *(mapping->mKey)) {
           // If we've got a valid zoomAndPan value, then set it on our root element.
-          if (NS_FAILED(root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].SetBaseValue(
+          if (NS_FAILED(root->mEnumAttributes[SVGSVGElement::ZOOMANDPAN].SetBaseValue(
                           mapping->mVal, root))) {
             return false;
           }
           break;
         }
         mapping++;
       }
       if (!mapping->mKey) {
@@ -237,26 +239,26 @@ SVGFragmentIdentifier::ProcessSVGViewSpe
 
 bool
 SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument* aDocument,
                                                  const nsAString& aAnchorName)
 {
   MOZ_ASSERT(aDocument->GetRootElement()->IsSVGElement(nsGkAtoms::svg),
              "expecting an SVG root element");
 
-  dom::SVGSVGElement* rootElement =
-    static_cast<dom::SVGSVGElement*>(aDocument->GetRootElement());
+  SVGSVGElement* rootElement =
+    static_cast<SVGSVGElement*>(aDocument->GetRootElement());
 
   if (!rootElement->mUseCurrentView) {
     SaveOldViewBox(rootElement);
     SaveOldPreserveAspectRatio(rootElement);
     SaveOldZoomAndPan(rootElement);
   }
 
-  const dom::SVGViewElement* viewElement = GetViewElement(aDocument, aAnchorName);
+  const SVGViewElement* viewElement = GetViewElement(aDocument, aAnchorName);
 
   if (viewElement) {
     if (!rootElement->mCurrentViewID) {
       rootElement->mCurrentViewID = new nsString();
     }
     *rootElement->mCurrentViewID = aAnchorName;
     rootElement->mUseCurrentView = true;
     rootElement->InvalidateTransformNotifyFrame();
@@ -280,8 +282,10 @@ SVGFragmentIdentifier::ProcessFragmentId
   rootElement->ClearZoomAndPanProperty();
   RestoreOldTransform(rootElement);
   rootElement->ClearTransformProperty();
   if (wasOverridden) {
     rootElement->InvalidateTransformNotifyFrame();
   }
   return false;
 }
+
+} // namespace mozilla
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -938,18 +938,18 @@ SVGSVGElement::GetLength(uint8_t aCtxTyp
   }
   return 0;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-SVGSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                                        TransformTypes aWhich) const
+SVGSVGElement::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
 {
   // 'transform' attribute:
   gfxMatrix fromUserSpace =
     SVGSVGElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
   if (aWhich == eUserSpaceToParent) {
     return fromUserSpace;
   }
 
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -133,18 +133,19 @@ public:
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
 
   virtual bool IsEventAttributeName(nsIAtom* aName) override;
 
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                      TransformTypes aWhich = eAllTransforms) const override;
+  virtual gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix,
+    SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // SVGSVGElement methods:
   float GetLength(uint8_t mCtxType);
 
   // public helpers:
 
   /**
--- a/dom/svg/SVGTransformableElement.cpp
+++ b/dom/svg/SVGTransformableElement.cpp
@@ -85,44 +85,22 @@ SVGTransformableElement::IsEventAttribut
 {
   return nsContentUtils::IsEventAttributeName(aName, EventNameType_SVGGraphic);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement overrides
 
 gfxMatrix
-SVGTransformableElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                                                  TransformTypes aWhich) const
+SVGTransformableElement::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix,
+  SVGTransformTypes aWhich) const
 {
-  gfxMatrix result(aMatrix);
-
-  if (aWhich == eChildToUserSpace) {
-    // We don't have anything to prepend.
-    // eChildToUserSpace is not the common case, which is why we return
-    // 'result' to benefit from NRVO rather than returning aMatrix before
-    // creating 'result'.
-    return result;
-  }
-
-  MOZ_ASSERT(aWhich == eAllTransforms || aWhich == eUserSpaceToParent,
-             "Unknown TransformTypes");
-
-  // animateMotion's resulting transform is supposed to apply *on top of*
-  // any transformations from the |transform| attribute. So since we're
-  // PRE-multiplying, we need to apply the animateMotion transform *first*.
-  if (mAnimateMotionTransform) {
-    result.PreMultiply(ThebesMatrix(*mAnimateMotionTransform));
-  }
-
-  if (mTransforms) {
-    result.PreMultiply(mTransforms->GetAnimValue().GetConsolidationMatrix());
-  }
-
-  return result;
+  return SVGContentUtils::PrependLocalTransformsTo(
+    aMatrix, aWhich, mAnimateMotionTransform, mTransforms);
 }
 
 const gfx::Matrix*
 SVGTransformableElement::GetAnimateMotionTransform() const
 {
   return mAnimateMotionTransform.get();
 }
 
--- a/dom/svg/SVGTransformableElement.h
+++ b/dom/svg/SVGTransformableElement.h
@@ -48,18 +48,19 @@ public:
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                       int32_t aModType) const override;
 
 
   // nsSVGElement overrides
   virtual bool IsEventAttributeName(nsIAtom* aName) override;
 
 
-  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                      TransformTypes aWhich = eAllTransforms) const override;
+  virtual gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix,
+    SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual const gfx::Matrix* GetAnimateMotionTransform() const override;
   virtual void SetAnimateMotionTransform(const gfx::Matrix* aMatrix) override;
 
   virtual nsSVGAnimatedTransformList*
     GetAnimatedTransformList(uint32_t aFlags = 0) override;
   virtual nsIAtom* GetTransformListAttrName() const override {
     return nsGkAtoms::transform;
   }
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -426,18 +426,18 @@ SVGUseElement::UnlinkSource()
   }
   mSource.Unlink();
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-SVGUseElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                                        TransformTypes aWhich) const
+SVGUseElement::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
 {
   // 'transform' attribute:
   gfxMatrix fromUserSpace =
     SVGUseElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
   if (aWhich == eUserSpaceToParent) {
     return fromUserSpace;
   }
   // our 'x' and 'y' attributes:
--- a/dom/svg/SVGUseElement.h
+++ b/dom/svg/SVGUseElement.h
@@ -55,18 +55,19 @@ public:
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
   // for nsSVGUseFrame's nsIAnonymousContentCreator implementation.
   nsIContent* CreateAnonymousContent();
   nsIContent* GetAnonymousContent() const { return mClone; }
   void DestroyAnonymousContent();
 
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                      TransformTypes aWhich = eAllTransforms) const override;
+  virtual gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix,
+    SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> Href();
--- a/dom/svg/moz.build
+++ b/dom/svg/moz.build
@@ -6,16 +6,17 @@
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsSVGClass.h',
     'nsSVGElement.h',
     'nsSVGFeatures.h',
     'SVGAttrValueWrapper.h',
+    'SVGContentUtils.h',
     'SVGPreserveAspectRatio.h',
     'SVGStringList.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'nsSVGAnimatedTransformList.h',
     'SVGAElement.h',
     'SVGAltGlyphElement.h',
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1549,18 +1549,18 @@ nsSVGElement::GetCtx() const
     ancestor = ancestor->GetFlattenedTreeParent();
   }
 
   // we don't have an ancestor <svg> element...
   return nullptr;
 }
 
 /* virtual */ gfxMatrix
-nsSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                                       TransformTypes aWhich) const
+nsSVGElement::PrependLocalTransformsTo(
+  const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
 {
   return aMatrix;
 }
 
 nsSVGElement::LengthAttributesInfo
 nsSVGElement::GetLengthInfo()
 {
   return LengthAttributesInfo(nullptr, nullptr, 0);
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -20,16 +20,17 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsError.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsISupportsImpl.h"
 #include "nsStyledElement.h"
 #include "nsSVGClass.h"
 #include "nsIDOMSVGElement.h"
+#include "SVGContentUtils.h"
 
 class nsSVGAngle;
 class nsSVGBoolean;
 class nsSVGEnum;
 class nsSVGInteger;
 class nsSVGIntegerPair;
 class nsSVGLength2;
 class nsSVGNumber2;
@@ -134,21 +135,16 @@ public:
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
   NS_DECL_NSIDOMSVGELEMENT
 
   // Gets the element that establishes the rectangular viewport against which
   // we should resolve percentage lengths (our "coordinate context"). Returns
   // nullptr for outer <svg> or SVG without an <svg> parent (invalid SVG).
   mozilla::dom::SVGSVGElement* GetCtx() const;
 
-  enum TransformTypes {
-     eAllTransforms
-    ,eUserSpaceToParent
-    ,eChildToUserSpace
-  };
   /**
    * Returns aMatrix pre-multiplied by (explicit or implicit) transforms that
    * are introduced by attributes on this element.
    *
    * If aWhich is eAllTransforms, then all the transforms from the coordinate
    * space established by this element for its children to the coordinate
    * space established by this element's parent element for this element, are
    * included.
@@ -162,18 +158,18 @@ public:
    * coordinates on an element apply.)
    *
    * If aWhich is eChildToUserSpace, then only the transforms from the
    * coordinate space established by this element for its childre to this
    * elements userspace are included. This includes any offsets due to e.g.
    * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but
    * does not include any transforms due to the 'transform' attribute.
    */
-  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
-                      TransformTypes aWhich = eAllTransforms) const;
+  virtual gfxMatrix PrependLocalTransformsTo(
+    const gfxMatrix &aMatrix, SVGTransformTypes aWhich = eAllTransforms) const;
 
   // Setter for to set the current <animateMotion> transformation
   // Only visible for nsSVGGraphicElement, so it's a no-op here, and that
   // subclass has the useful implementation.
   virtual void SetAnimateMotionTransform(const mozilla::gfx::Matrix* aMatrix) {/*no-op*/}
   virtual const mozilla::gfx::Matrix* GetAnimateMotionTransform() const { return nullptr; }
 
   bool IsStringAnimatable(uint8_t aAttrEnum) {
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -37,16 +37,17 @@
 
 #include "BluetoothCommon.h"
 #include "BluetoothHfpManagerBase.h"
 
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::gonk;
 using namespace android;
 using namespace mozilla;
--- a/dom/tests/mochitest/chrome/window_focus_docnav.xul
+++ b/dom/tests/mochitest/chrome/window_focus_docnav.xul
@@ -2,20 +2,21 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
 <window onload="start()"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <script type="application/javascript"
         src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 
-<textbox id="textbox"/>
+<textbox id="textbox1"/>
+<textbox id="textbox2"/>
 
 <panel id="panel" onpopupshown="runTests(this, 1);"
-                  onpopuphidden="done()">
+                  onpopuphidden="noChildrenTest()">
   <textbox id="p1textbox" value="Popup1"/>
 </panel>
 <panel id="panel2" onpopupshown="runTests(this, 2);" onpopuphidden="document.getElementById('panel').hidePopup()">
   <textbox id="p2textbox" value="Popup2"/>
 </panel>
 
 <browser id="browser" type="content" src="focus_frameset.html" width="500" height="400"/>
 
@@ -23,16 +24,37 @@
 <![CDATA[
 
 var fm = Components.classes["@mozilla.org/focus-manager;1"].
            getService(Components.interfaces.nsIFocusManager);
 
 function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
 function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
 
+function noChildrenTest()
+{
+  // Remove the browser element and test navigation when there are no other documents.
+  // The focus should move or stay on the first focusable element.
+  let browser = document.getElementById("browser");
+  browser.parentNode.removeChild(browser);
+
+  let textbox1 = document.getElementById("textbox1");
+  let textbox2 = document.getElementById("textbox2");
+
+  textbox2.focus();
+  next(window, textbox1.inputField, "Focus forward when no child documents");
+  next(window, textbox1.inputField, "Focus forward again when no child documents");
+
+  textbox2.focus();
+  previous(window, textbox1.inputField, "Focus backward when no child documents");
+  previous(window, textbox1.inputField, "Focus backward again when no child documents");
+
+  done();
+}
+
 function done()
 {
   var opener = window.opener;
   window.close();
   opener.wrappedJSObject.SimpleTest.finish();
 }
 
 function previous(expectedWindow, expectedElement, desc)
@@ -76,17 +98,17 @@ function runTests(panel, popupCount)
   if (popupCount) {
     if (popupCount == 2) {
       previous(window, document.getElementById("p2textbox").inputField, "First back from popup 2 with " + popupCount);
     }
 
     previous(window, document.getElementById("p1textbox").inputField, "First back from popup 1 with " + popupCount);
   }
 
-  previous(window, document.getElementById("textbox").inputField, "First back with " + popupCount);
+  previous(window, document.getElementById("textbox1").inputField, "First back with " + popupCount);
 
   if (panel == document.getElementById("panel"))
     document.getElementById("panel2").openPopup(null, "after_start", 100, 20);
   else if (panel == document.getElementById("panel2"))
     panel.hidePopup();
   else
     document.getElementById("panel").openPopup(null, "after_start");
 }
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -74,25 +74,16 @@ var ecmaGlobals =
     "Object",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     {name: "SharedArrayBuffer", nightly: true},
-    {name: "SharedInt8Array", nightly: true},
-    {name: "SharedUint8Array", nightly: true},
-    {name: "SharedUint8ClampedArray", nightly: true},
-    {name: "SharedInt16Array", nightly: true},
-    {name: "SharedUint16Array", nightly: true},
-    {name: "SharedInt32Array", nightly: true},
-    {name: "SharedUint32Array", nightly: true},
-    {name: "SharedFloat32Array", nightly: true},
-    {name: "SharedFloat64Array", nightly: true},
     {name: "SIMD", nightly: true},
     {name: "Atomics", nightly: true},
     "StopIteration",
     "String",
     "Symbol",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
--- a/dom/webidl/Clients.webidl
+++ b/dom/webidl/Clients.webidl
@@ -7,16 +7,18 @@
  * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
  *
  */
 
 [Exposed=ServiceWorker]
 interface Clients {
   // The objects returned will be new instances every time
   [NewObject]
+  Promise<any> get(DOMString id);
+  [NewObject]
   Promise<sequence<Client>?> matchAll(optional ClientQueryOptions options);
   [NewObject,
    Func="mozilla::dom::workers::ServiceWorkerGlobalScope::OpenWindowEnabled"]
   Promise<WindowClient> openWindow(USVString url);
   [NewObject]
   Promise<void> claim();
 };
 
--- a/dom/webidl/DOMException.webidl
+++ b/dom/webidl/DOMException.webidl
@@ -45,30 +45,29 @@ interface ExceptionMembers
   // Valid line numbers begin at '1'. '0' indicates unknown.
   readonly attribute unsigned long           lineNumber;
   // Valid column numbers begin at 0. 
   // We don't have an unambiguous indicator for unknown.
   readonly attribute unsigned long           columnNumber;
 
   // A stack trace, if available.  nsIStackFrame does not have classinfo so
   // this was only ever usefully available to chrome JS.
-  [ChromeOnly]
+  [ChromeOnly, Exposed=Window]
   readonly attribute StackFrame?             location;
-  // An inner exception that triggered this, if available.
-  readonly attribute nsISupports?            inner;
 
   // Arbitary data for the implementation.
+  [Exposed=Window]
   readonly attribute nsISupports?            data;
 
   // Formatted exception stack
   [Throws, Replaceable]
   readonly attribute DOMString               stack;
 };
 
-[NoInterfaceObject]
+[NoInterfaceObject, Exposed=(Window,Worker)]
 interface Exception {
   // A generic formatter - make it suitable to print, etc.
   stringifier;
 };
 
 Exception implements ExceptionMembers;
 
 // XXXkhuey this is an 'exception', not an interface, but we don't have any
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -31,16 +31,18 @@ interface Element : Node {
   [Pure]
            attribute DOMString className;
   [Constant]
   readonly attribute DOMTokenList classList;
 
   [SameObject]
   readonly attribute NamedNodeMap attributes;
   [Pure]
+  sequence<DOMString> getAttributeNames();
+  [Pure]
   DOMString? getAttribute(DOMString name);
   [Pure]
   DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
   [Throws]
   void setAttribute(DOMString name, DOMString value);
   [Throws]
   void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
   [Throws]
--- a/dom/webidl/FetchEvent.webidl
+++ b/dom/webidl/FetchEvent.webidl
@@ -7,18 +7,20 @@
  * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
  */
 
 [Constructor(DOMString type, optional FetchEventInit eventInitDict),
  Func="mozilla::dom::workers::ServiceWorkerVisible",
  Exposed=(ServiceWorker)]
 interface FetchEvent : ExtendableEvent {
   [SameObject] readonly attribute Request? request;
+  readonly attribute DOMString? clientId;
   readonly attribute boolean isReload;
 
   [Throws]
   void respondWith(Promise<Response> r);
 };
 
 dictionary FetchEventInit : EventInit {
   Request request;
+  DOMString? clientId = null;
   boolean isReload = false;
 };
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -342,22 +342,22 @@ interface WebGL2RenderingContext : WebGL
 
     /* Texture objects */
     void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
     void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
                       GLsizei depth);
 
     void texImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum format,
-                    GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
+                    GLenum type, ArrayBufferView? pixels);
     [Throws] // Can't actually throw.
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum format, GLenum type,
-                       (ArrayBufferView or SharedArrayBufferView)? pixels);
+                       ArrayBufferView? pixels);
     [Throws] // Can't actually throw.
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLenum format, GLenum type, ImageData? data);
     [Throws]
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLint zoffset, GLenum format, GLenum type, HTMLImageElement image);
     [Throws]
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
@@ -368,21 +368,21 @@ interface WebGL2RenderingContext : WebGL
                        GLint zoffset, GLenum format, GLenum type, HTMLVideoElement video);
 
     void copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                            GLint zoffset, GLint x, GLint y, GLsizei width,
                            GLsizei height);
 
     void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
                               GLsizei width, GLsizei height, GLsizei depth, GLint border,
-                              (ArrayBufferView or SharedArrayBufferView) data);
+                              ArrayBufferView data);
     void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                                  GLint zoffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum format,
-                                 (ArrayBufferView or SharedArrayBufferView) data);
+                                 ArrayBufferView data);
 
     /* Programs and shaders */
     [WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram? program, DOMString name);
 
     /* Uniforms and attributes */
     void uniform1ui(WebGLUniformLocation? location, GLuint v0);
     void uniform2ui(WebGLUniformLocation? location, GLuint v0, GLuint v1);
     void uniform3ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2);
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -547,39 +547,37 @@ interface WebGLRenderingContext {
     void blendEquation(GLenum mode);
     void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
     void blendFunc(GLenum sfactor, GLenum dfactor);
     void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
                            GLenum srcAlpha, GLenum dstAlpha);
 
     void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
     void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
-    void bufferData(GLenum target, SharedArrayBufferView data, GLenum usage);
     void bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
     void bufferData(GLenum target, SharedArrayBuffer data, GLenum usage);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBufferView data);
-    void bufferSubData(GLenum target, GLintptr offset, SharedArrayBufferView data);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBuffer? data);
     void bufferSubData(GLenum target, GLintptr offset, SharedArrayBuffer data);
 
     [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
     void clear(GLbitfield mask);
     void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     void clearDepth(GLclampf depth);
     void clearStencil(GLint s);
     void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
     void compileShader(WebGLShader? shader);
 
     void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
                               GLsizei width, GLsizei height, GLint border,
-                              (ArrayBufferView or SharedArrayBufferView) data);
+                              ArrayBufferView data);
     void compressedTexSubImage2D(GLenum target, GLint level,
                                  GLint xoffset, GLint yoffset,
                                  GLsizei width, GLsizei height, GLenum format,
-                                 (ArrayBufferView or SharedArrayBufferView) data);
+                                 ArrayBufferView data);
 
     void copyTexImage2D(GLenum target, GLint level, GLenum internalformat,
                         GLint x, GLint y, GLsizei width, GLsizei height,
                         GLint border);
     void copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                            GLint x, GLint y, GLsizei width, GLsizei height);
 
     WebGLBuffer? createBuffer();
@@ -672,17 +670,17 @@ interface WebGLRenderingContext {
     [WebGLHandlesContextLoss] GLboolean isTexture(WebGLTexture? texture);
     void lineWidth(GLfloat width);
     void linkProgram(WebGLProgram? program);
     void pixelStorei(GLenum pname, GLint param);
     void polygonOffset(GLfloat factor, GLfloat units);
 
     [Throws]
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
+                    GLenum format, GLenum type, ArrayBufferView? pixels);
 
     void renderbufferStorage(GLenum target, GLenum internalformat,
                              GLsizei width, GLsizei height);
     void sampleCoverage(GLclampf value, GLboolean invert);
     void scissor(GLint x, GLint y, GLsizei width, GLsizei height);
 
     void shaderSource(WebGLShader? shader, DOMString source);
 
@@ -693,17 +691,17 @@ interface WebGLRenderingContext {
     void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
     void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
 
 
     // Overloads must share [Throws].
     [Throws] // Can't actually throw.
     void texImage2D(GLenum target, GLint level, GLenum internalformat,
                     GLsizei width, GLsizei height, GLint border, GLenum format,
-                    GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
+                    GLenum type, ArrayBufferView? pixels);
     [Throws] // Can't actually throw.
     void texImage2D(GLenum target, GLint level, GLenum internalformat,
                     GLenum format, GLenum type, ImageData? pixels);
     [Throws]
     void texImage2D(GLenum target, GLint level, GLenum internalformat,
                     GLenum format, GLenum type, HTMLImageElement image); // May throw DOMException
     [Throws]
     void texImage2D(GLenum target, GLint level, GLenum internalformat,
@@ -713,17 +711,17 @@ interface WebGLRenderingContext {
                     GLenum format, GLenum type, HTMLVideoElement video); // May throw DOMException
 
     void texParameterf(GLenum target, GLenum pname, GLfloat param);
     void texParameteri(GLenum target, GLenum pname, GLint param);
 
     [Throws] // Can't actually throw.
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLsizei width, GLsizei height, GLenum format, GLenum type,
-                       (ArrayBufferView or SharedArrayBufferView)? pixels);
+                       ArrayBufferView? pixels);
     [Throws] // Can't actually throw.
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLenum format, GLenum type, ImageData? pixels);
     [Throws]
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                        GLenum format, GLenum type, HTMLImageElement image); // May throw DOMException
     [Throws]
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -310,16 +310,17 @@ private:
           override;
 
   NS_DECL_NSICANCELABLERUNNABLE
 
   void
   ShutdownScriptLoader(JSContext* aCx,
                        WorkerPrivate* aWorkerPrivate,
                        bool aResult,
+                       nsresult aLoadResult,
                        bool aMutedError);
 
   void LogExceptionToConsole(JSContext* aCx,
                              WorkerPrivate* WorkerPrivate);
 };
 
 class CacheScriptLoader;
 
@@ -1787,57 +1788,69 @@ void
 ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                                 bool aRunResult)
 {
   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
 
   if (mLastIndex == loadInfos.Length() - 1) {
     // All done. If anything failed then return false.
     bool result = true;
+    nsresult loadResult = NS_OK;
     bool mutedError = false;
     for (uint32_t index = 0; index < loadInfos.Length(); index++) {
       if (!loadInfos[index].mExecutionResult) {
-        mutedError = loadInfos[index].mMutedErrorFlag.valueOr(true);
+        mutedError = mutedError || loadInfos[index].mMutedErrorFlag.valueOr(true);
+        loadResult = loadInfos[index].mLoadResult;
         result = false;
-        break;
+
+        // If we have more than one loadInfos and one of them fails, the others
+        // are marked as NS_BINDING_ABORTED, but what we want to report is the
+        // error result of the 'real' failing one.
+        if (loadInfos[index].mLoadResult != NS_BINDING_ABORTED) {
+          loadResult = loadInfos[index].mLoadResult;
+          break;
+        }
       }
     }
 
-    ShutdownScriptLoader(aCx, aWorkerPrivate, result, mutedError);
+    ShutdownScriptLoader(aCx, aWorkerPrivate, result, loadResult, mutedError);
   }
 }
 
 NS_IMETHODIMP
 ScriptExecutorRunnable::Cancel()
 {
   if (mLastIndex == mScriptLoader.mLoadInfos.Length() - 1) {
     ShutdownScriptLoader(mWorkerPrivate->GetJSContext(), mWorkerPrivate,
-                         false, false);
+                         false, NS_OK, false);
   }
   return MainThreadWorkerSyncRunnable::Cancel();
 }
 
 void
 ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
                                              WorkerPrivate* aWorkerPrivate,
                                              bool aResult,
+                                             nsresult aLoadResult,
                                              bool aMutedError)
 {
   MOZ_ASSERT(mLastIndex == mScriptLoader.mLoadInfos.Length() - 1);
 
   if (mIsWorkerScript && aWorkerPrivate->IsServiceWorker()) {
     aWorkerPrivate->SetLoadingWorkerScript(false);
   }
 
   if (!aResult) {
     // If this error has to be muted, we have to clear the pending exception,
     // if any, and use the ErrorResult object to throw a new exception.
     if (aMutedError && JS_IsExceptionPending(aCx)) {
       LogExceptionToConsole(aCx, aWorkerPrivate);
       mScriptLoader.mRv.Throw(NS_ERROR_FAILURE);
+    } else if (NS_FAILED(aLoadResult)) {
+      mScriptLoader.mRv.Throw(aLoadResult);
     } else {
       mScriptLoader.mRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     }
   }
 
   aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader);
   aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, aResult);
 }
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -29,17 +29,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
   : mWindowId(0)
 {
   MOZ_ASSERT(aDoc);
-  nsresult rv = aDoc->GetId(mClientId);
+  nsresult rv = aDoc->GetOrCreateId(mClientId);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to get the UUID of the document.");
   }
 
   RefPtr<nsGlobalWindow> innerWindow = static_cast<nsGlobalWindow*>(aDoc->GetInnerWindow());
   if (innerWindow) {
     // XXXcatalinb: The inner window can be null if the document is navigating
     // and was detached.
--- a/dom/workers/ServiceWorkerClient.h
+++ b/dom/workers/ServiceWorkerClient.h
@@ -28,16 +28,21 @@ class ServiceWorkerWindowClient;
 class ServiceWorkerClientInfo final
 {
   friend class ServiceWorkerClient;
   friend class ServiceWorkerWindowClient;
 
 public:
   explicit ServiceWorkerClientInfo(nsIDocument* aDoc);
 
+  const nsString& ClientId() const
+  {
+    return mClientId;
+  }
+
 private:
   nsString mClientId;
   uint64_t mWindowId;
   nsString mUrl;
 
   // Window Clients
   VisibilityState mVisibilityState;
   bool mFocused;
--- a/dom/workers/ServiceWorkerClients.cpp
+++ b/dom/workers/ServiceWorkerClients.cpp
@@ -50,63 +50,150 @@ ServiceWorkerClients::ServiceWorkerClien
 JSObject*
 ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ClientsBinding::Wrap(aCx, this, aGivenProto);
 }
 
 namespace {
 
-class ResolvePromiseWorkerRunnable final : public WorkerRunnable
+class GetRunnable final : public nsRunnable
 {
+  class ResolvePromiseWorkerRunnable final : public WorkerRunnable
+  {
+    RefPtr<PromiseWorkerProxy> mPromiseProxy;
+    UniquePtr<ServiceWorkerClientInfo> mValue;
+    nsresult mRv;
+
+  public:
+    ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                                 PromiseWorkerProxy* aPromiseProxy,
+                                 UniquePtr<ServiceWorkerClientInfo>&& aValue,
+                                 nsresult aRv)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
+        mPromiseProxy(aPromiseProxy),
+        mValue(Move(aValue)),
+        mRv(Move(aRv))
+    {
+      AssertIsOnMainThread();
+    }
+
+    bool
+    WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+    {
+      MOZ_ASSERT(aWorkerPrivate);
+      aWorkerPrivate->AssertIsOnWorkerThread();
+
+      Promise* promise = mPromiseProxy->WorkerPromise();
+      MOZ_ASSERT(promise);
+
+      if (NS_FAILED(mRv)) {
+        promise->MaybeReject(mRv);
+      } else if (mValue) {
+        RefPtr<ServiceWorkerWindowClient> windowClient =
+          new ServiceWorkerWindowClient(promise->GetParentObject(), *mValue);
+        promise->MaybeResolve(windowClient.get());
+      } else {
+        promise->MaybeResolve(JS::UndefinedHandleValue);
+      }
+      mPromiseProxy->CleanUp(aCx);
+      return true;
+    }
+  };
+
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
-  nsTArray<ServiceWorkerClientInfo> mValue;
-
+  nsString mClientId;
 public:
-  ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
-                               PromiseWorkerProxy* aPromiseProxy,
-                               nsTArray<ServiceWorkerClientInfo>& aValue)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-      mPromiseProxy(aPromiseProxy)
+  GetRunnable(PromiseWorkerProxy* aPromiseProxy,
+              const nsAString& aClientId)
+    : mPromiseProxy(aPromiseProxy),
+      mClientId(aClientId)
   {
-    AssertIsOnMainThread();
-    mValue.SwapElements(aValue);
   }
 
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  NS_IMETHOD
+  Run() override
   {
-    MOZ_ASSERT(aWorkerPrivate);
-    aWorkerPrivate->AssertIsOnWorkerThread();
+    AssertIsOnMainThread();
 
-    Promise* promise = mPromiseProxy->WorkerPromise();
-    MOZ_ASSERT(promise);
-
-    nsTArray<RefPtr<ServiceWorkerClient>> ret;
-    for (size_t i = 0; i < mValue.Length(); i++) {
-      ret.AppendElement(RefPtr<ServiceWorkerClient>(
-            new ServiceWorkerWindowClient(promise->GetParentObject(),
-                                          mValue.ElementAt(i))));
+    MutexAutoLock lock(mPromiseProxy->Lock());
+    if (mPromiseProxy->CleanedUp()) {
+      return NS_OK;
     }
 
-    promise->MaybeResolve(ret);
-    mPromiseProxy->CleanUp(aCx);
-    return true;
+    WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    ErrorResult rv;
+    UniquePtr<ServiceWorkerClientInfo> result = swm->GetClient(workerPrivate->GetPrincipal(),
+                                                               mClientId, rv);
+    RefPtr<ResolvePromiseWorkerRunnable> r =
+      new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
+                                       mPromiseProxy, Move(result),
+                                       rv.StealNSResult());
+    rv.SuppressException();
+
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    r->Dispatch(jsapi.cx());
+    return NS_OK;
   }
 };
 
 class MatchAllRunnable final : public nsRunnable
 {
+  class ResolvePromiseWorkerRunnable final : public WorkerRunnable
+  {
+    RefPtr<PromiseWorkerProxy> mPromiseProxy;
+    nsTArray<ServiceWorkerClientInfo> mValue;
+
+  public:
+    ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                                 PromiseWorkerProxy* aPromiseProxy,
+                                 nsTArray<ServiceWorkerClientInfo>& aValue)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
+        mPromiseProxy(aPromiseProxy)
+    {
+      AssertIsOnMainThread();
+      mValue.SwapElements(aValue);
+    }
+
+    bool
+    WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+    {
+      MOZ_ASSERT(aWorkerPrivate);
+      aWorkerPrivate->AssertIsOnWorkerThread();
+
+      Promise* promise = mPromiseProxy->WorkerPromise();
+      MOZ_ASSERT(promise);
+
+      nsTArray<RefPtr<ServiceWorkerClient>> ret;
+      for (size_t i = 0; i < mValue.Length(); i++) {
+        ret.AppendElement(RefPtr<ServiceWorkerClient>(
+              new ServiceWorkerWindowClient(promise->GetParentObject(),
+                                            mValue.ElementAt(i))));
+      }
+
+      promise->MaybeResolve(ret);
+      mPromiseProxy->CleanUp(aCx);
+      return true;
+    }
+  };
+
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
   nsCString mScope;
+  bool mIncludeUncontrolled;
 public:
   MatchAllRunnable(PromiseWorkerProxy* aPromiseProxy,
-                   const nsCString& aScope)
+                   const nsCString& aScope,
+                   bool aIncludeUncontrolled)
     : mPromiseProxy(aPromiseProxy),
-      mScope(aScope)
+      mScope(aScope),
+      mIncludeUncontrolled(aIncludeUncontrolled)
   {
     MOZ_ASSERT(mPromiseProxy);
   }
 
   NS_IMETHOD
   Run() override
   {
     AssertIsOnMainThread();
@@ -114,17 +201,18 @@ public:
     MutexAutoLock lock(mPromiseProxy->Lock());
     if (mPromiseProxy->CleanedUp()) {
       return NS_OK;
     }
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     nsTArray<ServiceWorkerClientInfo> result;
 
-    swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope, result);
+    swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope,
+                       mIncludeUncontrolled, result);
     RefPtr<ResolvePromiseWorkerRunnable> r =
       new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
                                        mPromiseProxy, result);
 
     AutoJSAPI jsapi;
     jsapi.Init();
     r->Dispatch(jsapi.cx());
     return NS_OK;
@@ -565,27 +653,52 @@ private:
 
     return NS_OK;
   }
 };
 
 } // namespace
 
 already_AddRefed<Promise>
+ServiceWorkerClients::Get(const nsAString& aClientId, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  RefPtr<PromiseWorkerProxy> promiseProxy =
+    PromiseWorkerProxy::Create(workerPrivate, promise);
+  if (!promiseProxy) {
+    promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+    return promise.forget();
+  }
+
+  RefPtr<GetRunnable> r =
+    new GetRunnable(promiseProxy, aClientId);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
 ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
                                ErrorResult& aRv)
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
   workerPrivate->AssertIsOnWorkerThread();
 
   nsString scope;
   mWorkerScope->GetScope(scope);
 
-  if (aOptions.mIncludeUncontrolled || aOptions.mType != ClientType::Window) {
+  if (aOptions.mType != ClientType::Window) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
   RefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
@@ -594,17 +707,18 @@ ServiceWorkerClients::MatchAll(const Cli
     PromiseWorkerProxy::Create(workerPrivate, promise);
   if (!promiseProxy) {
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     return promise.forget();
   }
 
   RefPtr<MatchAllRunnable> r =
     new MatchAllRunnable(promiseProxy,
-                         NS_ConvertUTF16toUTF8(scope));
+                         NS_ConvertUTF16toUTF8(scope),
+                         aOptions.mIncludeUncontrolled);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
                                  ErrorResult& aRv)
 {
--- a/dom/workers/ServiceWorkerClients.h
+++ b/dom/workers/ServiceWorkerClients.h
@@ -25,16 +25,19 @@ class ServiceWorkerClients final : publi
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ServiceWorkerClients)
 
   explicit ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope);
 
   already_AddRefed<Promise>
+  Get(const nsAString& aClientId, ErrorResult& aRv);
+
+  already_AddRefed<Promise>
   MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   OpenWindow(const nsAString& aUrl, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   Claim(ErrorResult& aRv);
 
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -97,16 +97,17 @@ FetchEvent::Constructor(const GlobalObje
   RefPtr<EventTarget> owner = do_QueryObject(aGlobal.GetAsSupports());
   MOZ_ASSERT(owner);
   RefPtr<FetchEvent> e = new FetchEvent(owner);
   bool trusted = e->Init(owner);
   e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
   e->SetTrusted(trusted);
   e->mRequest = aOptions.mRequest.WasPassed() ?
       &aOptions.mRequest.Value() : nullptr;
+  e->mClientId = aOptions.mClientId;
   e->mIsReload = aOptions.mIsReload;
   return e.forget();
 }
 
 namespace {
 
 void
 AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -102,16 +102,17 @@ public:
 };
 
 class FetchEvent final : public ExtendableEvent
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
   RefPtr<Request> mRequest;
   nsCString mScriptSpec;
   nsCString mPreventDefaultScriptSpec;
+  nsString mClientId;
   uint32_t mPreventDefaultLineNumber;
   uint32_t mPreventDefaultColumnNumber;
   bool mIsReload;
   bool mWaitToRespond;
 protected:
   explicit FetchEvent(EventTarget* aOwner);
   ~FetchEvent();
 
@@ -144,16 +145,22 @@ public:
   }
 
   Request*
   GetRequest_() const
   {
     return mRequest;
   }
 
+  void
+  GetClientId(nsAString& aClientId) const
+  {
+    aClientId = mClientId;
+  }
+
   bool
   IsReload() const
   {
     return mIsReload;
   }
 
   void
   RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv);
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -15,21 +15,23 @@
 #include "nsIStreamLoader.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIJARChannel.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIMutableArray.h"
 #include "nsIScriptError.h"
+#include "nsISimpleEnumerator.h"
 #include "nsIUploadChannel2.h"
 #include "nsPIDOMWindow.h"
 #include "nsScriptLoader.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDebug.h"
+#include "nsISupportsPrimitives.h"
 
 #include "jsapi.h"
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/Telemetry.h"
@@ -3042,30 +3044,31 @@ ServiceWorkerManager::MaybeRemoveRegistr
   }
 
   if (data->mOrderedScopes.IsEmpty() && data->mJobQueues.Count() == 0) {
     mRegistrationInfos.Remove(aScopeKey);
   }
 }
 
 void
-ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
+ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc,
+                                            const nsAString& aDocumentId)
 {
   AssertIsOnMainThread();
 
   // We keep a set of documents that service workers may choose to start
   // controlling using claim().
   MOZ_ASSERT(!mAllDocuments.Contains(aDoc));
   mAllDocuments.PutEntry(aDoc);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(aDoc);
   if (registration) {
     MOZ_ASSERT(!mControlledDocuments.Contains(aDoc));
-    StartControllingADocument(registration, aDoc);
+    StartControllingADocument(registration, aDoc, aDocumentId);
   }
 }
 
 void
 ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
 {
   MOZ_ASSERT(aDoc);
   RefPtr<ServiceWorkerRegistrationInfo> registration;
@@ -3077,23 +3080,27 @@ ServiceWorkerManager::MaybeStopControlli
     StopControllingADocument(registration);
   }
 
   mAllDocuments.RemoveEntry(aDoc);
 }
 
 void
 ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
-                                                nsIDocument* aDoc)
+                                                nsIDocument* aDoc,
+                                                const nsAString& aDocumentId)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
+  if (!aDocumentId.IsEmpty()) {
+    aDoc->SetId(aDocumentId);
+  }
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 }
 
 void
 ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration)
 {
   aRegistration->StopControllingADocument();
   if (!aRegistration->IsControllingDocuments()) {
@@ -3261,28 +3268,28 @@ ServiceWorkerManager::GetServiceWorkerFo
 
 namespace {
 
 class ContinueDispatchFetchEventRunnable : public nsRunnable
 {
   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
   nsCOMPtr<nsIInterceptedChannel> mChannel;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
-  UniquePtr<ServiceWorkerClientInfo> mClientInfo;
+  nsString mDocumentId;
   bool mIsReload;
 public:
   ContinueDispatchFetchEventRunnable(ServiceWorkerPrivate* aServiceWorkerPrivate,
                                      nsIInterceptedChannel* aChannel,
                                      nsILoadGroup* aLoadGroup,
-                                     UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
+                                     const nsAString& aDocumentId,
                                      bool aIsReload)
     : mServiceWorkerPrivate(aServiceWorkerPrivate)
     , mChannel(aChannel)
     , mLoadGroup(aLoadGroup)
-    , mClientInfo(Move(aClientInfo))
+    , mDocumentId(aDocumentId)
     , mIsReload(aIsReload)
   {
     MOZ_ASSERT(aServiceWorkerPrivate);
     MOZ_ASSERT(aChannel);
   }
 
   void
   HandleError()
@@ -3311,56 +3318,62 @@ public:
     nsresult status;
     rv = channel->GetStatus(&status);
     if (NS_WARN_IF(NS_FAILED(rv) || NS_FAILED(status))) {
       HandleError();
       return NS_OK;
     }
 
     rv = mServiceWorkerPrivate->SendFetchEvent(mChannel, mLoadGroup,
-                                               Move(mClientInfo), mIsReload);
+                                               mDocumentId, mIsReload);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       HandleError();
     }
 
     return NS_OK;
   }
 };
 
 } // anonymous namespace
 
 already_AddRefed<nsIRunnable>
 ServiceWorkerManager::PrepareFetchEvent(const PrincipalOriginAttributes& aOriginAttributes,
                                         nsIDocument* aDoc,
+                                        const nsAString& aDocumentIdForTopLevelNavigation,
                                         nsIInterceptedChannel* aChannel,
                                         bool aIsReload,
                                         bool aIsSubresourceLoad,
                                         ErrorResult& aRv)
 {
   MOZ_ASSERT(aChannel);
   AssertIsOnMainThread();
 
   RefPtr<ServiceWorkerInfo> serviceWorker;
   nsCOMPtr<nsILoadGroup> loadGroup;
-  UniquePtr<ServiceWorkerClientInfo> clientInfo;
+  nsAutoString documentId;
 
   if (aIsSubresourceLoad) {
     MOZ_ASSERT(aDoc);
     serviceWorker = GetActiveWorkerInfoForDocument(aDoc);
     loadGroup = aDoc->GetDocumentLoadGroup();
-    clientInfo.reset(new ServiceWorkerClientInfo(aDoc));
+    nsresult rv = aDoc->GetOrCreateId(documentId);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
   } else {
     nsCOMPtr<nsIChannel> internalChannel;
     aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     internalChannel->GetLoadGroup(getter_AddRefs(loadGroup));
 
+    documentId = aDocumentIdForTopLevelNavigation;
+
     nsCOMPtr<nsIURI> uri;
     aRv = internalChannel->GetURI(getter_AddRefs(uri));
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     RefPtr<ServiceWorkerRegistrationInfo> registration =
       GetServiceWorkerRegistrationInfo(aOriginAttributes, uri);
@@ -3379,17 +3392,17 @@ ServiceWorkerManager::PrepareFetchEvent(
 
   if (NS_WARN_IF(aRv.Failed()) || !serviceWorker) {
     return nullptr;
   }
 
   nsCOMPtr<nsIRunnable> continueRunnable =
     new ContinueDispatchFetchEventRunnable(serviceWorker->WorkerPrivate(),
                                            aChannel, loadGroup,
-                                           Move(clientInfo), aIsReload);
+                                           documentId, aIsReload);
 
   return continueRunnable.forget();
 }
 
 void
 ServiceWorkerManager::DispatchPreparedFetchEvent(nsIInterceptedChannel* aChannel,
                                                  nsIRunnable* aPreparedRunnable,
                                                  ErrorResult& aRv)
@@ -3696,46 +3709,135 @@ FireControllerChangeOnDocument(nsIDocume
   container->ControllerChanged(result);
   if (result.Failed()) {
     NS_WARNING("Failed to dispatch controllerchange event");