merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 13 Sep 2017 23:58:43 +0200
changeset 430208 8645a74bbbd06b67699317df1abf3897db0e43d5
parent 430118 0b3646aa9cbf3f77ee574a553ade9685e9229ab5 (current diff)
parent 430207 c777acbcd2a9f0bcf14cbb0fffcdf399d8d6c8d2 (diff)
child 430209 c15e2f280729b6503f9455cd4448ab2852eb5806
child 430265 9d99ac9ae088bcee2b7f89f2aff10ff0bea73f56
child 430318 2cc3aa0395485e7139c5ab1fd5b515f976f5c074
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone57.0a1
first release with
nightly linux32
8645a74bbbd0 / 57.0a1 / 20170913220121 / files
nightly linux64
8645a74bbbd0 / 57.0a1 / 20170913220121 / files
nightly mac
8645a74bbbd0 / 57.0a1 / 20170913220121 / files
nightly win32
8645a74bbbd0 / 57.0a1 / 20170913220121 / files
nightly win64
8645a74bbbd0 / 57.0a1 / 20170913220121 / 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. r=merge a=merge MozReview-Commit-ID: 2iVDKexRjxu
browser/base/content/test/urlbar/browser_urlbar_search_no_speculative_connect_with_client_cert.js
devtools/client/netmonitor/src/assets/styles/netmonitor.css
devtools/client/sourceeditor/editor.js
layout/base/PresShell.cpp
mobile/android/modules/geckoview/moz.build
modules/libpref/init/all.js
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/webmessaging/messageerror.html.ini
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -1101,17 +1101,21 @@ struct RoleDescrComparator
 
   return [NSString stringWithFormat:@"(%p) %@", self, [self role]];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (BOOL)isFocused
 {
-  return FocusMgr()->IsFocused([self getGeckoAccessible]);
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    return FocusMgr()->IsFocused(accWrap);
+  }
+
+  return false; //XXX: proxy implementation is needed.
 }
 
 - (BOOL)canBeFocused
 {
   if (AccessibleWrap* accWrap = [self getGeckoAccessible])
       return accWrap->InteractiveState() & states::FOCUSABLE;
 
   if (ProxyAccessible* proxy = [self getProxyAccessible])
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -27,16 +27,18 @@ support-files =
   bug792517.html
   bug792517.sjs
   bug839103.css
   clipboard_pastefile.html
   contextmenu_common.js
   ctxmenu-image.png
   discovery.html
   download_page.html
+  download_page_1.txt
+  download_page_2.txt
   dummy_page.html
   feed_tab.html
   file_generic_favicon.ico
   file_with_favicon.html
   file_mediaPlayback.html
   file_bug970276_popup1.html
   file_bug970276_popup2.html
   file_bug970276_favicon1.ico
--- a/browser/base/content/test/general/browser_bug575561.js
+++ b/browser/base/content/test/general/browser_bug575561.js
@@ -1,15 +1,20 @@
 requestLongerTimeout(2);
 
 const TEST_URL = "http://example.com/browser/browser/base/content/test/general/app_bug575561.html";
 
 add_task(async function() {
   SimpleTest.requestCompleteLog();
 
+  // allow top level data: URI navigations, otherwise clicking data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
+
   // Pinned: Link to the same domain should not open a new tab
   // Tests link to http://example.com/browser/browser/base/content/test/general/dummy_page.html
   await testLink(0, true, false);
   // Pinned: Link to a different subdomain should open a new tab
   // Tests link to http://test1.example.com/browser/browser/base/content/test/general/dummy_page.html
   await testLink(1, true, true);
 
   // Pinned: Link to a different domain should open a new tab
--- a/browser/base/content/test/general/browser_bug734076.js
+++ b/browser/base/content/test/general/browser_bug734076.js
@@ -1,12 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 add_task(async function() {
+
+  // allow top level data: URI navigations, otherwise loading data: URIs
+  // in toplevel windows fail.
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
+
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, null, false);
 
   let browser = tab.linkedBrowser;
   browser.stop(); // stop the about:blank load
 
   let writeDomainURL = encodeURI("data:text/html,<script>document.write(document.domain);</script>");
 
   let tests = [
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -1,29 +1,31 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 
 const PREF_DISABLE_OPEN_NEW_WINDOW = "browser.link.open_newwindow.disabled_in_fullscreen";
+const PREF_BLOCK_TOPLEVEL_DATA = "security.data_uri.block_toplevel_data_uri_navigations";
 const isOSX = (Services.appinfo.OS === "Darwin");
 
 const TEST_FILE = "file_fullscreen-window-open.html";
 const gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/",
                                                           "http://127.0.0.1:8888/");
 
 var newWin;
 var newBrowser;
 
 async function test() {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref(PREF_DISABLE_OPEN_NEW_WINDOW, true);
+  Services.prefs.setBoolPref(PREF_BLOCK_TOPLEVEL_DATA, false);
 
   newWin = await BrowserTestUtils.openNewBrowserWindow();
   newBrowser = newWin.gBrowser;
   await promiseTabLoadEvent(newBrowser.selectedTab, gHttpTestRoot + TEST_FILE);
 
   // Enter browser fullscreen mode.
   newWin.BrowserFullScreen();
 
@@ -32,16 +34,17 @@ async function test() {
 
 registerCleanupFunction(async function() {
   // Exit browser fullscreen mode.
   newWin.BrowserFullScreen();
 
   await BrowserTestUtils.closeWindow(newWin);
 
   Services.prefs.clearUserPref(PREF_DISABLE_OPEN_NEW_WINDOW);
+  Services.prefs.clearUserPref(PREF_BLOCK_TOPLEVEL_DATA);
 });
 
 var gTests = [
   test_open,
   test_open_with_size,
   test_open_with_pos,
   test_open_with_outerSize,
   test_open_with_innerSize,
--- a/browser/base/content/test/general/download_page.html
+++ b/browser/base/content/test/general/download_page.html
@@ -6,23 +6,23 @@ https://bugzilla.mozilla.org/show_bug.cg
   <head>
     <title>Test for the download attribute</title>
 
   </head>
   <body>
     <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=676619">Bug 676619</a>
     <br/>
     <ul>
-        <li><a href="data:text/plain,Hey What are you looking for?"
+        <li><a href="download_page_1.txt"
                 download="test.txt" id="link1">Download "test.txt"</a></li>
         <li><a href="video.ogg"
                 download id="link2">Download "video.ogg"</a></li>
         <li><a href="video.ogg"
                 download="just some video" id="link3">Download "just some video"</a></li>
-        <li><a href="data:text/plain,test"
+        <li><a href="download_page_2.txt"
                 download="with-target.txt" id="link4">Download "with-target.txt"</a></li>
         <li><a href="javascript:(1+2)+''"
             download="javascript.txt" id="link5">Download "javascript.txt"</a></li>
     </ul>
     <script>
         var li = document.createElement("li");
         var a = document.createElement("a");
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/download_page_1.txt
@@ -0,0 +1,1 @@
+Hey What are you looking for?
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/download_page_2.txt
@@ -0,0 +1,1 @@
+test
--- a/browser/base/content/test/popups/browser.ini
+++ b/browser/base/content/test/popups/browser.ini
@@ -1,6 +1,12 @@
 [browser_popupUI.js]
 [browser_popup_blocker.js]
-support-files = popup_blocker.html
+support-files =
+  popup_blocker.html
+  popup_blocker_a.html
+  popup_blocker_b.html
 skip-if = (os == 'linux') || (e10s && debug) # Frequent bug 1081925 and bug 1125520 failures
 [browser_popup_frames.js]
-support-files = popup_blocker.html
+support-files =
+  popup_blocker.html
+  popup_blocker_a.html
+  popup_blocker_b.html
--- a/browser/base/content/test/popups/browser_popup_blocker.js
+++ b/browser/base/content/test/popups/browser_popup_blocker.js
@@ -59,18 +59,18 @@ add_task(async function test_opening_blo
   let allow = menu.querySelector("[observes='blockedPopupAllowSite']");
   allow.doCommand();
   await BrowserTestUtils.waitForCondition(() =>
     popupTabs.length == 2 &&
     popupTabs.every(aTab => aTab.linkedBrowser.currentURI.spec != "about:blank"));
 
   gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
 
-  is(popupTabs[0].linkedBrowser.currentURI.spec, "data:text/plain;charset=utf-8,a", "Popup a");
-  is(popupTabs[1].linkedBrowser.currentURI.spec, "data:text/plain;charset=utf-8,b", "Popup b");
+  ok(popupTabs[0].linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), "Popup a");
+  ok(popupTabs[1].linkedBrowser.currentURI.spec.endsWith("popup_blocker_b.html"), "Popup b");
 
   // Clean up.
   gBrowser.removeTab(tab);
   for (let popup of popupTabs) {
     gBrowser.removeTab(popup);
   }
   clearAllPermissionsByPrefix("popup");
   // Ensure the menu closes.
--- a/browser/base/content/test/popups/popup_blocker.html
+++ b/browser/base/content/test/popups/popup_blocker.html
@@ -1,13 +1,13 @@
 <!doctype html>
 <html>
   <head>
     <meta charset="UTF-8">
     <title>Page creating two popups</title>
   </head>
   <body>
     <script type="text/javascript">
-      window.open("data:text/plain;charset=utf-8,a", "a");
-      window.open("data:text/plain;charset=utf-8,b", "b");
+      window.open("popup_blocker_a.html", "a");
+      window.open("popup_blocker_b.html", "b");
     </script>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popups/popup_blocker_a.html
@@ -0,0 +1,1 @@
+<html><body>a</body></html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popups/popup_blocker_b.html
@@ -0,0 +1,1 @@
+<html><body>b</body></html>
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -24,16 +24,17 @@ support-files =
 [browser_bug1024133-switchtab-override-keynav.js]
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_bug1070778.js]
 [browser_bug1225194-remotetab.js]
 [browser_bug304198.js]
 [browser_bug556061.js]
 subsuite = clipboard
 [browser_bug562649.js]
+support-files = file_bug562649.html
 [browser_bug623155.js]
 support-files =
   redirect_bug623155.sjs
 [browser_bug783614.js]
 [browser_canonizeURL.js]
 [browser_dragdropURL.js]
 [browser_locationBarCommand.js]
 [browser_locationBarExternalLoad.js]
@@ -114,17 +115,16 @@ support-files =
   file_urlbar_edit_dos.html
 [browser_urlbar_searchsettings.js]
 [browser_urlbar_search_speculative_connect.js]
 [browser_urlbar_search_speculative_connect_engine.js]
 support-files =
   searchSuggestionEngine2.xml
   searchSuggestionEngine.sjs
 [browser_urlbar_search_speculative_connect_mousedown.js]
-[browser_urlbar_search_no_speculative_connect_with_client_cert.js]
 [browser_urlbar_stop_pending.js]
 support-files =
   slow-page.sjs
 [browser_urlbar_remoteness_switch.js]
 run-if = e10s
 [browser_urlHighlight.js]
 [browser_wyciwyg_urlbarCopying.js]
 subsuite = clipboard
--- a/browser/base/content/test/urlbar/browser_bug562649.js
+++ b/browser/base/content/test/urlbar/browser_bug562649.js
@@ -1,10 +1,11 @@
 function test() {
-  const URI = "data:text/plain,bug562649";
+  const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
+  const URI = TEST_PATH + "file_bug562649.html";
   window.browserDOMWindow.openURI(makeURI(URI),
                                   null,
                                   Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
                                   Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
                                   Services.scriptSecurityManager.getSystemPrincipal());
 
   is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
   is(gURLBar.value, URI, "location bar value matches test URI");
deleted file mode 100644
--- a/browser/base/content/test/urlbar/browser_urlbar_search_no_speculative_connect_with_client_cert.js
+++ /dev/null
@@ -1,182 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Test that if we're attempting to speculatively connect to a site but it
-// requests a client certificate, we cancel the speculative connection (this
-// avoids an unexpected "select a client certificate" dialog).
-
-const { MockRegistrar } =
-  Cu.import("resource://testing-common/MockRegistrar.jsm", {});
-
-const certService = Cc["@mozilla.org/security/local-cert-service;1"]
-                      .getService(Ci.nsILocalCertService);
-const certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
-                              .getService(Ci.nsICertOverrideService);
-
-const host = "localhost";
-let uri;
-let handshakeDone = false;
-let expectingChooseCertificate = false;
-let chooseCertificateCalled = false;
-
-const clientAuthDialogs = {
-  chooseCertificate(ctx, hostname, port, organization, issuerOrg, certList,
-                    selectedIndex) {
-    ok(expectingChooseCertificate,
-       `${expectingChooseCertificate ? "" : "not "}expecting chooseCertificate to be called`);
-    is(certList.length, 1, "should have only one client certificate available");
-    selectedIndex.value = 0;
-    chooseCertificateCalled = true;
-    return true;
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIClientAuthDialogs]),
-};
-
-function startServer(cert) {
-  let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
-                    .createInstance(Ci.nsITLSServerSocket);
-  tlsServer.init(-1, true, -1);
-  tlsServer.serverCert = cert;
-
-  let input, output;
-
-  let listener = {
-    onSocketAccepted(socket, transport) {
-      info("Accepted TLS client connection");
-      let connectionInfo = transport.securityInfo
-                           .QueryInterface(Ci.nsITLSServerConnectionInfo);
-      connectionInfo.setSecurityObserver(listener);
-      input = transport.openInputStream(0, 0, 0);
-      output = transport.openOutputStream(0, 0, 0);
-    },
-
-    onHandshakeDone(socket, status) {
-      info("TLS handshake done");
-      handshakeDone = true;
-
-      input.asyncWait({
-        onInputStreamReady(readyInput) {
-          try {
-            let request = NetUtil.readInputStreamToString(readyInput,
-                                                          readyInput.available());
-            ok(request.startsWith("GET /") && request.includes("HTTP/1.1"),
-               "expecting an HTTP/1.1 GET request");
-            let response = "HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n" +
-                           "Connection:Close\r\nContent-Length:2\r\n\r\nOK";
-            output.write(response, response.length);
-          } catch (e) {
-            // This will fail when we close the speculative connection.
-          }
-        }
-      }, 0, 0, Services.tm.currentThread);
-    },
-
-    onStopListening() {
-      info("onStopListening");
-      input.close();
-      output.close();
-    }
-  };
-
-  tlsServer.setSessionCache(false);
-  tlsServer.setSessionTickets(false);
-  tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_ALWAYS);
-
-  tlsServer.asyncListen(listener);
-
-  return tlsServer;
-}
-
-let server;
-
-add_task(async function setup() {
-  await SpecialPowers.pushPrefEnv({
-    set: [["browser.urlbar.autoFill", true],
-          // Turn off search suggestion so we won't speculative connect to the search engine.
-          ["browser.search.suggest.enabled", false],
-          ["browser.urlbar.speculativeConnect.enabled", true],
-          // In mochitest this number is 0 by default but we have to turn it on.
-          ["network.http.speculative-parallel-limit", 6],
-          // The http server is using IPv4, so it's better to disable IPv6 to avoid weird
-          // networking problem.
-          ["network.dns.disableIPv6", true],
-          ["security.default_personal_cert", "Ask Every Time"]],
-  });
-
-  let clientAuthDialogsCID =
-    MockRegistrar.register("@mozilla.org/nsClientAuthDialogs;1",
-                           clientAuthDialogs);
-
-  let cert = await new Promise((resolve, reject) => {
-    certService.getOrCreateCert("speculative-connect", {
-      handleCert(c, rv) {
-        if (!Components.isSuccessCode(rv)) {
-          reject(rv);
-          return;
-        }
-        resolve(c);
-      }
-    });
-  });
-  server = startServer(cert);
-  uri = `https://${host}:${server.port}/`;
-  info(`running tls server at ${uri}`);
-  await PlacesTestUtils.addVisits([{
-    uri,
-    title: "test visit for speculative connection",
-    transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
-  }]);
-
-  let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
-                     Ci.nsICertOverrideService.ERROR_MISMATCH;
-  certOverrideService.rememberValidityOverride("localhost", server.port, cert,
-                                               overrideBits, true);
-
-  registerCleanupFunction(async function() {
-    await PlacesUtils.history.clear();
-    MockRegistrar.unregister(clientAuthDialogsCID);
-    certOverrideService.clearValidityOverride("localhost", server.port);
-  });
-});
-
-add_task(async function popup_mousedown_no_client_cert_dialog_until_navigate_test() {
-  const test = {
-    // To not trigger autofill, search keyword starts from the second character.
-    search: host.substr(1, 4),
-    completeValue: uri
-  };
-  info(`Searching for '${test.search}'`);
-  await promiseAutocompleteResultPopup(test.search, window, true);
-  let controller = gURLBar.popup.input.controller;
-  // The first item should be 'Search with ...' thus we want the second.
-  let value = controller.getFinalCompleteValueAt(1);
-  info(`The value of the second item is ${value}`);
-  is(value, test.completeValue, "The second item has the url we visited.");
-
-  await BrowserTestUtils.waitForCondition(() => {
-    return !!gURLBar.popup.richlistbox.childNodes[1] &&
-           is_visible(gURLBar.popup.richlistbox.childNodes[1]);
-  }, "the node is there.");
-
-  let listitem = gURLBar.popup.richlistbox.childNodes[1];
-  EventUtils.synthesizeMouse(listitem, 10, 10, {type: "mousedown"}, window);
-  is(gURLBar.popup.richlistbox.selectedIndex, 1, "The second item is selected");
-  // Since we don't know before connecting that a server will request a client
-  // certificate, we actually do make a speculative connection. The trick is
-  // that we cancel it and don't re-use it if we are asked for a certificate
-  // (and of course we don't show the certificate-picking UI). So, the TLS
-  // server will actually complete the handshake.
-  await BrowserTestUtils.waitForCondition(() => handshakeDone,
-                                          "waiting for handshake to complete");
-  // Now mouseup, expect that we choose a client certificate, and expect that we
-  // successfully load a page.
-  expectingChooseCertificate = true;
-  EventUtils.synthesizeMouse(listitem, 10, 10, {type: "mouseup"}, window);
-  await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-  ok(chooseCertificateCalled, "chooseCertificate must have been called");
-  server.close();
-});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/file_bug562649.html
@@ -0,0 +1,1 @@
+<html><body>bug562649</body></html>
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
@@ -198,16 +198,22 @@ add_task(async function testBadPermissio
     },
   });
 
   await BrowserTestUtils.removeTab(tab2);
   await BrowserTestUtils.removeTab(tab1);
 });
 
 add_task(async function testMatchDataURI() {
+  // allow top level data: URI navigations, otherwise
+  // window.location.href = data: would be blocked
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]],
+  });
+
   const target = ExtensionTestUtils.loadExtension({
     files: {
       "page.html": `<!DOCTYPE html>
         <meta charset="utf-8">
         <script src="page.js"></script>
         <iframe id="inherited" src="data:text/html;charset=utf-8,inherited"></iframe>
       `,
       "page.js": function() {
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation_aboutPages.js
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation_aboutPages.js
@@ -63,16 +63,21 @@ function frame_script() {
   let element = content.document.getElementById("test");
   element.click();
 }
 
 /**
  * Check if data: URI inherits firstPartyDomain from about:blank correctly.
  */
 add_task(async function test_remote_window_open_data_uri() {
+  // allow top level data: URI navigations, otherwise
+  // <a href="data:" would fail.
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
   let win = await BrowserTestUtils.openNewBrowserWindow({ remote: true });
   let browser = win.gBrowser.selectedBrowser;
   let mm = browser.messageManager;
   mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
 
   await BrowserTestUtils.browserLoaded(browser, false, function(url) {
     return url == "data:text/plain,hello";
   });
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1593,29 +1593,36 @@ var PlacesControllerDragHelper = {
     let parentGuid = insertionPoint.guid;
     let tagName = insertionPoint.tagName;
 
     // Following flavors may contain duplicated data.
     let duplicable = new Map();
     duplicable.set(PlacesUtils.TYPE_UNICODE, new Set());
     duplicable.set(PlacesUtils.TYPE_X_MOZ_URL, new Set());
 
+    // Collect all data from the DataTransfer before processing it, as the
+    // DataTransfer is only valid during the synchronous handling of the `drop`
+    // event handler callback.
+    let dtItems = [];
     for (let i = 0; i < dropCount; ++i) {
       let flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
       if (!flavor)
         return;
 
       let data = dt.mozGetDataAt(flavor, i);
       if (duplicable.has(flavor)) {
         let handled = duplicable.get(flavor);
         if (handled.has(data))
           continue;
         handled.add(data);
       }
+      dtItems.push({flavor, data});
+    }
 
+    for (let {flavor, data} of dtItems) {
       let nodes;
       if (flavor != TAB_DROP_TYPE) {
         nodes = PlacesUtils.unwrapNodes(data, flavor);
       } else if (data instanceof XULElement && data.localName == "tab" &&
                data.ownerGlobal instanceof ChromeWindow) {
         let uri = data.linkedBrowser.currentURI;
         let spec = uri ? uri.spec : "about:blank";
         nodes = [{ uri: spec,
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js
@@ -17,16 +17,20 @@ const POPUP_LINK = `data:text/html;chars
 const WINDOW_BODY = `data:text/html,
                      <a href="%23" id="first"
                         onclick="window.open('${POPUP_LINK}', '_blank',
                                              'width=630,height=500')">
                        First click this.
                      </a>`;
 
 add_task(async function test_private_popup_window_opens_private_tabs() {
+  // allow top level data: URI navigations, otherwise clicking a data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
   let privWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
 
   // Sanity check - this browser better be private.
   ok(PrivateBrowsingUtils.isWindowPrivate(privWin),
      "Opened a private browsing window.");
 
   // First, open a private browsing window, and load our
   // testing page.
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -46,16 +46,18 @@ var gCurrentEpoch = 0;
 
 // A bound to the size of data to store for DOM Storage.
 const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
 
 // This pref controls whether or not we send updates to the parent on a timeout
 // or not, and should only be used for tests or debugging.
 const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
 
+const PREF_INTERVAL = "browser.sessionstore.interval";
+
 const kNoIndex = Number.MAX_SAFE_INTEGER;
 const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
 
 /**
  * A function that will recursively call |cb| to collected data for all
  * non-dynamic frames in the current frame/docShell tree.
  */
 function mapFrameTree(callback) {
@@ -728,29 +730,46 @@ var MessageQueue = {
 
   /**
    * The delay (in ms) used to delay sending changes after data has been
    * invalidated.
    */
   BATCH_DELAY_MS: 1000,
 
   /**
+   * The minimum idle period (in ms) we need for sending data to chrome process.
+   */
+  NEEDED_IDLE_PERIOD_MS: 5,
+
+  /**
+   * Timeout for waiting an idle period to send data. We will set this from
+   * the pref "browser.sessionstore.interval".
+   */
+  _timeoutWaitIdlePeriodMs: null,
+
+  /**
    * The current timeout ID, null if there is no queue data. We use timeouts
    * to damp a flood of data changes and send lots of changes as one batch.
    */
   _timeout: null,
 
   /**
    * Whether or not sending batched messages on a timer is disabled. This should
    * only be used for debugging or testing. If you need to access this value,
    * you should probably use the timeoutDisabled getter.
    */
   _timeoutDisabled: false,
 
   /**
+   * The idle callback ID referencing an active idle callback. When no idle
+   * callback is pending, this is null.
+   * */
+  _idleCallbackID: null,
+
+  /**
    * True if batched messages are not being fired on a timer. This should only
    * ever be true when debugging or during tests.
    */
   get timeoutDisabled() {
     return this._timeoutDisabled;
   },
 
   /**
@@ -766,28 +785,58 @@ var MessageQueue = {
     }
 
     return val;
   },
 
   init() {
     this.timeoutDisabled =
       Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+    this._timeoutWaitIdlePeriodMs =
+      Services.prefs.getIntPref(PREF_INTERVAL);
 
     Services.prefs.addObserver(TIMEOUT_DISABLED_PREF, this);
+    Services.prefs.addObserver(PREF_INTERVAL, this);
   },
 
   uninit() {
     Services.prefs.removeObserver(TIMEOUT_DISABLED_PREF, this);
+    Services.prefs.removeObserver(PREF_INTERVAL, this);
+    this.cleanupTimers();
+  },
+
+  /**
+   * Cleanup pending idle callback and timer.
+   */
+  cleanupTimers() {
+    if (this._idleCallbackID) {
+      content.cancelIdleCallback(this._idleCallbackID);
+      this._idleCallbackID = null;
+    }
+    if (this._timeout) {
+      clearTimeout(this._timeout);
+      this._timeout = null;
+    }
   },
 
   observe(subject, topic, data) {
-    if (topic == "nsPref:changed" && data == TIMEOUT_DISABLED_PREF) {
-      this.timeoutDisabled =
-        Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+    if (topic == "nsPref:changed") {
+      switch (data) {
+        case TIMEOUT_DISABLED_PREF:
+          this.timeoutDisabled =
+            Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+          break;
+        case PREF_INTERVAL:
+          this._timeoutWaitIdlePeriodMs =
+            Services.prefs.getIntPref(PREF_INTERVAL);
+          break;
+        default:
+          debug("received unknown message '" + data + "'");
+          break;
+      }
     }
   },
 
   /**
    * Pushes a given |value| onto the queue. The given |key| represents the type
    * of data that is stored and can override data that has been queued before
    * but has not been sent to the parent process, yet.
    *
@@ -798,39 +847,58 @@ var MessageQueue = {
    *        process.
    */
   push(key, fn) {
     this._data.set(key, fn);
 
     if (!this._timeout && !this._timeoutDisabled) {
       // Wait a little before sending the message to batch multiple changes.
       this._timeout = setTimeoutWithTarget(
-        () => this.send(), this.BATCH_DELAY_MS, tabEventTarget);
+        () => this.sendWhenIdle(), this.BATCH_DELAY_MS, tabEventTarget);
     }
   },
 
   /**
+   * Sends queued data when the remaining idle time is enough or waiting too
+   * long; otherwise, request an idle time again. If the |deadline| is not
+   * given, this function is going to schedule the first request.
+   *
+   * @param deadline (object)
+   *        An IdleDeadline object passed by requestIdleCallback().
+   */
+  sendWhenIdle(deadline) {
+    if (deadline) {
+      if (deadline.didTimeout || deadline.timeRemaining() > MessageQueue.NEEDED_IDLE_PERIOD_MS) {
+        MessageQueue.send();
+        return;
+      }
+    } else if (MessageQueue._idleCallbackID) {
+      // Bail out if there's a pending run.
+      return;
+    }
+    MessageQueue._idleCallbackID =
+      content.requestIdleCallback(MessageQueue.sendWhenIdle, {timeout: MessageQueue._timeoutWaitIdlePeriodMs});
+   },
+
+  /**
    * Sends queued data to the chrome process.
    *
    * @param options (object)
    *        {flushID: 123} to specify that this is a flush
    *        {isFinal: true} to signal this is the final message sent on unload
    */
   send(options = {}) {
     // Looks like we have been called off a timeout after the tab has been
     // closed. The docShell is gone now and we can just return here as there
     // is nothing to do.
     if (!docShell) {
       return;
     }
 
-    if (this._timeout) {
-      clearTimeout(this._timeout);
-      this._timeout = null;
-    }
+    this.cleanupTimers();
 
     let flushID = (options && options.flushID) || 0;
     let histID = "FX_SESSION_RESTORE_CONTENT_COLLECT_DATA_MS";
 
     let data = {};
     for (let [key, func] of this._data) {
       if (key != "isPrivate") {
         TelemetryStopwatch.startKeyed(histID, key);
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -65,17 +65,19 @@ support-files =
 
 #disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html
 #disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html
 #disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html
 
 [browser_aboutPrivateBrowsing.js]
 [browser_aboutSessionRestore.js]
 [browser_async_duplicate_tab.js]
+support-files = file_async_duplicate_tab.html
 [browser_async_flushes.js]
+support-files = file_async_flushes.html
 run-if = e10s && crashreporter
 skip-if = debug # bug 1167933
 [browser_async_remove_tab.js]
 run-if = e10s
 skip-if = debug # bug 1211084
 [browser_attributes.js]
 [browser_backup_recovery.js]
 [browser_broadcast.js]
@@ -106,16 +108,18 @@ skip-if = (os == 'win') # bug 1331853
 [browser_purge_shistory.js]
 skip-if = e10s # Bug 1271024
 [browser_replace_load.js]
 [browser_restore_redirect.js]
 [browser_restore_cookies_noOriginAttributes.js]
 [browser_scrollPositions.js]
 [browser_scrollPositionsReaderMode.js]
 [browser_sessionHistory.js]
+support-files =
+  file_sessionHistory_hashchange.html
 [browser_sessionStorage.js]
 [browser_sessionStorage_size.js]
 [browser_tab_label_during_restore.js]
 [browser_swapDocShells.js]
 [browser_switch_remoteness.js]
 run-if = e10s
 [browser_upgrade_backup.js]
 [browser_windowRestore_perwindowpb.js]
--- a/browser/components/sessionstore/test/browser_911547.js
+++ b/browser/components/sessionstore/test/browser_911547.js
@@ -6,16 +6,20 @@
 //    this tests that session restore component does restore the right
 //    content security policy with the document. (The policy being
 //    tested disallows inline scripts).
 // b) if security.data_uri.unique_opaque_origin == true, then
 //    this tests that data: URIs do not inherit the CSP from
 //    it's enclosing context.
 
 add_task(async function test() {
+  // allow top level data: URI navigations, otherwise clicking a data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
   let dataURIPref = Services.prefs.getBoolPref("security.data_uri.unique_opaque_origin");
   // create a tab that has a CSP
   let testURL = "http://mochi.test:8888/browser/browser/components/sessionstore/test/browser_911547_sample.html";
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, testURL);
   gBrowser.selectedTab = tab;
 
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
--- a/browser/components/sessionstore/test/browser_async_duplicate_tab.js
+++ b/browser/components/sessionstore/test/browser_async_duplicate_tab.js
@@ -1,11 +1,13 @@
 "use strict";
 
-const URL = "data:text/html;charset=utf-8,<a href=%23>clickme</a>";
+const PATH = getRootDirectory(gTestPath)
+             .replace("chrome://mochitests/content/", "http://example.com/");
+const URL = PATH + "file_async_duplicate_tab.html";
 
 add_task(async function test_duplicate() {
   // Create new tab.
   let tab = BrowserTestUtils.addTab(gBrowser, URL);
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
 
   // Flush to empty any queued update messages.
--- a/browser/components/sessionstore/test/browser_async_flushes.js
+++ b/browser/components/sessionstore/test/browser_async_flushes.js
@@ -1,11 +1,13 @@
 "use strict";
 
-const URL = "data:text/html;charset=utf-8,<a href=%23>clickme</a>";
+const PATH = getRootDirectory(gTestPath)
+             .replace("chrome://mochitests/content/", "http://example.com/");
+const URL = PATH + "file_async_flushes.html";
 
 add_task(async function test_flush() {
   // Create new tab.
   let tab = BrowserTestUtils.addTab(gBrowser, URL);
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
 
   // Flush to empty any queued update messages.
--- a/browser/components/sessionstore/test/browser_dynamic_frames.js
+++ b/browser/components/sessionstore/test/browser_dynamic_frames.js
@@ -3,16 +3,20 @@
 
 "use strict";
 
 /**
  * Ensure that static frames of framesets are serialized but dynamically
  * inserted iframes are ignored.
  */
 add_task(async function() {
+  // allow top level data: URI navigations, otherwise clicking a data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
   // This URL has the following frames:
   //  + data:text/html,A (static)
   //  + data:text/html,B (static)
   //  + data:text/html,C (dynamic iframe)
   const URL = "data:text/html;charset=utf-8," +
               "<frameset cols=50%25,50%25><frame src='data:text/html,A'>" +
               "<frame src='data:text/html,B'></frameset>" +
               "<script>var i=document.createElement('iframe');" +
@@ -41,16 +45,20 @@ add_task(async function() {
 });
 
 /**
  * Ensure that iframes created by the network parser are serialized but
  * dynamically inserted iframes are ignored. Navigating a subframe should
  * create a second root entry that doesn't contain any dynamic children either.
  */
 add_task(async function() {
+  // allow top level data: URI navigations, otherwise clicking a data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]]
+  });
   // This URL has the following frames:
   //  + data:text/html,A (static)
   //  + data:text/html,C (dynamic iframe)
   const URL = "data:text/html;charset=utf-8," +
               "<iframe name=t src='data:text/html,A'></iframe>" +
               "<a id=lnk href='data:text/html,B' target=t>clickme</a>" +
               "<script>var i=document.createElement('iframe');" +
               "i.setAttribute('src', 'data:text/html,C');" +
--- a/browser/components/sessionstore/test/browser_sessionHistory.js
+++ b/browser/components/sessionstore/test/browser_sessionHistory.js
@@ -32,18 +32,19 @@ add_task(async function test_load_start(
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that anchor navigation invalidates shistory.
  */
 add_task(async function test_hashchange() {
-  const URL = "data:text/html;charset=utf-8,<a id=a href=%23>clickme</a>";
-
+  const PATH = getRootDirectory(gTestPath)
+              .replace("chrome://mochitests/content/", "http://example.com/");
+  const URL = PATH + "file_sessionHistory_hashchange.html";
   // Create a new tab.
   let tab = BrowserTestUtils.addTab(gBrowser, URL);
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
 
   // Check that we start with a single shistory entry.
   await TabStateFlusher.flush(browser);
   let {entries} = JSON.parse(ss.getTabState(tab));
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/file_async_duplicate_tab.html
@@ -0,0 +1,1 @@
+<a href=#>clickme</a>
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/file_async_flushes.html
@@ -0,0 +1,1 @@
+<a href=#>clickme</a>
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/file_sessionHistory_hashchange.html
@@ -0,0 +1,1 @@
+<a id=a href=#>clickme</a>
--- a/browser/installer/windows/nsis/stub.nsi
+++ b/browser/installer/windows/nsis/stub.nsi
@@ -743,22 +743,22 @@ Function createInstall
   FindWindow $7 "#32770" "" $HWNDPARENT
   ${GetDlgItemWidthHeight} $HWNDPARENT $8 $9
 
   ; Resize the Dialog to fill the entire window
   System::Call 'user32::MoveWindow(i$Dialog,i0,i0,i $8,i $9,i0)'
 
   ; The header string may need more than half the width of the window, but it's
   ; currently not close to needing multiple lines in any localization.
-  ${NSD_CreateLabelCenter} 0% ${NOW_INSTALLING_TOP_DU} 100% 47u "$(STUB_INSTALLING_LABEL)"
+  ${NSD_CreateLabelCenter} 0% ${NOW_INSTALLING_TOP_DU} 100% 47u "$(STUB_INSTALLING_LABEL2)"
   Pop $0
   SendMessage $0 ${WM_SETFONT} $FontInstalling 0
   SetCtlColors $0 ${INSTALL_BLURB_TEXT_COLOR} transparent
 
-  ${NSD_CreateLabelCenter} 0% ${INSTALL_BLURB_TOP_DU} 100% 60u "$(STUB_BLURB1)"
+  ${NSD_CreateLabelCenter} 0% ${INSTALL_BLURB_TOP_DU} 100% 60u "$(STUB_BLURB_FIRST1)"
   Pop $LabelBlurb
   SendMessage $LabelBlurb ${WM_SETFONT} $FontBlurb 0
   SetCtlColors $LabelBlurb ${INSTALL_BLURB_TEXT_COLOR} transparent
 
   StrCpy $CurrentBlurbIdx "0"
 
   ${GetTextWidthHeight} "$(STUB_BLURB_FOOTER2)" $FontFooter \
     ${INSTALL_FOOTER_WIDTH_DU} $R1 $R2
@@ -891,21 +891,21 @@ FunctionEnd
 
 Function NextBlurb
   ${NSD_KillTimer} NextBlurb
 
   IntOp $CurrentBlurbIdx $CurrentBlurbIdx + 1
   IntOp $CurrentBlurbIdx $CurrentBlurbIdx % 3
 
   ${If} $CurrentBlurbIdx == "0"
-    StrCpy $0 "$(STUB_BLURB1)"
+    StrCpy $0 "$(STUB_BLURB_FIRST1)"
   ${ElseIf} $CurrentBlurbIdx == "1"
-    StrCpy $0 "$(STUB_BLURB2)"
+    StrCpy $0 "$(STUB_BLURB_SECOND1)"
   ${ElseIf} $CurrentBlurbIdx == "2"
-    StrCpy $0 "$(STUB_BLURB3)"
+    StrCpy $0 "$(STUB_BLURB_THIRD1)"
   ${EndIf}
 
   SendMessage $LabelBlurb ${WM_SETTEXT} 0 "STR:$0"
 
   ${NSD_CreateTimer} ClearBlurb ${BlurbDisplayMS}
 FunctionEnd
 
 Function ClearBlurb
--- a/browser/locales/en-US/installer/nsisstrings.properties
+++ b/browser/locales/en-US/installer/nsisstrings.properties
@@ -23,21 +23,17 @@ INSTALLER_WIN_CAPTION=$BrandShortName In
 # The \n in the next two strings can be moved or deleted as needed to make
 # the string fit in the 3 lines of space available.
 STUB_CLEANUP_PAVEOVER_HEADER=$BrandShortName is already installed.\nLet's update it.
 STUB_CLEANUP_REINSTALL_HEADER=$BrandShortName has been installed before.\nLet's get you a new copy.
 STUB_CLEANUP_PAVEOVER_BUTTON=&Update
 STUB_CLEANUP_REINSTALL_BUTTON=Re-&install
 STUB_CLEANUP_CHECKBOX_LABEL=&Restore default settings and remove old add-ons for optimal performance
 
-STUB_INSTALLING_LABEL=Now installing
 STUB_INSTALLING_LABEL2=Now installing…
-STUB_BLURB1=Fast, responsive online experiences
-STUB_BLURB2=Compatibility with more of your favorite sites
-STUB_BLURB3=Built-in privacy tools for safer browsing
 STUB_BLURB_FIRST1=The fastest, most responsive $BrandShortName yet
 STUB_BLURB_SECOND1=Faster page loading and tab switching
 STUB_BLURB_THIRD1=Powerful private browsing
 STUB_BLURB_FOOTER2=Built for people, not for profit
 
 WARN_MIN_SUPPORTED_OSVER_MSG=Sorry, $BrandShortName can't be installed. This version of $BrandShortName requires ${MinSupportedVer} or newer. Please click the OK button for additional information.
 WARN_MIN_SUPPORTED_CPU_MSG=Sorry, $BrandShortName can't be installed. This version of $BrandShortName requires a processor with ${MinSupportedCPU} support. Please click the OK button for additional information.
 WARN_MIN_SUPPORTED_OSVER_CPU_MSG=Sorry, $BrandShortName can't be installed. This version of $BrandShortName requires ${MinSupportedVer} or newer and a processor with ${MinSupportedCPU} support. Please click the OK button for additional information.
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -217,16 +217,21 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, 
                 'CRT.' % windows_sdk_dir_env)
 
     valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
     if not valid_sdks:
         raise FatalCheckError('Cannot find the Universal CRT SDK. '
                               'Please install it.')
 
     version, sdk = sdks[valid_sdks[0]]
+    minimum_ucrt_version = Version('10.0.10586.0')
+    if version < minimum_ucrt_version:
+        raise FatalCheckError('Latest Universal CRT SDK version found %s'
+                              ' and minimum required is %s.'
+                              % (version,  minimum_ucrt_version))
 
     return namespace(
         path=sdk.path,
         include=sdk.include,
         lib=sdk.lib,
         version=version,
     )
 
--- a/devtools/client/framework/options-panel.css
+++ b/devtools/client/framework/options-panel.css
@@ -113,11 +113,11 @@
 #screenshot-options legend::after {
   content: "";
   display: inline-block;
   background-image: url("chrome://devtools/skin/images/command-screenshot.svg");
   width: 16px;
   height: 16px;
   vertical-align: sub;
   margin-inline-start: 5px;
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
   opacity: 0.6;
 }
--- a/devtools/client/inspector/layout/components/Accordion.css
+++ b/devtools/client/inspector/layout/components/Accordion.css
@@ -34,17 +34,17 @@
   width: 100%;
   align-items: center;
   display: flex;
 
   -moz-user-select: none;
 }
 
 .accordion ._header:hover {
-  background-color: var(--theme-toolbar-background-hover);
+  background-color: var(--theme-toolbar-hover);
 }
 
 .accordion ._header:hover svg {
   fill: var(--theme-comment-alt);
 }
 
 .accordion ._content {
   border-bottom: 1px solid var(--theme-splitter-color);
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -1177,17 +1177,17 @@ body,
   padding-inline-end: 0;
   margin-top: 3px;
   margin-bottom: 3px;
   margin-inline-end: 1em;
 }
 
 .requests-list-network-summary-button > .summary-info-icon {
   background: url(chrome://devtools/skin/images/profiler-stopwatch.svg) no-repeat;
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
   width: 16px;
   height: 16px;
   opacity: 0.8;
 }
 
 .requests-list-network-summary-button:hover > .summary-info-icon {
   opacity: 1;
 }
--- a/devtools/client/responsive.html/index.css
+++ b/devtools/client/responsive.html/index.css
@@ -71,17 +71,17 @@ body,
 
 .toolbar-button:empty:hover:not(:disabled),
 .toolbar-button:empty:-moz-any(:hover:active, .checked):not(:disabled) {
   /* Reset background from .devtools-button */
   background: none;
 }
 
 .toolbar-button:active::before {
-  filter: var(--checked-icon-filter);
+  filter: var(--theme-icon-checked-filter);
 }
 
 select {
   -moz-appearance: none;
   background-color: var(--theme-toolbar-background);
   background-image: var(--viewport-selection-arrow);
   -moz-context-properties: fill;
   fill: currentColor;
@@ -161,17 +161,17 @@ select > option.divider {
   background-image: url("./images/screenshot.svg");
 }
 
 #global-exit-button::before {
   background-image: url("chrome://devtools/skin/images/close.svg");
 }
 
 #global-screenshot-button:disabled {
-  filter: var(--checked-icon-filter);
+  filter: var(--theme-icon-checked-filter);
   opacity: 1 !important;
 }
 
 #global-network-throttling-selector {
   height: 15px;
   padding-left: 0;
   width: 103px;
 }
--- a/devtools/client/shared/components/tabs/tabs.css
+++ b/devtools/client/shared/components/tabs/tabs.css
@@ -79,16 +79,21 @@
 
 .theme-dark .tabs .tabs-menu-item,
 .theme-light .tabs .tabs-menu-item {
   margin: 0;
   padding: 0;
   color: var(--theme-toolbar-color);
 }
 
+.theme-dark .tabs .tabs-menu-item.is-active,
+.theme-light .tabs .tabs-menu-item.is-active {
+  color: var(--theme-toolbar-selected-color);
+}
+
 .theme-dark .tabs .tabs-menu-item:last-child,
 .theme-light:not(.theme-firebug) .tabs .tabs-menu-item:last-child {
   border-inline-end-width: 1px;
 }
 
 .theme-dark .tabs .tabs-menu-item a,
 .theme-light .tabs .tabs-menu-item a {
   padding: 3px 15px;
--- a/devtools/client/shared/test/browser_theme.js
+++ b/devtools/client/shared/test/browser_theme.js
@@ -96,12 +96,12 @@ function testColorExistence() {
     "comment", "body-color", "body-color-alt", "content-color1", "content-color2",
     "content-color3", "highlight-green", "highlight-blue", "highlight-bluegrey",
     "highlight-purple", "highlight-lightorange", "highlight-orange", "highlight-red",
     "highlight-pink"
   ];
 
   for (let type of vars) {
     ok(getColor(type, "light"), `${type} is a valid color in light theme`);
-    ok(getColor(type, "dark"), `${type} is a valid color in light theme`);
-    ok(getColor(type, "firebug"), `${type} is a valid color in light theme`);
+    ok(getColor(type, "dark"), `${type} is a valid color in dark theme`);
+    ok(getColor(type, "firebug"), `${type} is a valid color in firebug theme`);
   }
 }
--- a/devtools/client/shared/widgets/filter-widget.css
+++ b/devtools/client/shared/widgets/filter-widget.css
@@ -226,14 +226,14 @@
 
 #toggle-presets {
   background: url(chrome://devtools/skin/images/pseudo-class.svg);
 }
 
 #filter-container .add,
 #filter-container .remove-button,
 #toggle-presets {
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
 }
 
 .show-presets #toggle-presets {
   filter: url(chrome://devtools/skin/images/filters.svg#checked-icon-state);
 }
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -546,17 +546,17 @@ Editor.prototype = {
 
   /**
    * Replaces whatever is in the text area with the contents of
    * the 'value' argument.
    */
   setText: function (value) {
     let cm = editors.get(this);
 
-    if (typeof value !== "string") {  // wasm?
+    if (typeof value !== "string" && "binary" in value) {  // wasm?
       // binary does not survive as Uint8Array, converting from string
       let binary = value.binary;
       let data = new Uint8Array(binary.length);
       for (let i = 0; i < data.length; i++) {
         data[i] = binary.charCodeAt(i);
       }
       let { lines, done } = getWasmText(this.getDoc(), data);
       const MAX_LINES = 10000000;
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -289,38 +289,33 @@ checkbox:-moz-focusring {
 }
 
 /* Icon button styles */
 .devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
   display: none;
 }
 
 /* Icon-only buttons */
-.devtools-button:empty::before,
-.devtools-toolbarbutton:not([label]):not([disabled]) > image {
-  opacity: 0.8;
-}
-
 .devtools-button:hover:empty:not(:disabled):before,
 .devtools-button.checked:empty::before,
 .devtools-toolbarbutton:not([label]):not([disabled=true]):hover > image,
 .devtools-toolbarbutton:not([label])[checked=true] > image,
 .devtools-toolbarbutton:not([label])[open=true] > image {
   opacity: 1;
 }
 
 .devtools-button:disabled,
 .devtools-toolbarbutton[disabled] {
   opacity: 0.5 !important;
 }
 
 .devtools-button.checked::before,
 .devtools-toolbarbutton:not([label])[checked=true] > image,
 .devtools-toolbarbutton:not([label])[open=true] > image {
-  filter: var(--checked-icon-filter);
+  filter: var(--theme-icon-checked-filter);
 }
 
 /* Button states */
 .devtools-toolbarbutton[label]:not([type=menu-button]),
 .devtools-toolbarbutton[standalone],
 .devtools-button[data-standalone],
 .devtools-button:not(:empty) {
   background: var(--toolbarbutton-background);
--- a/devtools/client/themes/images/filters.svg
+++ b/devtools/client/themes/images/filters.svg
@@ -1,25 +1,59 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <svg height="0" xmlns="http://www.w3.org/2000/svg">
-  <filter id="checked-icon-state">
+  <!-- DevTools icon filter: Grey 90 + 0.8 opacity (light theme normal) -->
+  <filter id="icon-normal-light">
     <feColorMatrix in="SourceGraphic" type="matrix"
-      values="0 0 0 0 0.043
-              0 0 0 0 0.415
-              0 0 0 0 0.79
+      values="0 0 0 0 0.01
+              0 0 0 0 0.01
+              0 0 0 0 0.01
+              0 0 0 0.8 0"/>
+  </filter>
+  <!-- DevTools icon filter: Photon Blue 60 (light theme selected) -->
+  <filter id="icon-selected-light">
+    <feColorMatrix in="SourceGraphic" type="matrix"
+      values="0 0 0 0 0
+              0 0 0 0 0.122
+              0 0 0 0 0.74
               0 0 0 1 0"/>
   </filter>
-  <filter id="dark-theme-checked-icon-state">
+  <!-- DevTools icon filter: Photon Blue 60 (light theme checked) -->
+  <filter id="icon-checked-light">
     <feColorMatrix in="SourceGraphic" type="matrix"
       values="0 0 0 0 0
+              0 0 0 0 0.122
+              0 0 0 0 0.74
+              0 0 0 1 0"/>
+  </filter>
+  <!-- DevTools icon filter: Grey 10 + 0.8 opacity (dark theme normal) -->
+  <filter id="icon-normal-dark">
+    <feColorMatrix in="SourceGraphic" type="matrix"
+      values="0 0 0 0 0.945
+              0 0 0 0 0.945
+              0 0 0 0 0.95
+              0 0 0 0.8 0"/>
+  </filter>
+  <!-- DevTools icon filter: white (dark theme selected) -->
+  <filter id="icon-selected-dark">
+    <feColorMatrix in="SourceGraphic" type="matrix"
+      values="0 0 0 0 1
               0 0 0 0 1
-              0 0 0 0 0.212
+              0 0 0 0 1
+              0 0 0 1 0"/>
+  </filter>
+  <!-- DevTools icon filter: syntax blue #75BFFF (dark theme checked) -->
+  <filter id="icon-checked-dark">
+    <feColorMatrix in="SourceGraphic" type="matrix"
+      values="0 0 0 0.18 0
+              0 0 0 0.52 0
+              0 0 0 1 0
               0 0 0 1 0"/>
   </filter>
 
   <!-- Web Audio Gradients -->
   <linearGradient id="bypass-light" x1="8%" y1="10%" x2="16%" y2="16%" spreadMethod="repeat">
     <stop offset="0%" stop-color="#dde1e4a0"/> <!-- theme-splitter-color (0.5 opacity) -->
     <stop offset="50%" stop-color="transparent"/>
   </linearGradient>
--- a/devtools/client/themes/shadereditor.css
+++ b/devtools/client/themes/shadereditor.css
@@ -52,17 +52,17 @@
 }
 
 .side-menu-widget-item-checkbox:not([checked]) .checkbox-check,
 .side-menu-widget-item-checkbox:not([checked]) + vbox {
   opacity: 0.3;
 }
 
 .side-menu-widget-item:not(.selected) .checkbox-check {
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
 }
 
 /* Make sure icon is white when the item is selected */
 .side-menu-widget-item.selected .checkbox-check {
   filter: invert(1);
 }
 
 /* Shader source editors */
--- a/devtools/client/themes/styleeditor.css
+++ b/devtools/client/themes/styleeditor.css
@@ -168,17 +168,17 @@ li.error > .stylesheet-info > .styleshee
   margin: 0 8px;
   background-image: url(images/item-toggle.svg);
   background-repeat: no-repeat;
   background-clip: content-box;
   background-position: center;
   background-size: 16px;
   width: 24px;
   height: 40px;
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
 }
 
 .disabled > .stylesheet-enabled {
   opacity: 0.3;
 }
 
 /* Invert the toggle icon in the active row for light theme */
 .theme-light .splitview-nav > li.splitview-active .stylesheet-enabled {
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -9,44 +9,35 @@
   --searchbox-border-color: #ffbf00;
   --searcbox-no-match-background-color: #ffe5e5;
   --searcbox-no-match-border-color: #e52e2e;
 
   --magnifying-glass-image: url(chrome://devtools/skin/images/search.svg);
   --filter-image: url(chrome://devtools/skin/images/filter.svg);
   --tool-options-image: url(chrome://devtools/skin/images/tool-options.svg);
 
-  --icon-filter: none;
-  --checked-icon-filter: url(chrome://devtools/skin/images/filters.svg#checked-icon-state);
-
   --separator-border-image: linear-gradient(transparent 4px, rgba(0,0,0,.1) 4px, rgba(0,0,0,.1) calc(100% - 4px), transparent calc(100% - 4px));
 }
 
 .theme-dark {
   --searchbox-background-color: #4d4222;
   --searchbox-border-color: #d99f2b;
   --searcbox-no-match-background-color: #402325;
   --searcbox-no-match-border-color: #cc3d3d;
 
   --magnifying-glass-image: url(chrome://devtools/skin/images/search.svg);
   --filter-image: url(chrome://devtools/skin/images/filter.svg);
   --tool-options-image: url(chrome://devtools/skin/images/tool-options.svg);
 
-  --icon-filter: invert(1);
-  --checked-icon-filter: url(chrome://devtools/skin/images/filters.svg#dark-theme-checked-icon-state);
-
-  --separator-border-image: linear-gradient(transparent 4px, rgba(100%,100%,100%,.2) 4px, rgba(100%,100%,100%,.2) calc(100% - 4px), transparent calc(100% - 4px))
+  --separator-border-image: linear-gradient(transparent 4px, rgba(100%,100%,100%,.2) 4px, rgba(100%,100%,100%,.2) calc(100% - 4px), transparent calc(100% - 4px));
 }
 
 .theme-firebug {
   --magnifying-glass-image: url(chrome://devtools/skin/images/search.svg);
   --tool-options-image: url(chrome://devtools/skin/images/firebug/tool-options.svg);
-
-  --icon-filter: none;
-  --checked-icon-filter: none;
 }
 
 
 /* Toolbars */
 .devtools-toolbar,
 .devtools-sidebar-tabs tabs {
   -moz-appearance: none;
   padding: 0;
@@ -196,17 +187,17 @@
 .devtools-toolbarbutton > image,
 .devtools-button::before,
 .scrollbutton-up > .toolbarbutton-icon,
 .scrollbutton-down > .toolbarbutton-icon,
 #black-boxed-message-button .button-icon,
 #canvas-debugging-empty-notice-button .button-icon,
 #toggle-breakpoints[checked] > image,
 .event-tooltip-debugger-icon {
-  filter: var(--icon-filter);
+  filter: var(--theme-icon-filter);
 }
 
 .hidden-labels-box:not(.visible) > label,
 .hidden-labels-box.visible ~ .hidden-labels-box > label:last-child {
   display: none;
 }
 
 .devtools-invisible-splitter {
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -139,52 +139,47 @@
 .theme-firebug .devtools-tab {
   -moz-box-flex: initial;
 }
 
 .devtools-tab {
   color: var(--theme-toolbar-color);
 }
 
-.theme-dark .devtools-tab:hover {
-  color: #ced3d9;
-}
-
 .devtools-tab:hover {
   background-color: var(--theme-toolbar-hover);
 }
 
-.theme-dark .devtools-tab:hover:active {
-  color: var(--theme-selection-color);
-}
-
 .devtools-tab:hover:active {
   background-color: var(--theme-toolbar-hover-active);
 }
 
 .devtools-tab:not(.selected).highlighted {
   background-color: var(--theme-toolbar-background-alt);
 }
 
+.devtools-tab.selected {
+  color: var(--theme-toolbar-selected-color);
+}
+
 /* Display execution pointer in the Debugger tab to indicate
    that the debugger is paused. */
 .theme-firebug #toolbox-tab-jsdebugger.devtools-tab:not(.selected).highlighted {
   background-color: rgba(89, 178, 234, .2);
   background-image: url(chrome://devtools/skin/images/firebug/tool-debugger-paused.svg);
   background-repeat: no-repeat;
   padding-left: 13px !important;
   background-position: 3px 6px;
 }
 
 .devtools-tab > img {
   border: none;
   margin: 0;
   margin-inline-start: 10px;
   margin-inline-end: 5px;
-  opacity: 0.8;
   max-height: 16px;
   width: 16px; /* Prevents collapse during theme switching */
   vertical-align: text-top;
   flex-shrink: 0;
 }
 
 /* Don't apply any filter to non-invertable command button icons */
 .command-button:not(.command-button-invertable),
@@ -195,20 +190,19 @@
   filter: none;
 }
 
 .devtools-tab > label {
   white-space: nowrap;
   margin: 0 4px;
 }
 
-.devtools-tab:hover > img,
-.devtools-tab:active > img,
-.devtools-tab.selected > img {
-  opacity: 1;
+/* Apply selected icon filter to `invertable` icons */
+.devtools-tab.selected.icon-invertable > img {
+  filter: var(--theme-icon-selected-filter) !important;
 }
 
 .devtools-tab:not(.highlighted) > .highlighted-icon,
 .devtools-tab.selected > .highlighted-icon,
 .devtools-tab:not(.selected).highlighted > .default-icon {
   display: none;
 }
 
--- a/devtools/client/themes/variables.css
+++ b/devtools/client/themes/variables.css
@@ -20,20 +20,21 @@
   --theme-body-background: white;
   --theme-sidebar-background: white;
   --theme-contrast-background: #e6b064;
 
   /* Toolbar */
   --theme-tab-toolbar-background: var(--grey-10);
   --theme-toolbar-background: var(--grey-10);
   --theme-toolbar-color: var(--grey-90);
+  --theme-toolbar-selected-color: var(--blue-60);
   --theme-toolbar-background-hover: rgba(221, 225, 228, 0.66);
   --theme-toolbar-background-alt: #f5f5f5;
-  --theme-toolbar-hover: rgba(170, 170, 170, .2);
-  --theme-toolbar-hover-active: rgba(170, 170, 170, .4);
+  --theme-toolbar-hover: var(--grey-20);
+  --theme-toolbar-hover-active: var(--grey-20);
 
   /* Selection */
   --theme-selection-background: var(--blue-55);
   --theme-selection-background-hover: #F0F9FE;
   --theme-selection-color: #f5f7fa;
 
   /* Border color that splits the toolbars/panels/headers.
    * This needs to be sync with commandline.css and commandline-browser.css. */
@@ -75,16 +76,21 @@
   --theme-graphs-grey: #cccccc;
   --theme-graphs-full-red: #f00;
   --theme-graphs-full-blue: #00f;
 
   /* Images */
   --theme-pane-collapse-image: url(chrome://devtools/skin/images/pane-collapse.svg);
   --theme-pane-expand-image: url(chrome://devtools/skin/images/pane-expand.svg);
 
+  /* Icon filters */
+  --theme-icon-filter: url(chrome://devtools/skin/images/filters.svg#icon-normal-light);
+  --theme-icon-selected-filter: url(chrome://devtools/skin/images/filters.svg#icon-selected-light);
+  --theme-icon-checked-filter: url(chrome://devtools/skin/images/filters.svg#icon-checked-light);
+
   /* Tooltips */
   --theme-tooltip-border: #d9e1e8;
   --theme-tooltip-background: rgba(255, 255, 255, .9);
   --theme-tooltip-shadow: rgba(155, 155, 155, 0.26);
 
   /* Command line */
   --theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme);
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme-focus);
@@ -96,20 +102,21 @@
   --theme-body-background: var(--grey-80);
   --theme-sidebar-background: var(--grey-90);
   --theme-contrast-background: #ffb35b;
 
   /* Toolbar */
   --theme-tab-toolbar-background: var(--grey-90);
   --theme-toolbar-background: var(--grey-90);
   --theme-toolbar-color: var(--grey-40);
+  --theme-toolbar-selected-color: white;
   --theme-toolbar-background-hover: #20232B;
   --theme-toolbar-background-alt: #2F343E;
-  --theme-toolbar-hover: rgba(110, 120, 130, 0.1);
-  --theme-toolbar-hover-active: rgba(110, 120, 130, 0.2);
+  --theme-toolbar-hover: #252526;
+  --theme-toolbar-hover-active: #252526;
 
   /* Selection */
   --theme-selection-background: #204E8A;
   --theme-selection-background-hover: #353B48;
   --theme-selection-color: #f5f7fa;
 
   /* Border color that splits the toolbars/panels/headers.
    * This needs to be sync with commandline.css and commandline-browser.css. */
@@ -151,16 +158,21 @@
   --theme-graphs-grey: #757873;
   --theme-graphs-full-red: #f00;
   --theme-graphs-full-blue: #00f;
 
   /* Images */
   --theme-pane-collapse-image: url(chrome://devtools/skin/images/pane-collapse.svg);
   --theme-pane-expand-image: url(chrome://devtools/skin/images/pane-expand.svg);
 
+  /* Icon filters */
+  --theme-icon-filter: url(chrome://devtools/skin/images/filters.svg#icon-normal-dark);
+  --theme-icon-selected-filter: url(chrome://devtools/skin/images/filters.svg#icon-selected-dark);
+  --theme-icon-checked-filter: url(chrome://devtools/skin/images/filters.svg#icon-checked-dark);
+
   /* Tooltips */
   --theme-tooltip-border: #434850;
   --theme-tooltip-background: rgba(19, 28, 38, .9);
   --theme-tooltip-shadow: rgba(25, 25, 25, 0.76);
 
   /* Command line */
   --theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme);
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme-focus);
@@ -209,16 +221,21 @@
   --theme-graphs-grey: #cccccc;
   --theme-graphs-full-red: #f00;
   --theme-graphs-full-blue: #00f;
 
   /* Images */
   --theme-pane-collapse-image: url(chrome://devtools/skin/images/firebug/pane-collapse.svg);
   --theme-pane-expand-image: url(chrome://devtools/skin/images/firebug/pane-expand.svg);
 
+  /* Icon filters */
+  --theme-icon-filter: none;
+  --theme-icon-selected-filter: none;
+  --theme-icon-checked-filter: none;
+
   /* Font size */
   --theme-toolbar-font-size: 12px;
 
   /* Header */
   --theme-header-background: #F0F0F0 linear-gradient(to top,
                                                      rgba(0, 0, 0, 0.1),
                                                      transparent) repeat-x;
 
@@ -248,17 +265,17 @@
   --theme-focus-border-color-textbox: #0675d3;
   --theme-textbox-box-shadow: rgba(97,181,255,.75);
 
   /* For accessibility purposes we want to enhance the focus styling. This
    * should improve keyboard navigation usability. */
   --theme-focus-outline: 1px dotted var(--theme-focus-outline-color);
   --theme-focus-box-shadow-textbox: 0 0 0 1px var(--theme-textbox-box-shadow);
 
-  --toolbarbutton-background: rgba(110,120,130,0.1);
+  --toolbarbutton-background: var(--theme-toolbar-hover);
   --toolbarbutton-border-color: transparent;
   --toolbarbutton-hover-background: rgba(110,120,130,0.2);
   --toolbarbutton-hover-border-color: var(--toolbarbutton-border-color);
   --toolbarbutton-checked-background: var(--theme-selection-background);
   --toolbarbutton-checked-color: var(--theme-selection-color);
   --toolbarbutton-checked-border-color: var(--toolbarbutton-border-color);
 
   /* The photon animation curve */
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -138,60 +138,86 @@ PostMessageEvent::Run()
         nsContentUtils::eDOM_PROPERTIES,
         "TargetPrincipalDoesNotMatch",
         params, ArrayLength(params));
 
       return NS_OK;
     }
   }
 
-  ErrorResult rv;
+  IgnoredErrorResult rv;
   JS::Rooted<JS::Value> messageData(cx);
-  nsCOMPtr<nsPIDOMWindowInner> window = targetWindow->AsInner();
+  nsCOMPtr<mozilla::dom::EventTarget> eventTarget = do_QueryObject(targetWindow);
 
-  Read(window, cx, &messageData, rv);
+  Read(targetWindow->AsInner(), cx, &messageData, rv);
   if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
+    DispatchError(cx, targetWindow, eventTarget);
+    return NS_OK;
   }
 
   // Create the event
-  nsCOMPtr<mozilla::dom::EventTarget> eventTarget = do_QueryObject(targetWindow);
-  RefPtr<MessageEvent> event =
-    new MessageEvent(eventTarget, nullptr, nullptr);
+  RefPtr<MessageEvent> event = new MessageEvent(eventTarget, nullptr, nullptr);
 
 
   Nullable<WindowProxyOrMessagePortOrServiceWorker> source;
   source.SetValue().SetAsWindowProxy() = mSource ? mSource->AsOuter() : nullptr;
 
   Sequence<OwningNonNull<MessagePort>> ports;
   if (!TakeTransferredPortsAsSequence(ports)) {
-    return NS_ERROR_OUT_OF_MEMORY;
+    DispatchError(cx, targetWindow, eventTarget);
+    return NS_OK;
   }
 
   event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
                           false /*non-bubbling */, false /*cancelable */,
                           messageData, mCallerOrigin,
                           EmptyString(), source, ports);
 
+  Dispatch(targetWindow, event);
+  return NS_OK;
+}
+
+void
+PostMessageEvent::DispatchError(JSContext* aCx, nsGlobalWindow* aTargetWindow,
+                                mozilla::dom::EventTarget* aEventTarget)
+{
+  RootedDictionary<MessageEventInit> init(aCx);
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mOrigin = mCallerOrigin;
+
+  if (mSource) {
+    init.mSource.SetValue().SetAsWindowProxy() = mSource->AsOuter();
+  }
+
+  RefPtr<Event> event =
+    MessageEvent::Constructor(aEventTarget, NS_LITERAL_STRING("messageerror"),
+                              init);
+  Dispatch(aTargetWindow, event);
+}
+
+void
+PostMessageEvent::Dispatch(nsGlobalWindow* aTargetWindow, Event* aEvent)
+{
   // We can't simply call dispatchEvent on the window because doing so ends
   // up flipping the trusted bit on the event, and we don't want that to
   // happen because then untrusted content can call postMessage on a chrome
   // window if it can get a reference to it.
 
-  nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
+  nsIPresShell *shell = aTargetWindow->GetExtantDoc()->GetShell();
   RefPtr<nsPresContext> presContext;
-  if (shell)
+  if (shell) {
     presContext = shell->GetPresContext();
+  }
 
-  event->SetTrusted(mTrustedCaller);
-  WidgetEvent* internalEvent = event->WidgetEventPtr();
+  aEvent->SetTrusted(mTrustedCaller);
+  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
 
   nsEventStatus status = nsEventStatus_eIgnore;
-  EventDispatcher::Dispatch(window,
+  EventDispatcher::Dispatch(aTargetWindow->AsInner(),
                             presContext,
                             internalEvent,
-                            static_cast<dom::Event*>(event.get()),
+                            aEvent,
                             &status);
-  return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -35,16 +35,23 @@ public:
                    nsGlobalWindow* aTargetWindow,
                    nsIPrincipal* aProvidedPrincipal,
                    nsIDocument* aSourceDocument,
                    bool aTrustedCaller);
 
 private:
   ~PostMessageEvent();
 
+  void
+  Dispatch(nsGlobalWindow* aTargetWindow, Event* aEvent);
+
+  void
+  DispatchError(JSContext* aCx, nsGlobalWindow* aTargetWindow,
+                mozilla::dom::EventTarget* aEventTarget);
+
   RefPtr<nsGlobalWindow> mSource;
   nsString mCallerOrigin;
   RefPtr<nsGlobalWindow> mTargetWindow;
   nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
   nsCOMPtr<nsIDocument> mSourceDocument;
   bool mTrustedCaller;
 };
 
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -840,18 +840,26 @@ nsCopySupport::FireClipboardEvent(EventM
     doDefault = (status != nsEventStatus_eConsumeNoDefault);
   }
 
   // When this function exits, the event dispatch is over. We want to disconnect
   // our DataTransfer, which means setting its mode to `Protected` and clearing
   // all stored data, before we return.
   auto clearAfter = MakeScopeExit([&] {
     if (clipboardData) {
-      clipboardData->SetMode(DataTransfer::Mode::Protected);
-      clipboardData->ClearAll();
+      clipboardData->Disconnect();
+
+      // NOTE: Disconnect may not actually clear the DataTransfer if the
+      // dom.events.dataTransfer.protected.enabled pref is not on, so we make
+      // sure we clear here, as not clearing could provide the DataTransfer
+      // access to information from the system clipboard at an arbitrary point
+      // in the future.
+      if (originalEventMessage == ePaste) {
+        clipboardData->ClearAll();
+      }
     }
   });
 
   // No need to do anything special during a paste. Either an event listener
   // took care of it and cancelled the event, or the caller will handle it.
   // Return true to indicate that the event wasn't cancelled.
   if (originalEventMessage == ePaste) {
     if (aActionTaken) {
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -915,16 +915,17 @@ GK_ATOM(onlevelchange, "onlevelchange")
 GK_ATOM(onLoad, "onLoad")
 GK_ATOM(onload, "onload")
 GK_ATOM(onloading, "onloading")
 GK_ATOM(onloadingdone, "onloadingdone")
 GK_ATOM(onloadingerror, "onloadingerror")
 GK_ATOM(onpopstate, "onpopstate")
 GK_ATOM(only, "only")               // this one is not an event
 GK_ATOM(onmessage, "onmessage")
+GK_ATOM(onmessageerror, "onmessageerror")
 GK_ATOM(onmousedown, "onmousedown")
 GK_ATOM(onmouseenter, "onmouseenter")
 GK_ATOM(onmouseleave, "onmouseleave")
 GK_ATOM(onmouselongtap, "onmouselongtap")
 GK_ATOM(onmousemove, "onmousemove")
 GK_ATOM(onmouseout, "onmouseout")
 GK_ATOM(onmouseover, "onmouseover")
 GK_ATOM(onMozMouseHittest, "onMozMouseHittest")
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2820,17 +2820,17 @@ ToSupportsIsOnPrimaryInheritanceChain(T*
 }
 
 // Get the size of allocated memory to associate with a binding JSObject for a
 // native object. This is supplied to the JS engine to allow it to schedule GC
 // when necessary.
 //
 // This function supplies a default value and is overloaded for specific native
 // object types.
-inline uint64_t
+inline size_t
 BindingJSObjectMallocBytes(void *aNativePtr)
 {
   return 0;
 }
 
 // The BindingJSObjectCreator class is supposed to be used by a caller that
 // wants to create and initialise a binding JSObject. After initialisation has
 // been successfully completed it should call ForgetObject().
@@ -2869,34 +2869,34 @@ public:
     aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
                                       options));
     if (aReflector) {
       js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
       mNative = aNative;
       mReflector = aReflector;
     }
 
-    if (uint64_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
+    if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
       JS_updateMallocCounter(aCx, mallocBytes);
     }
   }
 
   void
   CreateObject(JSContext* aCx, const JSClass* aClass,
                JS::Handle<JSObject*> aProto,
                T* aNative, JS::MutableHandle<JSObject*> aReflector)
   {
     aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
     if (aReflector) {
       js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
       mNative = aNative;
       mReflector = aReflector;
     }
 
-    if (uint64_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
+    if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
       JS_updateMallocCounter(aCx, mallocBytes);
     }
   }
 
   void
   InitializationSucceeded()
   {
     void* dummy;
--- a/dom/broadcastchannel/BroadcastChannel.h
+++ b/dom/broadcastchannel/BroadcastChannel.h
@@ -63,16 +63,17 @@ public:
   }
 
   void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                    ErrorResult& aRv);
 
   void Close();
 
   IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(messageerror)
 
   void Shutdown();
 
 private:
   BroadcastChannel(nsPIDOMWindowInner* aWindow,
                    const PrincipalInfo& aPrincipalInfo,
                    const nsACString& aOrigin,
                    const nsAString& aChannel);
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -75,20 +75,20 @@ BroadcastChannelChild::RecvNotify(const 
   if (!globalObject || !jsapi.Init(globalObject)) {
     NS_WARNING("Failed to initialize AutoJSAPI object.");
     return IPC_OK();
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (cloneData.DataLength()) {
-    ErrorResult rv;
+    IgnoredErrorResult rv;
     cloneData.Read(cx, &value, rv);
     if (NS_WARN_IF(rv.Failed())) {
-      rv.SuppressException();
+      DispatchError(cx);
       return IPC_OK();
     }
   }
 
   RootedDictionary<MessageEventInit> init(cx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mOrigin = mOrigin;
@@ -106,10 +106,26 @@ BroadcastChannelChild::RecvNotify(const 
 }
 
 void
 BroadcastChannelChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mActorDestroyed = true;
 }
 
+void
+BroadcastChannelChild::DispatchError(JSContext* aCx)
+{
+  RootedDictionary<MessageEventInit> init(aCx);
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mOrigin = mOrigin;
+
+  RefPtr<Event> event =
+    MessageEvent::Constructor(mBC, NS_LITERAL_STRING("messageerror"), init);
+  event->SetTrusted(true);
+
+  bool dummy;
+  mBC->DispatchEvent(event, &dummy);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/broadcastchannel/BroadcastChannelChild.h
+++ b/dom/broadcastchannel/BroadcastChannelChild.h
@@ -39,16 +39,18 @@ public:
   }
 
 private:
   explicit BroadcastChannelChild(const nsACString& aOrigin);
   ~BroadcastChannelChild();
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
+  void DispatchError(JSContext* aCx);
+
   // This raw pointer is actually the parent object.
   // It's set to null when the parent object is deleted.
   BroadcastChannel* mBC;
 
   nsString mOrigin;
 
   bool mActorDestroyed;
 };
--- a/dom/browser-element/mochitest/browserElement_Iconchange.js
+++ b/dom/browser-element/mochitest/browserElement_Iconchange.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that the onmozbrowsericonchange event works.
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
+browserElementTestHelpers.allowTopLevelDataURINavigation();
 
 function createHtml(link) {
   return 'data:text/html,<html><head>' + link + '<body></body></html>';
 }
 
 function createLink(name, sizes, rel) {
   var s = sizes ? 'sizes="' + sizes + '"' : '';
   if (!rel) {
--- a/dom/browser-element/mochitest/browserElement_Manifestchange.js
+++ b/dom/browser-element/mochitest/browserElement_Manifestchange.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that the onmozbrowsermanifestchange event works.
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
+browserElementTestHelpers.allowTopLevelDataURINavigation();
 
 function createHtml(manifest) {
   return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace"><head>' + manifest + '<body></body></html>';
 }
 
 function createManifest(href) {
   return '<link rel="manifest" href="' + href + '">';
 }
--- a/dom/browser-element/mochitest/browserElement_Metachange.js
+++ b/dom/browser-element/mochitest/browserElement_Metachange.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that the onmozbrowsermetachange event works.
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
+browserElementTestHelpers.allowTopLevelDataURINavigation();
 
 function createHtml(meta) {
   return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace"><head>' + meta + '<body></body></html>';
 }
 
 function createHtmlWithLang(meta, lang) {
   return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace" lang="' + lang + '"><head>' + meta + '<body></body></html>';
 }
--- a/dom/browser-element/mochitest/browserElement_Opensearch.js
+++ b/dom/browser-element/mochitest/browserElement_Opensearch.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that the onmozbrowseropensearch event works.
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
+browserElementTestHelpers.allowTopLevelDataURINavigation();
 
 function createHtml(link) {
   return 'data:text/html,<html><head>' + link + '<body></body></html>';
 }
 
 function createLink(name) {
   return '<link rel="search" title="Test OpenSearch" type="application/opensearchdescription+xml" href="http://example.com/' + name + '.xml">';
 }
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1784,22 +1784,16 @@ CanvasRenderingContext2D::RegisterAlloca
   // PeristentBufferProvider, rather than here.
   static bool registered = false;
   // FIXME: Disable the reporter for now, see bug 1241865
   if (!registered && false) {
     registered = true;
     RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
   }
 
-  gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
-  JSContext* context = nsContentUtils::GetCurrentJSContext();
-  if (context) {
-    JS_updateMallocCounter(context, mWidth * mHeight * 4);
-  }
-
   JSObject* wrapper = GetWrapperPreserveColor();
   if (wrapper) {
     CycleCollectedJSRuntime::Get()->
       AddZoneWaitingForGC(JS::GetObjectZone(wrapper));
   }
 }
 
 static already_AddRefed<LayerManager>
@@ -6549,10 +6543,16 @@ CanvasPath::EnsurePathBuilder() const
   }
 
   // if there is not pathbuilder, there must be a path
   MOZ_ASSERT(mPath);
   mPathBuilder = mPath->CopyToBuilder();
   mPath = nullptr;
 }
 
+size_t
+BindingJSObjectMallocBytes(CanvasRenderingContext2D* aContext)
+{
+  return aContext->GetWidth() * aContext->GetHeight() * 4;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -1164,12 +1164,14 @@ protected:
     if (aPerCSSPixel)
       *aPerCSSPixel = cssPixel;
   }
 
   friend struct CanvasBidiProcessor;
   friend class CanvasDrawObserver;
 };
 
+size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D* aContext);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* CanvasRenderingContext2D_h */
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -30,55 +30,16 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Im
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmap)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmap)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmap)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /*
- * This helper function is used to notify DOM that aBytes memory is allocated
- * here so that we could trigger GC appropriately.
- */
-static void
-RegisterAllocation(nsIGlobalObject* aGlobal, size_t aBytes)
-{
-  AutoJSAPI jsapi;
-  if (jsapi.Init(aGlobal)) {
-    JS_updateMallocCounter(jsapi.cx(), aBytes);
-  }
-}
-
-static void
-RegisterAllocation(nsIGlobalObject* aGlobal, SourceSurface* aSurface)
-{
-  // Calculate how many bytes are used.
-  const int bytesPerPixel = BytesPerPixel(aSurface->GetFormat());
-  const size_t bytes =
-    aSurface->GetSize().height * aSurface->GetSize().width * bytesPerPixel;
-
-  // Register.
-  RegisterAllocation(aGlobal, bytes);
-}
-
-static void
-RegisterAllocation(nsIGlobalObject* aGlobal, layers::Image* aImage)
-{
-  // Calculate how many bytes are used.
-  if (aImage->GetFormat() == mozilla::ImageFormat::PLANAR_YCBCR) {
-    RegisterAllocation(aGlobal, aImage->AsPlanarYCbCrImage()->GetDataSize());
-  } else if (aImage->GetFormat() == mozilla::ImageFormat::NV_IMAGE) {
-    RegisterAllocation(aGlobal, aImage->AsNVImage()->GetBufferSize());
-  } else {
-    RefPtr<SourceSurface> surface = aImage->GetAsSourceSurface();
-    RegisterAllocation(aGlobal, surface);
-  }
-}
-
-/*
  * If either aRect.width or aRect.height are negative, then return a new IntRect
  * which represents the same rectangle as the aRect does but with positive width
  * and height.
  */
 static IntRect
 FixUpNegativeDimension(const IntRect& aRect, ErrorResult& aRv)
 {
   gfx::IntRect rect = aRect;
@@ -439,16 +400,17 @@ ImageBitmap::ImageBitmap(nsIGlobalObject
                          gfxAlphaType aAlphaType)
   : mParent(aGlobal)
   , mData(aData)
   , mSurface(nullptr)
   , mDataWrapper(new ImageUtils(mData))
   , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
   , mAlphaType(aAlphaType)
   , mIsCroppingAreaOutSideOfSourceImage(false)
+  , mAllocatedImageData(false)
 {
   MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
 }
 
 ImageBitmap::~ImageBitmap()
 {
 }
 
@@ -706,18 +668,17 @@ ImageBitmap::ToCloneData() const
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
                                  ImageBitmapCloneData* aData)
 {
   RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
 
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mAlphaType);
 
-  // Report memory allocation.
-  RegisterAllocation(aGlobal, aData->mSurface);
+  ret->mAllocatedImageData = true;
 
   ret->mIsCroppingAreaOutSideOfSourceImage =
     aData->mIsCroppingAreaOutSideOfSourceImage;
 
   ErrorResult rv;
   ret->SetPictureRect(aData->mPictureRect, rv);
   return ret.forget();
 }
@@ -744,18 +705,17 @@ ImageBitmap::CreateFromOffscreenCanvas(n
     return nullptr;
   }
 
   RefPtr<layers::Image> data =
     CreateImageFromSurface(surface);
 
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
 
-  // Report memory allocation.
-  RegisterAllocation(aGlobal, surface);
+  ret->mAllocatedImageData = true;
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
@@ -891,19 +851,18 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
 
-  // Report memory allocation if needed.
   if (needToReportMemoryAllocation) {
-    RegisterAllocation(aGlobal, croppedSurface);
+    ret->mAllocatedImageData = true;
   }
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(cropRect, aRv);
   }
 
   // Set mIsCroppingAreaOutSideOfSourceImage.
@@ -960,18 +919,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
   // Create an ImageBimtap.
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, alphaType);
 
-  // Report memory allocation.
-  RegisterAllocation(aGlobal, data);
+  ret->mAllocatedImageData = true;
 
   // The cropping information has been handled in the CreateImageFromRawData()
   // function.
 
   // Set mIsCroppingAreaOutSideOfSourceImage.
   ret->SetIsCroppingAreaOutSideOfSourceImage(imageSize, aCropRect);
 
   return ret.forget();
@@ -1004,18 +962,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
 
-  // Report memory allocation.
-  RegisterAllocation(aGlobal, surface);
+  ret->mAllocatedImageData = true;
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   // Set mIsCroppingAreaOutSideOfSourceImage.
   ret->SetIsCroppingAreaOutSideOfSourceImage(surface->GetSize(), aCropRect);
@@ -1249,18 +1206,17 @@ protected:
       imageBitmap->SetPictureRect(mCropRect.ref(), rv);
 
       if (rv.Failed()) {
         mPromise->MaybeReject(rv);
         return false;
       }
     }
 
-    // Report memory allocation.
-    RegisterAllocation(mGlobalObject, imageBitmap->mData);
+    imageBitmap->mAllocatedImageData = true;
 
     mPromise->MaybeResolve(imageBitmap);
     return true;
   }
 
   // Will return null on failure.  In that case, mPromise will already
   // be rejected with the right thing.
   virtual already_AddRefed<ImageBitmap> CreateImageBitmap() = 0;
@@ -1539,18 +1495,17 @@ ImageBitmap::ReadStructuredClone(JSConte
       error.SuppressException();
       return nullptr;
     }
 
     if (!GetOrCreateDOMReflector(aCx, imageBitmap, &value)) {
       return nullptr;
     }
 
-    // Report memory allocation.
-    RegisterAllocation(aParent, aClonedSurfaces[aIndex]);
+    imageBitmap->mAllocatedImageData = true;
   }
 
   return &(value.toObject());
 }
 
 /*static*/ bool
 ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
                                   nsTArray<RefPtr<DataSourceSurface>>& aClonedSurfaces,
@@ -2139,26 +2094,52 @@ ImageBitmap::Create(nsIGlobalObject* aGl
     return promise.forget();
   }
 
   // Create an ImageBimtap.
   // Assume the data from an external buffer is not alpha-premultiplied.
   RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aGlobal, data,
                                                     gfxAlphaType::NonPremult);
 
-  // Report memory allocation.
-  RegisterAllocation(aGlobal, data);
+  imageBitmap->mAllocatedImageData = true;
 
   // We don't need to call SetPictureRect() here because there is no cropping
   // supported and the ImageBitmap's mPictureRect is the size of the source
   // image in default
 
   // We don't need to set mIsCroppingAreaOutSideOfSourceImage here because there
   // is no cropping supported and the mIsCroppingAreaOutSideOfSourceImage is
   // false in default.
 
   AsyncFulfillImageBitmapPromise(promise, imageBitmap);
 
   return promise.forget();
 }
 
+size_t
+ImageBitmap::GetAllocatedSize() const
+{
+  if (!mAllocatedImageData) {
+    return 0;
+  }
+
+  // Calculate how many bytes are used.
+  if (mData->GetFormat() == mozilla::ImageFormat::PLANAR_YCBCR) {
+    return mData->AsPlanarYCbCrImage()->GetDataSize();
+  }
+
+  if (mData->GetFormat() == mozilla::ImageFormat::NV_IMAGE) {
+    return mData->AsNVImage()->GetBufferSize();
+  }
+
+  RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
+  const int bytesPerPixel = BytesPerPixel(surface->GetFormat());
+  return surface->GetSize().height * surface->GetSize().width * bytesPerPixel;
+}
+
+size_t
+BindingJSObjectMallocBytes(ImageBitmap* aBitmap)
+{
+  return aBitmap->GetAllocatedSize();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/canvas/ImageBitmap.h
+++ b/dom/canvas/ImageBitmap.h
@@ -174,16 +174,18 @@ public:
   MappedDataLength(ImageBitmapFormat aFormat, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   MapDataInto(JSContext* aCx,
               ImageBitmapFormat aFormat,
               const ArrayBufferViewOrArrayBuffer& aBuffer,
               int32_t aOffset, ErrorResult& aRv);
 
+  size_t GetAllocatedSize() const;
+
 protected:
 
   /*
    * The default value of aIsPremultipliedAlpha is TRUE because that the
    * data stored in HTMLImageElement, HTMLVideoElement, HTMLCanvasElement,
    * CanvasRenderingContext2D are alpha-premultiplied in default.
    *
    * Actually, if one HTMLCanvasElement's rendering context is WebGLContext, it
@@ -279,16 +281,20 @@ protected:
    * Set mIsCroppingAreaOutSideOfSourceImage if image bitmap was cropped to the
    * source rectangle so that it contains any transparent black pixels (cropping
    * area is outside of the source image).
    * This is used in mapDataInto() to check if we should reject promise with
    * IndexSizeError.
    */
   bool mIsCroppingAreaOutSideOfSourceImage;
 
+  /*
+   * Whether this object allocated allocated and owns the image data.
+   */
+  bool mAllocatedImageData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ImageBitmap_h
 
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -76,16 +76,33 @@ const char DataTransfer::sEffects[8][9] 
 };
 
 // Used for custom clipboard types.
 enum CustomClipboardTypeId {
   eCustomClipboardTypeId_None,
   eCustomClipboardTypeId_String
 };
 
+// The dom.events.dataTransfer.protected.enabled preference controls whether or
+// not the `protected` dataTransfer state is enabled. If the `protected`
+// dataTransfer stae is disabled, then the DataTransfer will be read-only
+// whenever it should be protected, and will not be disconnected after a drag
+// event is completed.
+static bool
+PrefProtected()
+{
+  static bool sInitialized = false;
+  static bool sValue = false;
+  if (!sInitialized) {
+    sInitialized = true;
+    Preferences::AddBoolVarCache(&sValue, "dom.events.dataTransfer.protected.enabled");
+  }
+  return sValue;
+}
+
 static DataTransfer::Mode
 ModeForEvent(EventMessage aEventMessage)
 {
   switch (aEventMessage) {
   case eCut:
   case eCopy:
   case eDragStart:
     // For these events, we want to be able to add data to the data transfer,
@@ -93,17 +110,19 @@ ModeForEvent(EventMessage aEventMessage)
     return DataTransfer::Mode::ReadWrite;
   case eDrop:
   case ePaste:
   case ePasteNoFormatting:
     // For these events we want to be able to read the data which is stored in
     // the DataTransfer, rather than just the type information.
     return DataTransfer::Mode::ReadOnly;
   default:
-    return DataTransfer::Mode::Protected;
+    return PrefProtected()
+      ? DataTransfer::Mode::Protected
+      : DataTransfer::Mode::ReadOnly;
   }
 }
 
 DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
                            bool aIsExternal, int32_t aClipboardType)
   : mParent(aParent)
   , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE)
   , mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
@@ -1272,16 +1291,25 @@ DataTransfer::ConvertFromVariant(nsIVari
 
   // each character is two bytes
   *aLength = str.Length() << 1;
 
   return true;
 }
 
 void
+DataTransfer::Disconnect()
+{
+  SetMode(Mode::Protected);
+  if (PrefProtected()) {
+    ClearAll();
+  }
+}
+
+void
 DataTransfer::ClearAll()
 {
   mItems->ClearAllItems();
 }
 
 uint32_t
 DataTransfer::MozItemCount() const
 {
@@ -1603,10 +1631,20 @@ DataTransfer::FillInExternalCustomTypes(
       rv = variant->SetAsAString(data);
       NS_ENSURE_SUCCESS_VOID(rv);
 
       SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
     }
   } while (type != eCustomClipboardTypeId_None);
 }
 
+void
+DataTransfer::SetMode(DataTransfer::Mode aMode)
+{
+  if (!PrefProtected() && aMode == Mode::Protected) {
+    mMode = Mode::ReadOnly;
+  } else {
+    mMode = aMode;
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -224,19 +224,17 @@ public:
   }
 
   // Returns the current "Drag Data Store Mode" of the DataTransfer. This
   // determines what modifications may be performed on the DataTransfer, and
   // what data may be read from it.
   Mode GetMode() const {
     return mMode;
   }
-  void SetMode(Mode aMode) {
-    mMode = aMode;
-  }
+  void SetMode(Mode aMode);
 
   // Helper method. Is true if the DataTransfer's mode is ReadOnly or Protected,
   // which means that the DataTransfer cannot be modified.
   bool IsReadOnly() const {
     return mMode != Mode::ReadWrite;
   }
   // Helper method. Is true if the DataTransfer's mode is Protected, which means
   // that DataTransfer type information may be read, but data may not be.
@@ -267,16 +265,22 @@ public:
   GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext);
 
   // converts the data in the variant to an nsISupportString if possible or
   // an nsISupports or null otherwise.
   bool ConvertFromVariant(nsIVariant* aVariant,
                           nsISupports** aSupports,
                           uint32_t* aLength) const;
 
+  // Disconnects the DataTransfer from the Drag Data Store. If the
+  // dom.dataTransfer.disconnect pref is enabled, this will clear the
+  // DataTransfer and set it to the `Protected` state, otherwise this method is
+  // a no-op.
+  void Disconnect();
+
   // clears all of the data
   void ClearAll();
 
   // Similar to SetData except also specifies the principal to store.
   // aData may be null when called from CacheExternalDragFormats or
   // CacheExternalClipboardFormats.
   nsresult SetDataWithPrincipal(const nsAString& aFormat,
                                 nsIVariant* aData,
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -546,16 +546,20 @@ WINDOW_EVENT(languagechange,
              eBasicEventClass)
 // XXXbz Should the onmessage attribute on <body> really not work?  If so, do we
 // need a different macro to flag things like that (IDL, but not content
 // attributes on body/frameset), or is just using EventNameType_None enough?
 WINDOW_EVENT(message,
              eMessage,
              EventNameType_None,
              eBasicEventClass)
+WINDOW_EVENT(messageerror,
+             eMessageError,
+             EventNameType_HTMLBodyOrFramesetOnly,
+             eBasicEventClass)
 WINDOW_EVENT(offline,
              eOffline,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(online,
              eOnline,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1769,18 +1769,17 @@ EventStateManager::GenerateDragGesture(n
       nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
       if (!window)
         return;
 
       RefPtr<DataTransfer> dataTransfer =
         new DataTransfer(window, eDragStart, false, -1);
       auto protectDataTransfer = MakeScopeExit([&] {
         if (dataTransfer) {
-          dataTransfer->SetMode(DataTransfer::Mode::Protected);
-          dataTransfer->ClearAll();
+          dataTransfer->Disconnect();
         }
       });
 
       nsCOMPtr<nsISelection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
         DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -1371,17 +1371,20 @@ IMEContentObserver::MaybeNotifyIMEOfAdde
 void
 IMEContentObserver::BeginDocumentUpdate()
 {
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
     ("0x%p IMEContentObserver::BeginDocumentUpdate(), "
      "HasAddedNodesDuringDocumentChange()=%s",
      this, ToChar(HasAddedNodesDuringDocumentChange())));
 
-  MOZ_ASSERT(!HasAddedNodesDuringDocumentChange());
+  // If we're not in a nested document update, this will return early,
+  // otherwise, it will handle flusing any changes currently pending before
+  // entering a nested document update.
+  MaybeNotifyIMEOfAddedTextDuringDocumentChange();
 }
 
 void
 IMEContentObserver::EndDocumentUpdate()
 {
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
     ("0x%p IMEContentObserver::EndDocumentUpdate(), "
      "HasAddedNodesDuringDocumentChange()=%s",
--- a/dom/events/test/test_bug508479.html
+++ b/dom/events/test/test_bug508479.html
@@ -69,17 +69,17 @@ function runTests()
   is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (1)");
 
   // reset
   gGotHandlingDrop = false;
   gGotNotHandlingDrop = false;
 
   SpecialPowers.addChromeEventListener("drop", chromeListener, true, false);
   var targetNotHandling = document.getElementById("nothandling_target");
-  fireDrop(targetNotHandling, false, true);
+  fireDrop(targetNotHandling, true, true);
   SpecialPowers.removeChromeEventListener("drop", chromeListener, true);
   ok(chromeGotEvent, "Chrome should have got drop event!");
   is(gGotHandlingDrop, false, "Didn't get drop on accepting element (2)");
   is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (2)");
 
   SimpleTest.finish();
 }
 
--- a/dom/file/Blob.cpp
+++ b/dom/file/Blob.cpp
@@ -287,17 +287,17 @@ Blob::IsMemoryFile() const
 }
 
 void
 Blob::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
 {
   mImpl->GetInternalStream(aStream, aRv);
 }
 
-uint64_t
+size_t
 BindingJSObjectMallocBytes(Blob* aBlob)
 {
   MOZ_ASSERT(aBlob);
   return aBlob->GetAllocationSize();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/file/Blob.h
+++ b/dom/file/Blob.h
@@ -146,14 +146,14 @@ protected:
   RefPtr<BlobImpl> mImpl;
 
 private:
   nsCOMPtr<nsISupports> mParent;
 };
 
 // Override BindingJSObjectMallocBytes for blobs to tell the JS GC how much
 // memory is held live by the binding object.
-uint64_t BindingJSObjectMallocBytes(Blob* aBlob);
+size_t BindingJSObjectMallocBytes(Blob* aBlob);
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Blob_h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2305,18 +2305,16 @@ ContentChild::ActorDestroy(ActorDestroyR
   }
 
   if (AbnormalShutdown == why) {
     NS_WARNING("shutting down early because of crash!");
     ProcessChild::QuickExit();
   }
 
 #ifndef NS_FREE_PERMANENT_DATA
-  CompositorManagerChild::Shutdown();
-
   // In release builds, there's no point in the content process
   // going through the full XPCOM shutdown path, because it doesn't
   // keep persistent state.
   ProcessChild::QuickExit();
 #else
   if (gFirstIdleTask) {
     gFirstIdleTask->Cancel();
   }
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -154,10 +154,10 @@ skip-if = android_version == '22' # bug 
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
 [test_WaitingOnMissingData.html]
 skip-if = (toolkit == 'android') #timeout android only bug 1101187
 [test_WaitingOnMissingData_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
 [test_WaitingOnMissingDataEnded_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
 [test_WaitingToEndedTransition_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
+skip-if = ((os == "win" && os_version >= "10.0") || (toolkit == 'android')) # Not supported on android 2.3, failing on windows 10
 
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -132,27 +132,29 @@ private:
       end = MakeUnique<MessagePortTimelineMarker>(
         ProfileTimelineMessagePortOperationType::DeserializeData,
         MarkerTracingType::END);
       timelines->AddMarkerForAllObservedDocShells(start);
       timelines->AddMarkerForAllObservedDocShells(end);
     }
 
     if (NS_WARN_IF(rv.Failed())) {
+      mPort->DispatchError();
       return rv.StealNSResult();
     }
 
     // Create the event
     nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
       do_QueryInterface(mPort->GetOwner());
     RefPtr<MessageEvent> event =
       new MessageEvent(eventTarget, nullptr, nullptr);
 
     Sequence<OwningNonNull<MessagePort>> ports;
     if (!mData->TakeTransferredPortsAsSequence(ports)) {
+      mPort->DispatchError();
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
                             false /* non-bubbling */,
                             false /* cancelable */, value, EmptyString(),
                             EmptyString(), nullptr, ports);
     event->SetTrusted(true);
@@ -689,17 +691,17 @@ MessagePort::Entangled(nsTArray<ClonedMe
     // only clear after `messages` have gone out of scope.
     mMessagesForTheOtherPort.Clear();
   }
 
   // We must convert the messages into SharedMessagePortMessages to avoid leaks.
   FallibleTArray<RefPtr<SharedMessagePortMessage>> data;
   if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
                                                                       data))) {
-    // OOM, we cannot continue.
+    DispatchError();
     return;
   }
 
   // If the next step is to close the port, we do it ignoring the received
   // messages.
   if (oldState == eStateEntanglingForClose) {
     CloseForced();
     return;
@@ -743,17 +745,17 @@ MessagePort::MessagesReceived(nsTArray<C
              mState == eStateDisentangledForClose);
   MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty());
 
   RemoveDocFromBFCache();
 
   FallibleTArray<RefPtr<SharedMessagePortMessage>> data;
   if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages,
                                                                       data))) {
-    // OOM, We cannot continue.
+    DispatchError();
     return;
   }
 
   mMessages.AppendElements(data);
 
   if (mState == eStateEntangled) {
     Dispatch();
   }
@@ -999,10 +1001,33 @@ MessagePort::RemoveDocFromBFCache()
 }
 
 /* static */ void
 MessagePort::ForceClose(const MessagePortIdentifier& aIdentifier)
 {
   ForceCloseHelper::ForceClose(aIdentifier);
 }
 
+void
+MessagePort::DispatchError()
+{
+  nsCOMPtr<nsIGlobalObject> globalObject = GetParentObject();
+
+  AutoJSAPI jsapi;
+  if (!globalObject || !jsapi.Init(globalObject)) {
+    NS_WARNING("Failed to initialize AutoJSAPI object.");
+    return;
+  }
+
+  RootedDictionary<MessageEventInit> init(jsapi.cx());
+  init.mBubbles = false;
+  init.mCancelable = false;
+
+  RefPtr<Event> event =
+    MessageEvent::Constructor(this, NS_LITERAL_STRING("messageerror"), init);
+  event->SetTrusted(true);
+
+  bool dummy;
+  DispatchEvent(event, &dummy);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -69,16 +69,18 @@ public:
   void Start();
 
   void Close();
 
   EventHandlerNonNull* GetOnmessage();
 
   void SetOnmessage(EventHandlerNonNull* aCallback);
 
+  IMPL_EVENT_HANDLER(messageerror)
+
   // Non WebIDL methods
 
   void UnshippedEntangle(MessagePort* aEntangledPort);
 
   void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
 
   void CloseForced();
 
@@ -142,16 +144,18 @@ private:
                   uint32_t aSequenceID, bool mNeutered, State aState,
                   ErrorResult& aRv);
 
   void ConnectToPBackground();
 
   // Dispatch events from the Message Queue using a nsRunnable.
   void Dispatch();
 
+  void DispatchError();
+
   void StartDisentangling();
   void Disentangle();
 
   void RemoveDocFromBFCache();
 
   void CloseInternal(bool aSoftly);
 
   // This method is meant to keep alive the MessagePort when this object is
--- a/dom/tests/mochitest/general/test_clipboard_events.html
+++ b/dom/tests/mochitest/general/test_clipboard_events.html
@@ -741,14 +741,20 @@ function test_image_dataTransfer() {
   try {
     synthesizeKey("v", {accelKey: 1});
     ok(onpasteCalled, "The paste event listener must have been called");
   } finally {
     document.onpaste = null;
   }
 }
 
-SimpleTest.waitForFocus(doTests);
+SimpleTest.waitForFocus(() => {
+  SpecialPowers.pushPrefEnv({
+    // NOTE: These tests operate under the assumption that the protected mode of
+    // DataTransfer is enabled.
+    "set": [["dom.events.dataTransfer.protected.enabled", true]]
+  }, doTests);
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -869,17 +869,17 @@ var interfaceNamesInGlobalScope =
     {name: "SpecialPowers", xbl: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "StereoPannerNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Storage",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "StorageEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "StorageManager", nightly: true, isSecureContext: true, android: false},
+    {name: "StorageManager", isSecureContext: true, android: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "StyleSheet",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "StyleSheetList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SubtleCrypto",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SVGAElement",
--- a/dom/webidl/BroadcastChannel.webidl
+++ b/dom/webidl/BroadcastChannel.webidl
@@ -1,21 +1,22 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * For more information on this interface, please see
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts
+ * https://html.spec.whatwg.org/#broadcastchannel
  */
 
 [Constructor(DOMString channel),
  Exposed=(Window,Worker)]
 interface BroadcastChannel : EventTarget {
   readonly attribute DOMString name;
 
   [Throws]
   void postMessage(any message);
 
   void close();
 
-           attribute EventHandler onmessage;
+  attribute EventHandler onmessage;
+  attribute EventHandler onmessageerror;
 };
--- a/dom/webidl/DedicatedWorkerGlobalScope.webidl
+++ b/dom/webidl/DedicatedWorkerGlobalScope.webidl
@@ -19,9 +19,10 @@ interface DedicatedWorkerGlobalScope : W
   readonly attribute DOMString name;
 
   [Throws]
   void postMessage(any message, optional sequence<object> transfer = []);
 
   void close();
 
   attribute EventHandler onmessage;
+  attribute EventHandler onmessageerror;
 };
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -142,16 +142,17 @@ interface GlobalEventHandlers {
 [NoInterfaceObject]
 interface WindowEventHandlers {
            attribute EventHandler onafterprint;
            attribute EventHandler onbeforeprint;
            attribute OnBeforeUnloadEventHandler onbeforeunload;
            attribute EventHandler onhashchange;
            attribute EventHandler onlanguagechange;
            attribute EventHandler onmessage;
+           attribute EventHandler onmessageerror;
            attribute EventHandler onoffline;
            attribute EventHandler ononline;
            attribute EventHandler onpagehide;
            attribute EventHandler onpageshow;
            attribute EventHandler onpopstate;
            attribute EventHandler onstorage;
            attribute EventHandler onunload;
 };
--- a/dom/webidl/MessagePort.webidl
+++ b/dom/webidl/MessagePort.webidl
@@ -12,10 +12,11 @@ interface MessagePort : EventTarget {
   [Throws]
   void postMessage(any message, optional sequence<object> transferable = []);
 
   void start();
   void close();
 
   // event handlers
   attribute EventHandler onmessage;
+  attribute EventHandler onmessageerror;
 };
 // MessagePort implements Transferable;
--- a/dom/webidl/Worker.webidl
+++ b/dom/webidl/Worker.webidl
@@ -17,16 +17,17 @@
  Exposed=(Window,DedicatedWorker,SharedWorker,System)]
 interface Worker : EventTarget {
   void terminate();
 
   [Throws]
   void postMessage(any message, optional sequence<object> transfer = []);
 
   attribute EventHandler onmessage;
+  attribute EventHandler onmessageerror;
 };
 
 Worker implements AbstractWorker;
 
 dictionary WorkerOptions {
   // WorkerType type = "classic"; TODO: Bug 1247687
   // RequestCredentials credentials = "omit"; // credentials is only used if type is "module" TODO: Bug 1247687
   DOMString name = "";
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -675,17 +675,22 @@ private:
     if (mCanceledMainThread || !mCacheCreator) {
       aRequest->Cancel(NS_ERROR_FAILURE);
       return NS_ERROR_FAILURE;
     }
 
     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
 
     nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
-    MOZ_ASSERT(channel == loadInfo.mChannel);
+
+    // Note that importScripts() can redirect.  In theory the main
+    // script could also encounter an internal redirect, but currently
+    // the assert does not allow that.
+    MOZ_ASSERT_IF(mIsMainScript, channel == loadInfo.mChannel);
+    loadInfo.mChannel = channel;
 
     // We synthesize the result code, but its never exposed to content.
     RefPtr<mozilla::dom::InternalResponse> ir =
       new mozilla::dom::InternalResponse(200, NS_LITERAL_CSTRING("OK"));
     ir->SetBody(loadInfo.mCacheReadStream, InternalResponse::UNKNOWN_BODY_SIZE);
 
     // Drop our reference to the stream now that we've passed it along, so it
     // doesn't hang around once the cache is done with it and keep data alive.
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -724,17 +724,17 @@ public:
       if (NS_WARN_IF(!parent)) {
         return false;
       }
     }
 
     MOZ_ASSERT(parent);
 
     JS::Rooted<JS::Value> messageData(aCx);
-    ErrorResult rv;
+    IgnoredErrorResult rv;
 
     UniquePtr<AbstractTimelineMarker> start;
     UniquePtr<AbstractTimelineMarker> end;
     RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
     bool isTimelineRecording = timelines && !timelines->IsEmpty();
 
     if (isTimelineRecording) {
       start = MakeUnique<WorkerTimelineMarker>(aIsMainThread
@@ -750,22 +750,23 @@ public:
         ? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
         : ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
         MarkerTracingType::END);
       timelines->AddMarkerForAllObservedDocShells(start);
       timelines->AddMarkerForAllObservedDocShells(end);
     }
 
     if (NS_WARN_IF(rv.Failed())) {
-      xpc::Throw(aCx, rv.StealNSResult());
+      DispatchError(aCx, aTarget);
       return false;
     }
 
     Sequence<OwningNonNull<MessagePort>> ports;
     if (!TakeTransferredPortsAsSequence(ports)) {
+      DispatchError(aCx, aTarget);
       return false;
     }
 
     nsCOMPtr<nsIDOMEvent> domEvent;
     RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
     event->InitMessageEvent(nullptr,
                             NS_LITERAL_STRING("message"),
                             false /* non-bubbling */,
@@ -809,16 +810,31 @@ private:
                               !aWorkerPrivate->GetParent());
     }
 
     MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
 
     return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
                             false);
   }
+
+  void
+  DispatchError(JSContext* aCx, DOMEventTargetHelper* aTarget)
+  {
+    RootedDictionary<MessageEventInit> init(aCx);
+    init.mBubbles = false;
+    init.mCancelable = false;
+
+    RefPtr<Event> event =
+      MessageEvent::Constructor(aTarget, NS_LITERAL_STRING("messageerror"), init);
+    event->SetTrusted(true);
+
+    bool dummy;
+    aTarget->DispatchEvent(event, &dummy);
+  }
 };
 
 class DebuggerMessageEventRunnable : public WorkerDebuggerRunnable {
   nsString mMessage;
 
 public:
   DebuggerMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
                                const nsAString& aMessage)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -877,16 +877,17 @@ public:
   {
     return mLoadInfo.mLoadFailedAsyncRunnable.forget();
   }
 
   void
   FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
 
   IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(messageerror)
   IMPL_EVENT_HANDLER(error)
 
   // Check whether this worker is a secure context.  For use from the parent
   // thread only; the canonical "is secure context" boolean is stored on the
   // compartment of the worker global.  The only reason we don't
   // AssertIsOnParentThread() here is so we can assert that this value matches
   // the one on the compartment, which has to be done from the worker thread.
   bool IsSecureContext() const
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -246,16 +246,17 @@ public:
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Sequence<JSObject*>& aTransferable,
               ErrorResult& aRv);
 
   void
   Close(JSContext* aCx);
 
   IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(messageerror)
 };
 
 class SharedWorkerGlobalScope final : public WorkerGlobalScope
 {
   const nsString mName;
 
   ~SharedWorkerGlobalScope() { }
 
@@ -391,16 +392,17 @@ public:
 
   void
   LeaveEventLoop();
 
   void
   PostMessage(const nsAString& aMessage);
 
   IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(messageerror)
 
   void
   SetImmediate(Function& aHandler, ErrorResult& aRv);
 
   void
   ReportError(JSContext* aCx, const nsAString& aMessage);
 
   void
--- a/dom/workers/test/navigator_worker.js
+++ b/dom/workers/test/navigator_worker.js
@@ -10,17 +10,17 @@ var supportedProps = [
   "appVersion",
   "platform",
   "product",
   "userAgent",
   "onLine",
   "language",
   "languages",
   "hardwareConcurrency",
-  { name: "storage", nightly: true, isSecureContext: true },
+  { name: "storage", isSecureContext: true },
   "connection",
 ];
 
 self.onmessage = function(event) {
   if (!event || !event.data) {
     return;
   }
 
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -207,17 +207,17 @@ var interfaceNamesInGlobalScope =
     "Response",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerGlobalScope",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerRegistration",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "StorageManager", nightly: true, android: false},
+    {name: "StorageManager", android: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SubtleCrypto",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextDecoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextEncoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URL",
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -193,17 +193,17 @@ var interfaceNamesInGlobalScope =
     "PushSubscriptionOptions",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Request",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Response",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerRegistration",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "StorageManager", nightly: true, isSecureContext: true, android: false},
+    {name: "StorageManager", isSecureContext: true, android: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SubtleCrypto",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextDecoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextEncoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XMLHttpRequest",
--- a/gfx/ipc/VsyncBridgeParent.cpp
+++ b/gfx/ipc/VsyncBridgeParent.cpp
@@ -23,17 +23,17 @@ VsyncBridgeParent::Start(Endpoint<PVsync
 
   return parent;
 }
 
 VsyncBridgeParent::VsyncBridgeParent()
  : mOpen(false)
 {
   MOZ_COUNT_CTOR(VsyncBridgeParent);
-  mCompositorThreadRef = CompositorThreadHolder::GetSingleton();
+  mCompositorThreadRef = new CompositorThreadHolderDebug("VsyncBridge");
 }
 
 VsyncBridgeParent::~VsyncBridgeParent()
 {
   MOZ_COUNT_DTOR(VsyncBridgeParent);
 }
 
 void
--- a/gfx/ipc/VsyncBridgeParent.h
+++ b/gfx/ipc/VsyncBridgeParent.h
@@ -33,15 +33,15 @@ private:
   VsyncBridgeParent();
   ~VsyncBridgeParent();
 
   void Open(Endpoint<PVsyncBridgeParent>&& aEndpoint);
   void ShutdownImpl();
 
 private:
   bool mOpen;
-  RefPtr<layers::CompositorThreadHolder> mCompositorThreadRef;
+  RefPtr<layers::CompositorThreadHolderDebug> mCompositorThreadRef;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif // include_gfx_ipc_VsyncBridgeParent_h
--- a/gfx/layers/d3d11/MLGDeviceD3D11.cpp
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
@@ -1088,16 +1088,27 @@ MLGDeviceD3D11::InitSamplerStates()
     desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
     memset(desc.BorderColor, 0, sizeof(desc.BorderColor));
     HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClampToZero]));
     if (FAILED(hr)) {
       return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
                   "Could not create linear clamp to zero sampler (%x)", hr);
     }
   }
+  {
+    CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+    desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+    desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+    desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+    HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearRepeat]));
+    if (FAILED(hr)) {
+      return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
+                  "Could not create linear clamp to zero sampler (%x)", hr);
+    }
+  }
 
   {
     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
     desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
     HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::Point]));
     if (FAILED(hr)) {
       return Fail("FEATURE_FAILURE_POINT_SAMPLER",
                   "Could not create point sampler (%x)", hr);
--- a/gfx/layers/ipc/CompositorManagerParent.cpp
+++ b/gfx/layers/ipc/CompositorManagerParent.cpp
@@ -31,16 +31,18 @@ CompositorManagerParent::CreateSameProce
     MOZ_ASSERT_UNREACHABLE("Already initialized");
     return nullptr;
   }
 
   // The child is responsible for setting up the IPC channel in the same
   // process case because if we open from the child perspective, we can do it
   // on the main thread and complete before we return the manager handles.
   RefPtr<CompositorManagerParent> parent = new CompositorManagerParent();
+  parent->mCompositorThreadHolder =
+    new CompositorThreadHolderDebug("CompositorManagerSame");
   parent->SetOtherProcessId(base::GetCurrentProcId());
 
   // CompositorManagerParent::Bind would normally add a reference for IPDL but
   // we don't use that in the same process case.
   parent.get()->AddRef();
   sInstance = parent;
   return parent.forget();
 }
@@ -50,16 +52,18 @@ CompositorManagerParent::Create(Endpoint
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // We are creating a manager for the another process, inside the GPU process
   // (or UI process if it subsumbed the GPU process).
   MOZ_ASSERT(aEndpoint.OtherPid() != base::GetCurrentProcId());
 
   RefPtr<CompositorManagerParent> bridge = new CompositorManagerParent();
+  bridge->mCompositorThreadHolder =
+    new CompositorThreadHolderDebug("CompositorManagerContent");
 
   RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PCompositorManagerParent>&&>(
     "CompositorManagerParent::Bind",
     bridge,
     &CompositorManagerParent::Bind,
     Move(aEndpoint));
   CompositorThreadHolder::Loop()->PostTask(runnable.forget());
 }
@@ -100,17 +104,16 @@ CompositorManagerParent::CreateSameProce
     new CompositorBridgeParent(sInstance, aScale, vsyncRate, aOptions,
                                aUseExternalSurfaceSize, aSurfaceSize);
 
   sInstance->mPendingCompositorBridges.AppendElement(bridge);
   return bridge.forget();
 }
 
 CompositorManagerParent::CompositorManagerParent()
-  : mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
 {
 }
 
 CompositorManagerParent::~CompositorManagerParent()
 {
 }
 
 void
--- a/gfx/layers/ipc/CompositorManagerParent.h
+++ b/gfx/layers/ipc/CompositorManagerParent.h
@@ -13,17 +13,17 @@
 #include "mozilla/RefPtr.h"             // for already_AddRefed
 #include "mozilla/layers/PCompositorManagerParent.h"
 #include "nsTArray.h"                   // for AutoTArray
 
 namespace mozilla {
 namespace layers {
 
 class CompositorBridgeParent;
-class CompositorThreadHolder;
+class CompositorThreadHolderDebug;
 
 class CompositorManagerParent final : public PCompositorManagerParent
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorManagerParent)
 
 public:
   static already_AddRefed<CompositorManagerParent> CreateSameProcess();
   static void Create(Endpoint<PCompositorManagerParent>&& aEndpoint);
@@ -47,17 +47,17 @@ private:
   ~CompositorManagerParent() override;
 
   void Bind(Endpoint<PCompositorManagerParent>&& aEndpoint);
 
   void DeallocPCompositorManagerParent() override;
 
   void DeferredDestroy();
 
-  RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+  RefPtr<CompositorThreadHolderDebug> mCompositorThreadHolder;
 
   AutoTArray<RefPtr<CompositorBridgeParent>, 1> mPendingCompositorBridges;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/CompositorThread.cpp
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -4,26 +4,56 @@
  * 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 "CompositorThread.h"
 #include "MainThreadUtils.h"
 #include "nsThreadUtils.h"
 #include "CompositorBridgeParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/media/MediaSystemResourceService.h"
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"     // for CrashReporter
+#endif
 
 namespace mozilla {
 
 namespace gfx {
 // See VRManagerChild.cpp
 void ReleaseVRManagerParentSingleton();
 } // namespace gfx
 
 namespace layers {
 
+#ifdef MOZ_CRASHREPORTER
+static Atomic<int32_t> sHoldersNextId(0);
+#endif
+
+CompositorThreadHolderDebug::CompositorThreadHolderDebug(const char* aName)
+  : mHolder(CompositorThreadHolder::GetSingleton())
+{
+#ifdef MOZ_CRASHREPORTER
+  if (XRE_IsParentProcess()) {
+    mId.AppendLiteral("gfxCompositorThread:");
+    mId.Append(aName);
+    mId.AppendLiteral(":");
+    mId.AppendInt(++sHoldersNextId);
+    CrashReporter::AnnotateCrashReport(mId, NS_LITERAL_CSTRING("1"));
+  }
+#endif
+}
+
+CompositorThreadHolderDebug::~CompositorThreadHolderDebug()
+{
+#ifdef MOZ_CRASHREPORTER
+  if (XRE_IsParentProcess()) {
+    CrashReporter::AnnotateCrashReport(mId, NS_LITERAL_CSTRING("0"));
+  }
+#endif
+}
+
 static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
 static bool sFinishedCompositorShutDown = false;
 
 // See ImageBridgeChild.cpp
 void ReleaseImageBridgeParentSingleton();
 
 CompositorThreadHolder* GetCompositorThreadHolder()
 {
--- a/gfx/layers/ipc/CompositorThread.h
+++ b/gfx/layers/ipc/CompositorThread.h
@@ -55,14 +55,30 @@ private:
   base::Thread* const mCompositorThread;
 
   static base::Thread* CreateCompositorThread();
   static void DestroyCompositorThread(base::Thread* aCompositorThread);
 
   friend class CompositorBridgeParent;
 };
 
+class CompositorThreadHolderDebug final
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorThreadHolderDebug)
+
+public:
+  explicit CompositorThreadHolderDebug(const char* aName);
+
+private:
+  ~CompositorThreadHolderDebug();
+
+  RefPtr<CompositorThreadHolder> mHolder;
+#ifdef MOZ_CRASHREPORTER
+  nsAutoCString mId;
+#endif
+};
+
 base::Thread* CompositorThread();
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_CompositorThread_h
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -362,17 +362,19 @@ ImageBridgeParent::GetInstance(ProcessId
   MonitorAutoLock lock(*sImageBridgesLock);
   NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
   return sImageBridges[aId];
 }
 
 void
 ImageBridgeParent::OnChannelConnected(int32_t aPid)
 {
-  mCompositorThreadHolder = GetCompositorThreadHolder();
+  mCompositorThreadHolder =
+    new CompositorThreadHolderDebug(IsSameProcess() ? "ImageBridgeSame"
+                                                    : "ImageBridge");
 }
 
 
 bool
 ImageBridgeParent::AllocShmem(size_t aSize,
                       ipc::SharedMemory::SharedMemoryType aType,
                       ipc::Shmem* aShmem)
 {
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -136,15 +136,15 @@ private:
   bool mSetChildThreadPriority;
   bool mClosed;
 
   /**
    * Map of all living ImageBridgeParent instances
    */
   static std::map<base::ProcessId, ImageBridgeParent*> sImageBridges;
 
-  RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+  RefPtr<CompositorThreadHolderDebug> mCompositorThreadHolder;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // gfx_layers_ipc_ImageBridgeParent_h_
--- a/gfx/layers/ipc/VideoBridgeParent.cpp
+++ b/gfx/layers/ipc/VideoBridgeParent.cpp
@@ -16,17 +16,17 @@ using namespace mozilla::gfx;
 
 static VideoBridgeParent* sVideoBridgeSingleton;
 
 VideoBridgeParent::VideoBridgeParent()
   : mClosed(false)
 {
   mSelfRef = this;
   sVideoBridgeSingleton = this;
-  mCompositorThreadRef = CompositorThreadHolder::GetSingleton();
+  mCompositorThreadRef = new CompositorThreadHolderDebug("VideoBridge");
 }
 
 VideoBridgeParent::~VideoBridgeParent()
 {
   sVideoBridgeSingleton = nullptr;
 }
 
 /* static */ VideoBridgeParent*
--- a/gfx/layers/ipc/VideoBridgeParent.h
+++ b/gfx/layers/ipc/VideoBridgeParent.h
@@ -7,17 +7,17 @@
 #define gfx_layers_ipc_VideoBridgeParent_h_
 
 #include "mozilla/layers/PVideoBridgeParent.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 
 namespace mozilla {
 namespace layers {
 
-class CompositorThreadHolder;
+class CompositorThreadHolderDebug;
 
 class VideoBridgeParent final : public PVideoBridgeParent,
                                 public HostIPCAllocator,
                                 public ShmemAllocator
 {
 public:
   VideoBridgeParent();
   ~VideoBridgeParent();
@@ -58,17 +58,17 @@ public:
   void DeallocShmem(ipc::Shmem& aShmem) override;
 
 private:
   void DeallocPVideoBridgeParent() override;
 
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   RefPtr<VideoBridgeParent> mSelfRef;
-  RefPtr<CompositorThreadHolder> mCompositorThreadRef;
+  RefPtr<CompositorThreadHolderDebug> mCompositorThreadRef;
 
   std::map<uint64_t, PTextureParent*> mTextureMap;
 
   bool mClosed;
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/mlgpu/ImageLayerMLGPU.cpp
+++ b/gfx/layers/mlgpu/ImageLayerMLGPU.cpp
@@ -72,19 +72,26 @@ ImageLayerMLGPU::IsContentOpaque()
     return gfx::IsOpaque(mHost->CurrentTextureHost()->GetFormat());
   }
   return false;
 }
 
 void
 ImageLayerMLGPU::SetRegionToRender(LayerIntRegion&& aRegion)
 {
-  // See bug 1264142.
-  if (mScaleMode == ScaleMode::STRETCH) {
+  switch (mScaleMode) {
+  case ScaleMode::STRETCH:
+    // See bug 1264142.
     aRegion.AndWith(LayerIntRect(0, 0, mScaleToSize.width, mScaleToSize.height));
+    break;
+  default:
+    // Clamp the visible region to the texture size. (see bug 1396507)
+    MOZ_ASSERT(mScaleMode == ScaleMode::SCALE_NONE);
+    aRegion.AndWith(LayerIntRect(0, 0, mPictureRect.width, mPictureRect.height));
+    break;
   }
   LayerMLGPU::SetRegionToRender(Move(aRegion));
 }
 
 void
 ImageLayerMLGPU::CleanupResources()
 {
   if (mHost) {
--- a/gfx/layers/mlgpu/MLGDevice.cpp
+++ b/gfx/layers/mlgpu/MLGDevice.cpp
@@ -233,31 +233,16 @@ MLGDevice::SetPSTexturesYUV(uint32_t aSl
 }
 
 void
 MLGDevice::SetPSTexture(uint32_t aSlot, TextureSource* aSource)
 {
   SetPSTextures(aSlot, 1, &aSource);
 }
 
-static inline SamplerMode
-FilterToSamplerMode(gfx::SamplingFilter aFilter)
-{
-  switch (aFilter) {
-  case gfx::SamplingFilter::POINT:
-    return SamplerMode::Point;
-  case gfx::SamplingFilter::LINEAR:
-  case gfx::SamplingFilter::GOOD:
-    return SamplerMode::LinearClamp;
-  default:
-    MOZ_ASSERT_UNREACHABLE("Unknown sampler mode");
-    return SamplerMode::LinearClamp;
-  }
-}
-
 void
 MLGDevice::SetSamplerMode(uint32_t aIndex, gfx::SamplingFilter aFilter)
 {
   SetSamplerMode(aIndex, FilterToSamplerMode(aFilter));
 }
 
 bool
 MLGDevice::Fail(const nsCString& aFailureId, const nsCString* aMessage)
--- a/gfx/layers/mlgpu/MLGDeviceTypes.h
+++ b/gfx/layers/mlgpu/MLGDeviceTypes.h
@@ -2,16 +2,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_gfx_layers_mlgpu_MLGDeviceTypes_h
 #define mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
 
 #include "mozilla/TypedEnumBits.h"
+#include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace layers {
 
 enum class MLGUsage
 {
   // GPU read-only, CPU write once on creation and read/write never.
   Immutable,
@@ -42,16 +43,18 @@ enum class MLGBufferType : uint32_t
 };
 
 enum class SamplerMode
 {
   // Linear filter, clamped to border.
   LinearClamp = 0,
   // Linear filter, clamped to transparent pixels.
   LinearClampToZero,
+  // Linear filter, wrap edges.
+  LinearRepeat,
   // Point filter, clamped to border.
   Point,
   MaxModes
 };
 
 enum class MLGBlendState
 {
   Copy = 0,
@@ -99,12 +102,27 @@ enum class MLGRenderTargetFlags : uint32
   ZBuffer = (1 << 0)
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MLGRenderTargetFlags);
 
 // NVIDIA drivers crash when we supply too many rects to ClearView - it
 // seems to cause a stack overflow >= 20 rects. We cap to 12 for now.
 static const size_t kMaxClearViewRects = 12;
 
+static inline SamplerMode
+FilterToSamplerMode(gfx::SamplingFilter aFilter)
+{
+  switch (aFilter) {
+  case gfx::SamplingFilter::POINT:
+    return SamplerMode::Point;
+  case gfx::SamplingFilter::LINEAR:
+  case gfx::SamplingFilter::GOOD:
+    return SamplerMode::LinearClamp;
+  default:
+    MOZ_ASSERT_UNREACHABLE("Unknown sampler mode");
+    return SamplerMode::LinearClamp;
+  }
+}
+
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
--- a/gfx/layers/mlgpu/PaintedLayerMLGPU.h
+++ b/gfx/layers/mlgpu/PaintedLayerMLGPU.h
@@ -3,16 +3,17 @@
 * 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_GFX_PAINTEDLAYERMLGPU_H
 #define MOZILLA_GFX_PAINTEDLAYERMLGPU_H
 
 #include "LayerManagerMLGPU.h"
 #include "mozilla/layers/ContentHost.h"
+#include "MLGDeviceTypes.h"
 #include "nsRegionFwd.h"
 #include <functional>
 
 namespace mozilla {
 namespace layers {
 
 class PaintedLayerMLGPU final
   : public PaintedLayer,
@@ -44,16 +45,24 @@ public:
   }
   TextureSource* GetTextureOnWhite() const {
     MOZ_ASSERT(HasComponentAlpha());
     return mTextureOnWhite;
   }
   ContentHostTexture* GetContentHost() const {
     return mHost;
   }
+  SamplerMode GetSamplerMode() {
+    // Note that when resamping, we must break the texture coordinates into
+    // no-repeat rects. When we have simple integer translations we can
+    // simply wrap around the edge of the buffer texture.
+    return MayResample()
+           ? SamplerMode::LinearClamp
+           : SamplerMode::LinearRepeat;
+  }
 
   // This can return a different region than GetShadowVisibleRegion or
   // GetLocalVisibleRegion, since we make sure to clamp it to the
   // texture size and account for resampling.
   nsIntRegion GetRenderRegion();
 
   MOZ_LAYER_DECL_NAME("PaintedLayerMLGPU", TYPE_PAINTED)
 
--- a/gfx/layers/mlgpu/RenderPassMLGPU.cpp
+++ b/gfx/layers/mlgpu/RenderPassMLGPU.cpp
@@ -443,163 +443,191 @@ SolidColorPass::SetupPipeline()
 }
 
 TexturedRenderPass::TexturedRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : BatchRenderPass(aBuilder, aItem),
    mTextureFlags(TextureFlags::NO_FLAGS)
 {
 }
 
+TexturedRenderPass::Info::Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer)
+ : item(aItem),
+   textureSize(aLayer->GetTexture()->GetSize()),
+   destOrigin(aLayer->GetContentHost()->GetOriginOffset()),
+   decomposeIntoNoRepeatRects(aLayer->MayResample())
+{
+}
+
+TexturedRenderPass::Info::Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer)
+ : item(aItem),
+   textureSize(aLayer->GetTexture()->GetSize()),
+   scale(aLayer->GetPictureScale()),
+   decomposeIntoNoRepeatRects(false)
+{
+}
+
+TexturedRenderPass::Info::Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer)
+ : item(aItem),
+   textureSize(aLayer->GetTargetSize()),
+   destOrigin(aLayer->GetTargetOffset()),
+   decomposeIntoNoRepeatRects(false)
+{
+}
+
 bool
 TexturedRenderPass::AddItem(Txn& aTxn,
-                            const ItemInfo& aInfo,
-                            const Rect& aDrawRect,
-                            const Point& aDestOrigin,
-                            const IntSize& aTextureSize,
-                            const Maybe<Size>& aScale)
+                            const Info& aInfo,
+                            const Rect& aDrawRect)
 {
-
   if (mGeometry == GeometryMode::Polygon) {
     // This path will not clamp the draw rect to the layer clip, so we can pass
     // the draw rect texture rects straight through.
-    return AddClippedItem(aTxn, aInfo, aDrawRect, aDestOrigin, aTextureSize, aScale);
+    return AddClippedItem(aTxn, aInfo, aDrawRect);
   }
 
-  MOZ_ASSERT(!aInfo.geometry);
-  MOZ_ASSERT(aInfo.HasRectTransformAndClip());
+  const ItemInfo& item = aInfo.item;
+
+  MOZ_ASSERT(!item.geometry);
+  MOZ_ASSERT(item.HasRectTransformAndClip());
   MOZ_ASSERT(mHasRectTransformAndClip);
 
-  const Matrix4x4& fullTransform = aInfo.layer->GetLayer()->GetEffectiveTransformForBuffer();
+  const Matrix4x4& fullTransform = item.layer->GetLayer()->GetEffectiveTransformForBuffer();
   Matrix transform = fullTransform.As2D();
   Matrix inverse = transform;
   if (!inverse.Invert()) {
     // Degenerate transforms are not visible, since there is no mapping to
     // screen space. Just return without adding any draws.
     return true;
   }
   MOZ_ASSERT(inverse.IsRectilinear());
 
   // Transform the clip rect.
-  IntRect clipRect = aInfo.layer->GetComputedClipRect().ToUnknownRect();
-  clipRect += aInfo.view->GetTargetOffset();
+  IntRect clipRect = item.layer->GetComputedClipRect().ToUnknownRect();
+  clipRect += item.view->GetTargetOffset();
 
   // Clip and adjust the texture rect.
   Rect localClip = inverse.TransformBounds(Rect(clipRect));
   Rect clippedDrawRect = aDrawRect.Intersect(localClip);
   if (clippedDrawRect.IsEmpty()) {
     return true;
   }
 
-  return AddClippedItem(aTxn, aInfo, clippedDrawRect, aDestOrigin, aTextureSize, aScale);
+  return AddClippedItem(aTxn, aInfo, clippedDrawRect);
 }
 
 bool
 TexturedRenderPass::AddClippedItem(Txn& aTxn,
-                                   const ItemInfo& aInfo,
-                                   const gfx::Rect& aDrawRect,
-                                   const gfx::Point& aDestOrigin,
-                                   const gfx::IntSize& aTextureSize,
-                                   const Maybe<gfx::Size>& aScale)
+                                   const Info& aInfo,
+                                   const gfx::Rect& aDrawRect)
 {
-  float xScale = aScale ? aScale->width : 1.0f;
-  float yScale = aScale ? aScale->height : 1.0f;
+  float xScale = 1.0;
+  float yScale = 1.0;
+  if (aInfo.scale) {
+    xScale = aInfo.scale->width;
+    yScale = aInfo.scale->height;
+  }
 
-  Point offset = aDrawRect.TopLeft() - aDestOrigin;
+  Point offset = aDrawRect.TopLeft() - aInfo.destOrigin;
   Rect textureRect(
     offset.x * xScale,
     offset.y * yScale,
     aDrawRect.Width() * xScale,
     aDrawRect.Height() * yScale);
 
-  Rect textureCoords = TextureRectToCoords(textureRect, aTextureSize);
+  Rect textureCoords = TextureRectToCoords(textureRect, aInfo.textureSize);
   if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
     textureCoords.y = 1.0 - textureCoords.y;
     textureCoords.SetHeight(-textureCoords.Height());
   }
 
-  Rect layerRects[4];
-  Rect textureRects[4];
-  size_t numRects =
-    DecomposeIntoNoRepeatRects(aDrawRect, textureCoords, &layerRects, &textureRects);
-
-  for (size_t i = 0; i < numRects; i++) {
-    TexturedTraits traits(aInfo, layerRects[i], textureRects[i]);
+  if (!aInfo.decomposeIntoNoRepeatRects) {
+    // Fast, normal case, we can use the texture coordinates as-s and the caller
+    // will use a repeat sampler if needed.
+    TexturedTraits traits(aInfo.item, aDrawRect, textureCoords);
     if (!aTxn.Add(traits)) {
       return false;
     }
+  } else {
+    Rect layerRects[4];
+    Rect textureRects[4];
+    size_t numRects =
+      DecomposeIntoNoRepeatRects(aDrawRect, textureCoords, &layerRects, &textureRects);
+
+    for (size_t i = 0; i < numRects; i++) {
+      TexturedTraits traits(aInfo.item, layerRects[i], textureRects[i]);
+      if (!aTxn.Add(traits)) {
+        return false;
+      }
+    }
   }
   return true;
 }
 
 SingleTexturePass::SingleTexturePass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mOpacity(1.0f)
 {
   SetDefaultGeometry(aItem);
 }
 
 bool
-SingleTexturePass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aInfo)
+SingleTexturePass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem)
 {
   RefPtr<TextureSource> texture;
 
-  gfx::SamplingFilter filter;
+  SamplerMode sampler;
   TextureFlags flags = TextureFlags::NO_FLAGS;
   if (PaintedLayerMLGPU* paintedLayer = aLayer->AsPaintedLayerMLGPU()) {
     if (paintedLayer->HasComponentAlpha()) {
       return false;
     }
     texture = paintedLayer->GetTexture();
-    filter = SamplingFilter::LINEAR;
+    sampler = paintedLayer->GetSamplerMode();
   } else if (TexturedLayerMLGPU* texLayer = aLayer->AsTexturedLayerMLGPU()) {
     texture = texLayer->GetTexture();
-    filter = texLayer->GetSamplingFilter();
+    sampler = FilterToSamplerMode(texLayer->GetSamplingFilter());
     TextureHost* host = texLayer->GetImageHost()->CurrentTextureHost();
     flags = host->GetFlags();
   } else {
     return false;
   }
 
   // We should not assign a texture-based layer to tiles if it has no texture.
   MOZ_ASSERT(texture);
 
   float opacity = aLayer->GetComputedOpacity();
   if (mTexture) {
     if (texture != mTexture) {
       return false;
     }
-    if (mFilter != filter) {
+    if (mSamplerMode != sampler) {
       return false;
     }
     if (mOpacity != opacity) {
       return false;
     }
     // Note: premultiplied, origin-bottom-left are already implied by the texture source.
   } else {
     mTexture = texture;
-    mFilter = filter;
+    mSamplerMode = sampler;
     mOpacity = opacity;
     mTextureFlags = flags;
   }
 
   Txn txn(this);
 
   if (PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU()) {
-    nsIntRegion visible = layer->GetRenderRegion();
-    IntPoint offset = layer->GetContentHost()->GetOriginOffset();
-
-    if (!AddItems(txn, aInfo, visible, offset, mTexture->GetSize())) {
+    Info info(aItem, layer);
+    if (!AddItems(txn, info, layer->GetRenderRegion())) {
       return false;
     }
   } else if (TexturedLayerMLGPU* layer = aLayer->AsTexturedLayerMLGPU()) {
-    IntPoint origin(0, 0);
-    Maybe<Size> pictureScale = layer->GetPictureScale();
+    Info info(aItem, layer);
     nsIntRegion visible = layer->GetShadowVisibleRegion().ToUnknownRegion();
-
-    if (!AddItems(txn, aInfo, visible, origin, mTexture->GetSize(), pictureScale)) {
+    if (!AddItems(txn, info, visible)) {
       return false;
     }
   }
 
   return txn.Commit();
 }
 
 Maybe<MLGBlendState>
@@ -617,17 +645,17 @@ SingleTexturePass::SetupPipeline()
 
   if (mGeometry == GeometryMode::UnitQuad) {
     mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
   } else {
     mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
   }
 
   mDevice->SetPSTexture(0, mTexture);
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, mFilter);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
   switch (mTexture.get()->GetFormat()) {
     case SurfaceFormat::B8G8R8A8:
     case SurfaceFormat::R8G8B8A8:
       if (mGeometry == GeometryMode::UnitQuad)
         mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA);
       else
         mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA);
       break;
@@ -643,36 +671,34 @@ SingleTexturePass::SetupPipeline()
 ComponentAlphaPass::ComponentAlphaPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
 : TexturedRenderPass(aBuilder, aItem),
   mAssignedLayer(nullptr)
 {
   SetDefaultGeometry(aItem);
 }
 
 bool
-ComponentAlphaPass::AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo)
+ComponentAlphaPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem)
 {
-  PaintedLayerMLGPU* layer = aItem->AsPaintedLayerMLGPU();
+  PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU();
   MOZ_ASSERT(layer);
 
   if (mAssignedLayer && mAssignedLayer != layer) {
     return false;
   }
   if (!mAssignedLayer) {
     mAssignedLayer = layer;
     mTextureOnBlack = layer->GetTexture();
     mTextureOnWhite = layer->GetTextureOnWhite();
   } 
 
   Txn txn(this);
 
-  nsIntRegion visible = layer->GetRenderRegion();
-  IntPoint offset = layer->GetContentHost()->GetOriginOffset();
-
-  if (!AddItems(txn, aInfo, visible, offset, mTextureOnWhite->GetSize())) {
+  Info info(aItem, layer);
+  if (!AddItems(txn, info, layer->GetRenderRegion())) {
     return false;
   }
   return txn.Commit();
 }
 
 float
 ComponentAlphaPass::GetOpacity() const
 {
@@ -692,70 +718,68 @@ ComponentAlphaPass::SetupPipeline()
   if (mGeometry == GeometryMode::UnitQuad) {
     mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
     mDevice->SetPixelShader(PixelShaderID::ComponentAlphaQuad);
   } else {
     mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
     mDevice->SetPixelShader(PixelShaderID::ComponentAlphaVertex);
   }
 
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mAssignedLayer->GetSamplerMode());
   mDevice->SetPSTextures(0, 2, textures);
 }
 
 VideoRenderPass::VideoRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mOpacity(1.0f)
 {
   SetDefaultGeometry(aItem);
 }
 
 bool
-VideoRenderPass::AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo)
+VideoRenderPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem)
 {
-  ImageLayerMLGPU* layer = aItem->AsImageLayerMLGPU();
+  ImageLayerMLGPU* layer = aLayer->AsImageLayerMLGPU();
   if (!layer) {
     return false;
   }
 
   RefPtr<TextureHost> host = layer->GetImageHost()->CurrentTextureHost();
   RefPtr<TextureSource> source = layer->GetTexture();
   float opacity = layer->GetComputedOpacity();
-  SamplingFilter filter = layer->GetSamplingFilter();
+  SamplerMode sampler = FilterToSamplerMode(layer->GetSamplingFilter());
 
   if (mHost) {
     if (mHost != host) {
       return false;
     }
     if (mTexture != source) {
       return false;
     }
     if (mOpacity != opacity) {
       return false;
     }
-    if (mFilter != filter) {
+    if (mSamplerMode != sampler) {
       return false;
     }
   } else {
     mHost = host;
     mTexture = source;
     mOpacity = opacity;
-    mFilter = filter;
+    mSamplerMode = sampler;
   }
   MOZ_ASSERT(!mTexture->AsBigImageIterator());
   MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED));
   MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT));
 
   Txn txn(this);
 
-  IntPoint origin(0, 0);
-  Maybe<Size> pictureScale = layer->GetPictureScale();
+  Info info(aItem, layer);
   nsIntRegion visible = layer->GetShadowVisibleRegion().ToUnknownRegion();
-
-  if (!AddItems(txn, aInfo, visible, origin, mTexture->GetSize(), pictureScale)) {
+  if (!AddItems(txn, info, visible)) {
     return false;
   }
   return txn.Commit();
 }
 
 void
 VideoRenderPass::SetupPipeline()
 {
@@ -802,17 +826,17 @@ VideoRenderPass::SetupPipeline()
       mDevice->SetPixelShader(PixelShaderID::TexturedVertexNV12);
     mDevice->SetPSTexturesNV12(0, mTexture);
     break;
   default:
     MOZ_ASSERT_UNREACHABLE("Unknown video format");
     break;
   }
 
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, mFilter);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
   mDevice->SetPSConstantBuffer(1, ps1);
 }
 
 RenderViewPass::RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mParentView(nullptr)
 {
   mAssignedLayer = aItem.layer->AsContainerLayerMLGPU();
@@ -826,41 +850,42 @@ RenderViewPass::RenderViewPass(FrameBuil
     // We do not have fast-path rect shaders for blending.
     SetGeometry(aItem, GeometryMode::Polygon);
   } else {
     SetDefaultGeometry(aItem);
   }
 }
 
 bool
-RenderViewPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aInfo)
+RenderViewPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem)
 {
   // We bake in the layer ahead of time, which also guarantees the blend mode
   // is baked in, as well as the geometry requirement.
   if (mAssignedLayer != aLayer) {
     return false;
   }
 
   mSource = mAssignedLayer->GetRenderTarget();
   if (!mSource) {
     return false;
   }
 
-  mParentView = aInfo.view;
+  mParentView = aItem.view;
 
   Txn txn(this);
 
   IntPoint offset = mAssignedLayer->GetTargetOffset();
   IntSize size = mAssignedLayer->GetTargetSize();
 
   // Clamp the visible region to the texture size.
   nsIntRegion visible = mAssignedLayer->GetShadowVisibleRegion().ToUnknownRegion();
   visible.AndWith(IntRect(offset, size));
 
-  if (!AddItems(txn, aInfo, visible, offset, size)) {
+  Info info(aItem, mAssignedLayer);
+  if (!AddItems(txn, info, visible)) {
     return false;
   }
   return txn.Commit();
 }
 
 float
 RenderViewPass::GetOpacity() const
 {
--- a/gfx/layers/mlgpu/RenderPassMLGPU.h
+++ b/gfx/layers/mlgpu/RenderPassMLGPU.h
@@ -287,63 +287,61 @@ protected:
 
 // Shaders which sample from a texture should inherit from this.
 class TexturedRenderPass : public BatchRenderPass<TexturedTraits>
 {
 public:
   explicit TexturedRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
 
 protected:
+  struct Info {
+    Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer);
+    Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer);
+    Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer);
+
+    const ItemInfo& item;
+    gfx::IntSize textureSize;
+    gfx::Point destOrigin;
+    Maybe<gfx::Size> scale;
+    bool decomposeIntoNoRepeatRects;
+  };
+
   // Add a set of draw rects based on a visible region. The texture size and
   // scaling factor are used to compute uv-coordinates.
   //
   // The origin is the offset from the draw rect to the layer bounds. You can
   // also think of it as the translation from layer space into texture space,
   // pre-scaling. For example, ImageLayers use the texture bounds as their
   // draw rect, so the origin will be (0, 0). ContainerLayer intermediate
   // surfaces, on the other hand, are relative to the target offset of the
   // layer. In all cases the visible region may be partially occluded, so
   // knowing the true origin is important.
   bool AddItems(Txn& aTxn,
-                const ItemInfo& aInfo,
-                const nsIntRegion& aDrawRects,
-                const gfx::IntPoint& aDestOrigin,
-                const gfx::IntSize& aTextureSize,
-                const Maybe<gfx::Size>& aScale = Nothing())
+                const Info& aInfo,
+                const nsIntRegion& aDrawRegion)
   {
-    gfx::Point origin(aDestOrigin);
-    for (auto iter = aDrawRects.RectIter(); !iter.Done(); iter.Next()) {
+    for (auto iter = aDrawRegion.RectIter(); !iter.Done(); iter.Next()) {
       gfx::Rect drawRect = gfx::Rect(iter.Get());
-      if (!AddItem(aTxn, aInfo, drawRect, origin, aTextureSize, aScale)) {
+      if (!AddItem(aTxn, aInfo, drawRect)) {
         return false;
       }
     }
     return true;
   }
 
 private:
   // Add a draw instance to the given destination rect. Texture coordinates
   // are built from the given texture size, optional scaling factor, and
   // texture origin relative to the draw rect. This will ultimately call
   // AddClippedItem, potentially clipping the draw rect if needed.
-  bool AddItem(Txn& aTxn,
-               const ItemInfo& aInfo,
-               const gfx::Rect& aDrawRect,
-               const gfx::Point& aDestOrigin,
-               const gfx::IntSize& aTextureSize,
-               const Maybe<gfx::Size>& aTextureScale = Nothing());
+  bool AddItem(Txn& aTxn, const Info& aInfo, const gfx::Rect& aDrawRect);
 
   // Add an item that has gone through any necessary clipping already. This
   // is the final destination for handling textured items.
-  bool AddClippedItem(Txn& aTxn,
-                      const ItemInfo& aInfo,
-                      const gfx::Rect& aDrawRect,
-                      const gfx::Point& aDestOrigin,
-                      const gfx::IntSize& aTextureSize,
-                      const Maybe<gfx::Size>& aScale);
+  bool AddClippedItem(Txn& aTxn, const Info& aInfo, const gfx::Rect& aDrawRect);
 
 protected:
   TextureFlags mTextureFlags;
 };
 
 // This is only available when MLGDevice::CanUseClearView returns true.
 class ClearViewPass final : public RenderPassMLGPU
 {
@@ -398,17 +396,17 @@ private:
   void SetupPipeline() override;
   float GetOpacity() const override {
     return mOpacity;
   }
   Maybe<MLGBlendState> GetBlendState() const override;
 
 private:
   RefPtr<TextureSource> mTexture;
-  gfx::SamplingFilter mFilter;
+  SamplerMode mSamplerMode;
   float mOpacity;
 };
 
 class ComponentAlphaPass final : public TexturedRenderPass
 {
 public:
   explicit ComponentAlphaPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
 
@@ -444,17 +442,17 @@ private:
   void SetupPipeline() override;
   float GetOpacity() const override {
     return mOpacity;
   }
 
 private:
   RefPtr<TextureHost> mHost;
   RefPtr<TextureSource> mTexture;
-  gfx::SamplingFilter mFilter;
+  SamplerMode mSamplerMode;
   float mOpacity;
 };
 
 class RenderViewPass final : public TexturedRenderPass
 {
 public:
   RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
 
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -91,30 +91,30 @@ StackingContextHelper::StackingContextHe
   , mYScale(1.0f)
 {
   nsRect visibleRect;
 
   if (aTransformPtr) {
     mTransform = *aTransformPtr;
   }
 
+  // Apply the inherited scale from parent
+  mTransform.PostScale(aParentSC.mXScale, aParentSC.mYScale, 1.0);
+  mTransform.NudgeToIntegersFixedEpsilon();
+
   if (aPerspectivePtr) {
     mHasPerspectiveTransform = true;
   }
 
   bool is2d = !aTransformPtr || (aTransformPtr->Is2D() && !aPerspectivePtr);
   if (is2d) {
     nsRect itemBounds = aDisplayList->GetClippedBoundsWithRespectToASR(aDisplayListBuilder, aItem->GetActiveScrolledRoot());
     nsRect childrenVisible = aItem->GetVisibleRectForChildren();
     visibleRect = itemBounds.Intersect(childrenVisible);
 
-    // Apply the inherited scale from parent
-    mTransform.PostScale(aParentSC.mXScale, aParentSC.mYScale, 1.0);
-    mTransform.NudgeToIntegersFixedEpsilon();
-
     // Calculate the correct scale for current stacking context
     gfx::Size scale = mTransform.As2D().ScaleFactors(true);
 
     // Restore the scale to default if the scale is too small
     if (FuzzyEqualsAdditive(scale.width, 0.0f) ||
         FuzzyEqualsAdditive(scale.height, 0.0f)) {
       scale = gfx::Size(1.0f, 1.0f);
     }
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -182,29 +182,29 @@ VRManagerParent::RegisterVRManagerInComp
   aVRManager->RegisterWithManager();
 }
 
 /*static*/ VRManagerParent*
 VRManagerParent::CreateSameProcess()
 {
   MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
   RefPtr<VRManagerParent> vmp = new VRManagerParent(base::GetCurrentProcId(), false);
-  vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+  vmp->mCompositorThreadHolder = new layers::CompositorThreadHolderDebug("VRManagerSame");
   vmp->mSelfRef = vmp;
   loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get()));
   return vmp.get();
 }
 
 bool
 VRManagerParent::CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint)
 {
   MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
 
   RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid(), false);
-  vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+  vmp->mCompositorThreadHolder = new layers::CompositorThreadHolderDebug("VRManager");
   loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>(
     "gfx::VRManagerParent::Bind",
     vmp,
     &VRManagerParent::Bind,
     Move(aEndpoint)));
   return true;
 }
 
@@ -223,17 +223,19 @@ VRManagerParent::ActorDestroy(ActorDestr
     NewRunnableMethod("gfx::VRManagerParent::DeferredDestroy",
                       this,
                       &VRManagerParent::DeferredDestroy));
 }
 
 void
 VRManagerParent::OnChannelConnected(int32_t aPid)
 {
-  mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+  mCompositorThreadHolder =
+    new layers::CompositorThreadHolderDebug(IsSameProcess() ? "VRManagerSame"
+                                                            : "VRManager");
 }
 
 mozilla::ipc::IPCResult
 VRManagerParent::RecvRefreshDisplays()
 {
   // This is called to refresh the VR Displays for Navigator.GetVRDevices().
   // We must pass "true" to VRManager::RefreshVRDisplays()
   // to ensure that the promise returned by Navigator.GetVRDevices
--- a/gfx/vr/ipc/VRManagerParent.h
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -119,17 +119,17 @@ private:
 
   void DeferredDestroy();
 
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   RefPtr<VRManagerParent> mSelfRef;
 
   // Keep the compositor thread alive, until we have destroyed ourselves.
-  RefPtr<layers::CompositorThreadHolder> mCompositorThreadHolder;
+  RefPtr<layers::CompositorThreadHolderDebug> mCompositorThreadHolder;
 
   // Keep the VRManager alive, until we have destroyed ourselves.
   RefPtr<VRManager> mVRManagerHolder;
   nsRefPtrHashtable<nsUint32HashKey, impl::VRDisplayPuppet> mVRDisplayTests;
   nsRefPtrHashtable<nsUint32HashKey, impl::VRControllerPuppet> mVRControllerTests;
   uint32_t mDisplayTestID;
   uint32_t mControllerTestID;
   bool mHaveEventListener;
--- a/image/StreamingLexer.h
+++ b/image/StreamingLexer.h
@@ -424,17 +424,20 @@ public:
     // Since the current iterator has already advanced to this point, we
     // know that the state can only be READY or COMPLETE. That does not mean
     // everything is stored in a single chunk, and may require multiple Advance
     // calls to get where we want to be.
     SourceBufferIterator::State state;
     do {
       state = other.Advance(pos);
       if (state != SourceBufferIterator::READY) {
-        MOZ_ASSERT_UNREACHABLE("Cannot advance to existing position");
+        // The only way we should fail to advance over data we already seen is
+        // if we hit an error while inserting data into the buffer. This will
+        // cause an early exit.
+        MOZ_ASSERT(NS_FAILED(other.CompletionStatus()));
         return Nothing();
       }
       MOZ_ASSERT(pos >= other.Length());
       pos -= other.Length();
     } while (pos > 0);
 
     // Force the data pointer to be where we expect it to be.
     state = other.Advance(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/array-push-multiple-with-funapply.js
@@ -0,0 +1,80 @@
+// |jit-test| --no-threads
+
+// This test case check's Ion ability to inline Array.prototype.push, when
+// fun.apply is used and inlined with the set of arguments of the current
+// function. Note, that the following are not equivalent in case of failures:
+//
+//   arr = [];
+//   arr.push(1,2,3); // OOM ---> arr == []
+//
+//   arr = [];
+//   arr.push(1);
+//   arr.push(2); // OOM --> arr == [1]
+//   arr.push(3);
+
+function canIoncompile() {
+  while (true) {
+    var i = inIon();
+    if (i)
+      return i;
+  }
+}
+
+if (!("oomAtAllocation" in this))
+  quit();
+if (canIoncompile() != true)
+  quit();
+if ("gczeal" in this)
+  gczeal(0);
+
+function pushLimits(limit, offset) {
+  function pusher() {
+    Array.prototype.push.apply(arr, arguments)
+  }
+  var arr = [0,1,2,3,4,5,6,7];
+  arr.length = offset;
+  var l = arr.length;
+  var was = inIon();
+  oomAtAllocation(limit);
+  try {
+    for (var i = 0; i < 100; i++)
+      pusher(0,1,2,3,4,5,6,7);
+  } catch (e) {
+    // Catch OOM.
+  }
+  resetOOMFailure();
+  assertEq(arr.length % 8, l);
+  // Check for a bailout.
+  var is = inIon();
+  return was ? is ? 1 : 2 : 0;
+}
+
+
+
+// We need this limit to be high enough to be able to OSR in the for-loop of
+// pushLimits.
+var limit = 1024 * 1024 * 1024;
+while(true) {
+  var res = pushLimits(limit, 0);
+  print(limit, res);
+
+  if (res == 0) {
+    limit = 1024 * 1024 * 1024;
+  } else if (res == 1) { // Started and finished in Ion.
+    // We want to converge quickly to a state where the memory is limited
+    // enough to cause failures in array.prototype.push.
+    limit = (limit / 1.5) | 0;
+    if (limit == 0) // If we are not in the Jit.
+      break;
+  } else if (res == 2) { // Started in Ion, and finished in Baseline.
+    if (limit < 10) {
+      // This is used to offset the OOM location, such that we can test
+      // each steps of the Array.push function, when it is jitted.
+      for (var off = 1; off < 8; off++)
+        pushLimits(limit, off);
+    }
+    if (limit == 1)
+      break;
+    limit--;
+  }
+}
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3726,33 +3726,26 @@ IonBuilder::inlineScriptedCall(CallInfo&
     MOZ_ASSERT(IsIonInlinablePC(pc));
 
     MBasicBlock::BackupPoint backup(current);
     if (!backup.init(alloc()))
         return abort(AbortReason::Alloc);
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY.
-    uint32_t depth = current->stackDepth() + callInfo.numFormals();
-    if (depth > current->nslots()) {
-        if (!current->increaseSlots(depth - current->nslots()))
-            return abort(AbortReason::Alloc);
-    }
-
     // Create new |this| on the caller-side for inlined constructors.
     if (callInfo.constructing()) {
         MDefinition* thisDefn = createThis(target, callInfo.fun(), callInfo.getNewTarget());
         if (!thisDefn)
             return abort(AbortReason::Alloc);
         callInfo.setThis(thisDefn);
     }
 
     // Capture formals in the outer resume point.
-    callInfo.pushFormals(current);
+    MOZ_TRY(callInfo.pushFormals(this, current));
 
     MResumePoint* outerResumePoint =
         MResumePoint::New(alloc(), current, pc, MResumePoint::Outer);
     if (!outerResumePoint)
         return abort(AbortReason::Alloc);
     current->setOuterResumePoint(outerResumePoint);
 
     // Pop formals again, except leave |fun| on stack for duration of call.
@@ -4405,17 +4398,17 @@ AbortReasonOr<Ok>
 IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasicBlock* dispatchBlock)
 {
     // Generate a new block with all arguments on-stack.
     MBasicBlock* fallbackBlock;
     MOZ_TRY_VAR(fallbackBlock, newBlock(dispatchBlock, pc));
     graph().addBlock(fallbackBlock);
 
     // Create a new CallInfo to track modified state within this block.
-    CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
+    CallInfo fallbackInfo(alloc(), pc, callInfo.constructing(), callInfo.ignoresReturnValue());
     if (!fallbackInfo.init(callInfo))
         return abort(AbortReason::Alloc);
     fallbackInfo.popFormals(fallbackBlock);
 
     // Generate an MCall, which uses stateful |current|.
     MOZ_TRY(setCurrentAndSpecializePhis(fallbackBlock));
     MOZ_TRY(makeCall(target, fallbackInfo));
 
@@ -4442,17 +4435,17 @@ IonBuilder::inlineObjectGroupFallback(Ca
     MOZ_ASSERT_IF(callInfo.fun()->isTypeBarrier(), cache->hasOneUse());
 
     // This means that no resume points yet capture the MGetPropertyCache,
     // so everything from the MGetPropertyCache up until the call is movable.
     // We now move the MGetPropertyCache and friends into a fallback path.
     MOZ_ASSERT(cache->idempotent());
 
     // Create a new CallInfo to track modified state within the fallback path.
-    CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
+    CallInfo fallbackInfo(alloc(), pc, callInfo.constructing(), callInfo.ignoresReturnValue());
     if (!fallbackInfo.init(callInfo))
         return abort(AbortReason::Alloc);
 
     // Capture stack prior to the call operation. This captures the function.
     MResumePoint* preCallResumePoint =
         MResumePoint::New(alloc(), dispatchBlock, pc, MResumePoint::ResumeAt);
     if (!preCallResumePoint)
         return abort(AbortReason::Alloc);
@@ -4528,17 +4521,17 @@ IonBuilder::inlineCalls(CallInfo& callIn
     MOZ_ASSERT(IsIonInlinablePC(pc));
     MOZ_ASSERT(choiceSet.length() == targets.length());
     MOZ_ASSERT_IF(!maybeCache, targets.length() >= 2);
     MOZ_ASSERT_IF(maybeCache, targets.length() >= 1);
     MOZ_ASSERT_IF(maybeCache, maybeCache->value()->type() == MIRType::Object);
 
     MBasicBlock* dispatchBlock = current;
     callInfo.setImplicitlyUsedUnchecked();
-    callInfo.pushFormals(dispatchBlock);
+    MOZ_TRY(callInfo.pushFormals(this, dispatchBlock));
 
     // Patch any InlinePropertyTable to only contain functions that are
     // inlineable. The InlinePropertyTable will also be patched at the end to
     // exclude native functions that vetoed inlining.
     if (maybeCache) {
         InlinePropertyTable* propTable = maybeCache->propTable();
         propTable->trimToTargets(targets);
         if (propTable->numEntries() == 0)
@@ -4621,17 +4614,17 @@ IonBuilder::inlineCalls(CallInfo& callIn
         dispatchBlock->add(funcDef);
 
         // Use the inlined callee in the inline resume point and on stack.
         int funIndex = inlineBlock->entryResumePoint()->stackDepth() - callInfo.numFormals();
         inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
         inlineBlock->rewriteSlot(funIndex, funcDef);
 
         // Create a new CallInfo to track modified state within the inline block.
-        CallInfo inlineInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
+        CallInfo inlineInfo(alloc(), pc, callInfo.constructing(), callInfo.ignoresReturnValue());
         if (!inlineInfo.init(callInfo))
             return abort(AbortReason::Alloc);
         inlineInfo.popFormals(inlineBlock);
         inlineInfo.setFun(funcDef);
 
         if (maybeCache) {
             // Assign the 'this' value a TypeSet specialized to the groups that
             // can generate this inlining target.
@@ -5068,17 +5061,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
 
     int calleeDepth = -((int)argc + 2);
     int funcDepth = -((int)argc + 1);
 
     // If |Function.prototype.call| may be overridden, don't optimize callsite.
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction* native = getSingleCallTarget(calleeTypes);
     if (!native || !native->isNative() || native->native() != &fun_call) {
-        CallInfo callInfo(alloc(), /* constructing = */ false,
+        CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                           /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
     current->peek(calleeDepth)->setImplicitlyUsedUnchecked();
 
     // Extract call target.
@@ -5094,17 +5087,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
     // Pushing is safe here, since one stack slot has been removed.
     if (zeroArguments) {
         pushConstant(UndefinedValue());
     } else {
         // |this| becomes implicit in the call.
         argc -= 1;
     }
 
-    CallInfo callInfo(alloc(), /* constructing = */ false,
+    CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                       /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, argc))
         return abort(AbortReason::Alloc);
 
     // Try to inline the call.
     if (!zeroArguments) {
         InliningDecision decision = makeInliningDecision(target, callInfo);
         switch (decision) {
@@ -5130,17 +5123,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
 AbortReasonOr<Ok>
 IonBuilder::jsop_funapply(uint32_t argc)
 {
     int calleeDepth = -((int)argc + 2);
 
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction* native = getSingleCallTarget(calleeTypes);
     if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) {
-        CallInfo callInfo(alloc(), /* constructing = */ false,
+        CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                           /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
@@ -5160,17 +5153,17 @@ IonBuilder::jsop_funapply(uint32_t argc)
             objTypes &&
             objTypes->getKnownClass(constraints()) == &ArrayObject::class_ &&
             !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW) &&
             ElementAccessIsPacked(constraints(), argument))
         {
             return jsop_funapplyarray(argc);
         }
 
-        CallInfo callInfo(alloc(), /* constructing = */ false,
+        CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                           /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
 
     if ((!native || !native->isNative() ||
         native->native() != fun_apply) &&
@@ -5307,17 +5300,17 @@ IonBuilder::jsop_funapplyarguments(uint3
     }
 
     // When inlining we have the arguments the function gets called with
     // and can optimize even more, by just calling the functions with the args.
     // We also try this path when doing the definite properties analysis, as we
     // can inline the apply() target and don't care about the actual arguments
     // that were passed in.
 
-    CallInfo callInfo(alloc(), /* constructing = */ false,
+    CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                       /* ignoresReturnValue = */ BytecodeIsPopped(pc));
 
     // Vp
     MDefinition* vp = current->pop();
     vp->setImplicitlyUsedUnchecked();
 
     // Arguments
     if (inliningDepth_) {
@@ -5378,17 +5371,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
     int calleeDepth = -((int)argc + 2 + constructing);
 
     // Acquire known call target if existent.
     InliningTargets targets(alloc());
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     if (calleeTypes)
         MOZ_TRY(getPolyCallTargets(calleeTypes, constructing, targets, 4));
 
-    CallInfo callInfo(alloc(), constructing, ignoresReturnValue);
+    CallInfo callInfo(alloc(), pc, constructing, ignoresReturnValue);
     if (!callInfo.init(current, argc))
         return abort(AbortReason::Alloc);
 
     // Try inlining
     InliningStatus status;
     MOZ_TRY_VAR(status, inlineCallsite(targets, callInfo));
     if (status == InliningStatus_Inlined)
         return Ok();
@@ -5630,17 +5623,17 @@ IonBuilder::jsop_eval(uint32_t argc)
             return abort(AbortReason::Disable, "Direct eval with more than one argument");
 
         if (!info().funMaybeLazy())
             return abort(AbortReason::Disable, "Direct eval in global code");
 
         if (info().funMaybeLazy()->isArrow())
             return abort(AbortReason::Disable, "Direct eval from arrow function");
 
-        CallInfo callInfo(alloc(), /* constructing = */ false,
+        CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                           /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         callInfo.setImplicitlyUsedUnchecked();
 
         callInfo.fun()->setImplicitlyUsedUnchecked();
 
         MDefinition* envChain = current->environmentChain();
@@ -5669,17 +5662,17 @@ IonBuilder::jsop_eval(uint32_t argc)
             if (StringEqualsAscii(atom, "()")) {
                 MDefinition* name = string->getOperand(0);
                 MInstruction* dynamicName = MGetDynamicName::New(alloc(), envChain, name);
                 current->add(dynamicName);
 
                 current->push(dynamicName);
                 current->push(constant(UndefinedValue())); // thisv
 
-                CallInfo evalCallInfo(alloc(), /* constructing = */ false,
+                CallInfo evalCallInfo(alloc(), pc, /* constructing = */ false,
                                       /* ignoresReturnValue = */ BytecodeIsPopped(pc));
                 if (!evalCallInfo.init(current, /* argc = */ 0))
                     return abort(AbortReason::Alloc);
 
                 return makeCall(nullptr, evalCallInfo);
             }
         }
 
@@ -11096,17 +11089,17 @@ IonBuilder::getPropTryCommonGetter(bool*
 
     // Make sure there's enough room
     if (!current->ensureHasSlots(2))
         return abort(AbortReason::Alloc);
     current->push(constant(ObjectValue(*commonGetter)));
 
     current->push(obj);
 
-    CallInfo callInfo(alloc(), /* constructing = */ false,
+    CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                       /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, 0))
         return abort(AbortReason::Alloc);
 
     if (commonGetter->isNative()) {
         InliningStatus status;
         MOZ_TRY_VAR(status, inlineNativeGetter(callInfo, commonGetter));
         switch (status) {
@@ -11637,17 +11630,17 @@ IonBuilder::setPropTryCommonSetter(bool*
         return abort(AbortReason::Alloc);
 
     current->push(constant(ObjectValue(*commonSetter)));
     current->push(obj);
     current->push(value);
 
     // Call the setter. Note that we have to push the original value, not
     // the setter's return value.
-    CallInfo callInfo(alloc(), /* constructing = */ false,
+    CallInfo callInfo(alloc(), pc, /* constructing = */ false,
                       /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, 1))
         return abort(AbortReason::Alloc);
 
     // Ensure that we know we are calling a setter in case we inline it.
     callInfo.markAsSetter();
 
     // Inline the setter if we can.
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -1190,26 +1190,28 @@ class CallInfo
     MDefinitionVector args_;
 
     bool constructing_:1;
 
     // True if the caller does not use the return value.
     bool ignoresReturnValue_:1;
 
     bool setter_:1;
+    bool apply_:1;
 
   public:
-    CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue)
+    CallInfo(TempAllocator& alloc, jsbytecode* pc, bool constructing, bool ignoresReturnValue)
       : fun_(nullptr),
         thisArg_(nullptr),
         newTargetArg_(nullptr),
         args_(alloc),
         constructing_(constructing),
         ignoresReturnValue_(ignoresReturnValue),
-        setter_(false)
+        setter_(false),
+        apply_(JSOp(*pc) == JSOP_FUNAPPLY)
     { }
 
     MOZ_MUST_USE bool init(CallInfo& callInfo) {
         MOZ_ASSERT(constructing_ == callInfo.constructing());
 
         fun_ = callInfo.fun();
         thisArg_ = callInfo.thisArg();
         ignoresReturnValue_ = callInfo.ignoresReturnValue();
@@ -1243,25 +1245,36 @@ class CallInfo
 
         return true;
     }
 
     void popFormals(MBasicBlock* current) {
         current->popn(numFormals());
     }
 
-    void pushFormals(MBasicBlock* current) {
+    AbortReasonOr<Ok> pushFormals(MIRGenerator* mir, MBasicBlock* current) {
+        // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY.
+        if (apply_) {
+            uint32_t depth = current->stackDepth() + numFormals();
+            if (depth > current->nslots()) {
+                if (!current->increaseSlots(depth - current->nslots()))
+                    return mir->abort(AbortReason::Alloc);
+            }
+        }
+
         current->push(fun());
         current->push(thisArg());
 
         for (uint32_t i = 0; i < argc(); i++)
             current->push(getArg(i));
 
         if (constructing())
             current->push(getNewTarget());
+
+        return Ok();
     }
 
     uint32_t argc() const {
         return args_.length();
     }
     uint32_t numFormals() const {
         return argc() + 2 + constructing();
     }
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -873,17 +873,17 @@ IonBuilder::inlineArrayPush(CallInfo& ca
         truncate->setRecoveredOnBailout();
 
         current->add(elements);
         current->add(length);
         current->add(truncate);
 
         // Restore the stack, such that resume points are created with the stack
         // as it was before the call.
-        callInfo.pushFormals(current);
+        MOZ_TRY(callInfo.pushFormals(this, current));
     }
 
     MInstruction* ins = nullptr;
     for (uint32_t i = 0; i < callInfo.argc(); i++) {
         MDefinition* value = callInfo.getArg(i);
         if (toDouble) {
             MInstruction* valueDouble = MToDouble::New(alloc(), value);
             current->add(valueDouble);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -8241,18 +8241,17 @@ PresShell::HandleEventInternal(WidgetEve
     case eDragLeave:
     case eDragOver:
     case eDrop: {
       // After any drag event other than dragstart (which is handled separately,
       // as we need to collect the data first), the DataTransfer needs to be
       // made protected, and then disconnected.
       DataTransfer* dataTransfer = aEvent->AsDragEvent()->mDataTransfer;
       if (dataTransfer) {
-        dataTransfer->SetMode(DataTransfer::Mode::Protected);
-        dataTransfer->ClearAll();
+        dataTransfer->Disconnect();
       }
       break;
     }
     default:
       break;
     }
 
     if (aEvent->IsTrusted() && aEvent->mTimeStamp > mLastOSWake) {
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -746,23 +746,23 @@ ConstructBorderRenderer(nsPresContext* a
                "Should not skip sides for box-decoration-break:clone except "
                "::first-letter/line continuations or other frame types that "
                "don't have borders but those shouldn't reach this point. "
                "Overflow containers do reach this point though.");
     border.ApplySkipSides(aSkipSides);
   }
 
   // Convert to dev pixels.
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-  Rect joinedBorderAreaPx = NSRectToRect(joinedBorderArea, twipsPerPixel);
-  Float borderWidths[4] = { Float(border.top) / twipsPerPixel,
-                                   Float(border.right) / twipsPerPixel,
-                                   Float(border.bottom) / twipsPerPixel,
-                                   Float(border.left) / twipsPerPixel };
-  Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
+  nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
+  Rect joinedBorderAreaPx = NSRectToRect(joinedBorderArea, oneDevPixel);
+  Float borderWidths[4] = { Float(border.top) / oneDevPixel,
+                                   Float(border.right) / oneDevPixel,
+                                   Float(border.bottom) / oneDevPixel,
+                                   Float(border.left) / oneDevPixel };
+  Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);
 
   uint8_t borderStyles[4];
   nscolor borderColors[4];
   nsBorderColors* compositeColors[4];
 
   // pull out styles, colors, composite colors
   NS_FOR_CSS_SIDES (i) {
     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
@@ -996,25 +996,25 @@ nsCSSRendering::CreateBorderRendererForO
   nsRect outerRect = innerRect;
   outerRect.Inflate(width, width);
 
   // get the radius for our outline
   nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(),
                                outerRect.Size(), Sides(), twipsRadii);
 
   // Get our conversion values
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
 
   // get the outer rectangles
-  Rect oRect(NSRectToRect(outerRect, twipsPerPixel));
+  Rect oRect(NSRectToRect(outerRect, oneDevPixel));
 
   // convert the radii
   nsMargin outlineMargin(width, width, width, width);
   RectCornerRadii outlineRadii;
-  ComputePixelRadii(twipsRadii, twipsPerPixel, &outlineRadii);
+  ComputePixelRadii(twipsRadii, oneDevPixel, &outlineRadii);
 
   uint8_t outlineStyle = ourOutline->mOutlineStyle;
   if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO) {
     if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
       nsITheme* theme = aPresContext->GetTheme();
       if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                               NS_THEME_FOCUS_OUTLINE)) {
         theme->DrawWidgetBackground(aRenderingContext, aForFrame,
@@ -1039,21 +1039,21 @@ nsCSSRendering::CreateBorderRendererForO
   nscolor outlineColor =
     aStyleContext->GetVisitedDependentColor(&nsStyleOutline::mOutlineColor);
   nscolor outlineColors[4] = { outlineColor,
                                outlineColor,
                                outlineColor,
                                outlineColor };
 
   // convert the border widths
-  Float outlineWidths[4] = { Float(width) / twipsPerPixel,
-                             Float(width) / twipsPerPixel,
-                             Float(width) / twipsPerPixel,
-                             Float(width) / twipsPerPixel };
-  Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
+  Float outlineWidths[4] = { Float(width) / oneDevPixel,
+                             Float(width) / oneDevPixel,
+                             Float(width) / oneDevPixel,
+                             Float(width) / oneDevPixel };
+  Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);
 
   nsIDocument* document = nullptr;
   nsIContent* content = aForFrame->GetContent();
   if (content) {
     document = content->OwnerDoc();
   }
 
   DrawTarget* dt = aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
@@ -1437,24 +1437,24 @@ nsCSSRendering::GetShadowRect(const nsRe
 }
 
 bool
 nsCSSRendering::GetBorderRadii(const nsRect& aFrameRect,
                                const nsRect& aBorderRect,
                                nsIFrame* aFrame,
                                RectCornerRadii& aOutRadii)
 {
-  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
+  const nscoord oneDevPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
   nscoord twipsRadii[8];
   NS_ASSERTION(aBorderRect.Size() == aFrame->VisualBorderRectRelativeToSelf().Size(),
               "unexpected size");
   nsSize sz = aFrameRect.Size();
   bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
   if (hasBorderRadius) {
-    ComputePixelRadii(twipsRadii, twipsPerPixel, &aOutRadii);
+    ComputePixelRadii(twipsRadii, oneDevPixel, &aOutRadii);
   }
 
   return hasBorderRadius;
 }
 
 void
 nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
                                     gfxContext& aRenderingContext,
@@ -1473,44 +1473,44 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
   bool nativeTheme = HasBoxShadowNativeTheme(aForFrame, hasBorderRadius);
   const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
 
   nsRect frameRect = GetShadowRect(aFrameArea, nativeTheme, aForFrame);
 
   // Get any border radius, since box-shadow must also have rounded corners if
   // the frame does.
   RectCornerRadii borderRadii;
-  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  const nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
   if (hasBorderRadius) {
     nscoord twipsRadii[8];
     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
                  "unexpected size");
     nsSize sz = frameRect.Size();
     hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
     if (hasBorderRadius) {
-      ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
+      ComputePixelRadii(twipsRadii, oneDevPixel, &borderRadii);
     }
   }
 
 
   // We don't show anything that intersects with the frame we're blurring on. So tell the
   // blurrer not to do unnecessary work there.
-  gfxRect skipGfxRect = ThebesRect(NSRectToRect(frameRect, twipsPerPixel));
+  gfxRect skipGfxRect = ThebesRect(NSRectToRect(frameRect, oneDevPixel));
   skipGfxRect.Round();
   bool useSkipGfxRect = true;
   if (nativeTheme) {
     // Optimize non-leaf native-themed frames by skipping computing pixels
     // in the padding-box. We assume the padding-box is going to be painted
     // opaquely for non-leaf frames.
     // XXX this may not be a safe assumption; we should make this go away
     // by optimizing box-shadow drawing more for the cases where we don't have a skip-rect.
     useSkipGfxRect = !aForFrame->IsLeaf();
     nsRect paddingRect =
       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
-    skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
+    skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, oneDevPixel);
   } else if (hasBorderRadius) {
     skipGfxRect.Deflate(gfxMargin(
         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
   }
 
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
@@ -1524,35 +1524,35 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       shadowRect.Inflate(shadowItem->mSpread, shadowItem->mSpread);
     }
 
     // shadowRect won't include the blur, so make an extra rect here that includes the blur
     // for use in the even-odd rule below.
     nsRect shadowRectPlusBlur = shadowRect;
     nscoord blurRadius = shadowItem->mRadius;
     shadowRectPlusBlur.Inflate(
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
+      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, oneDevPixel));
 
     Rect shadowGfxRectPlusBlur =
-      NSRectToRect(shadowRectPlusBlur, twipsPerPixel);
+      NSRectToRect(shadowRectPlusBlur, oneDevPixel);
     shadowGfxRectPlusBlur.RoundOut();
     MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
 
     Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
 
     if (nativeTheme) {
       nsContextBoxBlur blurringArea;
 
       // When getting the widget shape from the native theme, we're going
       // to draw the widget into the shadow surface to create a mask.
       // We need to ensure that there actually *is* a shadow surface
       // and that we're not going to draw directly into aRenderingContext.
       gfxContext* shadowContext =
         blurringArea.Init(shadowRect, shadowItem->mSpread, blurRadius,
-                          twipsPerPixel, &aRenderingContext, aDirtyRect,
+                          oneDevPixel, &aRenderingContext, aDirtyRect,
                           useSkipGfxRect ? &skipGfxRect : nullptr,
                           nsContextBoxBlur::FORCE_MASK);
       if (!shadowContext)
         continue;
 
       MOZ_ASSERT(shadowContext == blurringArea.GetContext());
 
       aRenderingContext.Save();
@@ -1583,17 +1583,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
           styleDisplay->mAppearance, aFrameArea, nativeRect);
 
       blurringArea.DoPaint();
       aRenderingContext.Restore();
     } else {
       aRenderingContext.Save();
 
       {
-        Rect innerClipRect = NSRectToRect(frameRect, twipsPerPixel);
+        Rect innerClipRect = NSRectToRect(frameRect, oneDevPixel);
         if (!MaybeSnapToDevicePixels(innerClipRect, aDrawTarget, true)) {
           innerClipRect.Round();
         }
 
         // Clip out the interior of the frame's border edge so that the shadow
         // is only painted outside that area.
         RefPtr<PathBuilder> builder =
           aDrawTarget.CreatePathBuilder(FillRule::FILL_EVEN_ODD);
@@ -1639,32 +1639,32 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       fragmentClip = fragmentClip.Intersect(aDirtyRect);
       aRenderingContext.
         Clip(NSRectToSnappedRect(fragmentClip,
                                  aForFrame->PresContext()->AppUnitsPerDevPixel(),
                                  aDrawTarget));
 
       RectCornerRadii clipRectRadii;
       if (hasBorderRadius) {
-        Float spreadDistance = Float(shadowItem->mSpread) / twipsPerPixel;
+        Float spreadDistance = Float(shadowItem->mSpread) / oneDevPixel;
 
         Float borderSizes[4];
 
         borderSizes[eSideLeft] = spreadDistance;
         borderSizes[eSideTop] = spreadDistance;
         borderSizes[eSideRight] = spreadDistance;
         borderSizes[eSideBottom] = spreadDistance;
 
         nsCSSBorderRenderer::ComputeOuterRadii(borderRadii, borderSizes,
             &clipRectRadii);
 
       }
       nsContextBoxBlur::BlurRectangle(&aRenderingContext,
                                       shadowRect,
-                                      twipsPerPixel,
+                                      oneDevPixel,
                                       hasBorderRadius ? &clipRectRadii : nullptr,
                                       blurRadius,
                                       gfxShadowColor,
                                       aDirtyRect,
                                       skipGfxRect);
       aRenderingContext.Restore();
     }
 
@@ -1712,29 +1712,29 @@ nsCSSRendering::GetShadowInnerRadii(nsIF
   // Get any border radius, since box-shadow must also have rounded corners
   // if the frame does.
   nscoord twipsRadii[8];
   nsRect frameRect =
     ::BoxDecorationRectForBorder(aFrame, aFrameArea, aFrame->GetSkipSides());
   nsSize sz = frameRect.Size();
   nsMargin border = aFrame->GetUsedBorder();
   bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
-  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
+  const nscoord oneDevPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
 
   RectCornerRadii borderRadii;
 
   hasBorderRadius = GetBorderRadii(frameRect, aFrameArea, aFrame, borderRadii);
   if (hasBorderRadius) {
-    ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
+    ComputePixelRadii(twipsRadii, oneDevPixel, &borderRadii);
 
     Float borderSizes[4] = {
-      Float(border.top) / twipsPerPixel,
-      Float(border.right) / twipsPerPixel,
-      Float(border.bottom) / twipsPerPixel,
-      Float(border.left) / twipsPerPixel
+      Float(border.top) / oneDevPixel,
+      Float(border.right) / oneDevPixel,
+      Float(border.bottom) / oneDevPixel,
+      Float(border.left) / oneDevPixel
     };
     nsCSSBorderRenderer::ComputeInnerRadii(borderRadii,
                                            borderSizes,
                                            &aOutInnerRadii);
   }
 
   return hasBorderRadius;
 }
@@ -1755,45 +1755,45 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
 
   nsRect paddingRect = GetBoxShadowInnerPaddingRect(aForFrame, aFrameArea);
 
   RectCornerRadii innerRadii;
   bool hasBorderRadius = GetShadowInnerRadii(aForFrame,
                                              aFrameArea,
                                              innerRadii);
 
-  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  const nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (!shadowItem->mInset)
       continue;
 
     // shadowPaintRect: the area to paint on the temp surface
     // shadowClipRect: the area on the temporary surface within shadowPaintRect
     //                 that we will NOT paint in
     nscoord blurRadius = shadowItem->mRadius;
     nsMargin blurMargin =
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
+      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, oneDevPixel);
     nsRect shadowPaintRect = paddingRect;
     shadowPaintRect.Inflate(blurMargin);
 
     // Round the spread radius to device pixels (by truncation).
     // This mostly matches what we do for borders, except that we don't round
     // up values between zero and one device pixels to one device pixel.
     // This way of rounding is symmetric around zero, which makes sense for
     // the spread radius.
-    int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel;
+    int32_t spreadDistance = shadowItem->mSpread / oneDevPixel;
     nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
 
     nsRect shadowClipRect = paddingRect;
     shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
     shadowClipRect.Deflate(spreadDistanceAppUnits, spreadDistanceAppUnits);
 
-    Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, twipsPerPixel);
+    Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, oneDevPixel);
     shadowClipGfxRect.Round();
 
     RectCornerRadii clipRectRadii;
     if (hasBorderRadius) {
       // Calculate the radii the inner clipping rect will have
       Float borderSizes[4] = {0, 0, 0, 0};
 
       // See PaintBoxShadowOuter and bug 514670
@@ -1816,57 +1816,57 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
       nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
                                              &clipRectRadii);
     }
 
     // Set the "skip rect" to the area within the frame that we don't paint in,
     // including after blurring.
     nsRect skipRect = shadowClipRect;
     skipRect.Deflate(blurMargin);
-    gfxRect skipGfxRect = nsLayoutUtils::RectToGfxRect(skipRect, twipsPerPixel);
+    gfxRect skipGfxRect = nsLayoutUtils::RectToGfxRect(skipRect, oneDevPixel);
     if (hasBorderRadius) {
       skipGfxRect.Deflate(gfxMargin(
           std::max(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
           std::max(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0));
     }
 
     // When there's a blur radius, gfxAlphaBoxBlur leaves the skiprect area
     // unchanged. And by construction the gfxSkipRect is not touched by the
     // rendered shadow (even after blurring), so those pixels must be completely
     // transparent in the shadow, so drawing them changes nothing.
     DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
 
     // Clip the context to the area of the frame's padding rect, so no part of the
     // shadow is painted outside. Also cut out anything beyond where the inset shadow
     // will be.
-    Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
+    Rect shadowGfxRect = NSRectToRect(paddingRect, oneDevPixel);
     shadowGfxRect.Round();
 
     Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
     aRenderingContext.Save();
 
     // This clips the outside border radius.
     // clipRectRadii is the border radius inside the inset shadow.
     if (hasBorderRadius) {
       RefPtr<Path> roundedRect =
         MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
       aRenderingContext.Clip(roundedRect);
     } else {
       aRenderingContext.Clip(shadowGfxRect);
     }
 
     nsContextBoxBlur insetBoxBlur;
-    gfxRect destRect = nsLayoutUtils::RectToGfxRect(shadowPaintRect, twipsPerPixel);
-    Point shadowOffset(shadowItem->mXOffset / twipsPerPixel,
-                       shadowItem->mYOffset / twipsPerPixel);
+    gfxRect destRect = nsLayoutUtils::RectToGfxRect(shadowPaintRect, oneDevPixel);
+    Point shadowOffset(shadowItem->mXOffset / oneDevPixel,
+                       shadowItem->mYOffset / oneDevPixel);
 
     insetBoxBlur.InsetBoxBlur(&aRenderingContext, ToRect(destRect),
                               shadowClipGfxRect, shadowColor,
                               blurRadius, spreadDistanceAppUnits,
-                              twipsPerPixel, hasBorderRadius,
+                              oneDevPixel, hasBorderRadius,
                               clipRectRadii, ToRect(skipGfxRect),
                               shadowOffset);
     aRenderingContext.Restore();
   }
 }
 
 /* static */
 nsCSSRendering::PaintBGParams
@@ -3295,36 +3295,37 @@ nsCSSRendering::GetBackgroundLayerRect(n
 }
 
 // Begin table border-collapsing section
 // These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
 // At some point, all functions should be unified to include the additional functionality that these provide
 
 static nscoord
 RoundIntToPixel(nscoord aValue,
-                nscoord aTwipsPerPixel,
+                nscoord aOneDevPixel,
                 bool    aRoundDown = false)
 {
-  if (aTwipsPerPixel <= 0)
-    // We must be rendering to a device that has a resolution greater than Twips!
+  if (aOneDevPixel <= 0)
+    // We must be rendering to a device that has a resolution greater than
+    // one device pixel!
     // In that case, aValue is as accurate as it's going to get.
     return aValue;
 
-  nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
-  nscoord extra = aValue % aTwipsPerPixel;
-  nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
+  nscoord halfPixel = NSToCoordRound(aOneDevPixel / 2.0f);
+  nscoord extra = aValue % aOneDevPixel;
+  nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aOneDevPixel - extra) : aValue - extra;
   return finalValue;
 }
 
 static nscoord
 RoundFloatToPixel(float   aValue,
-                  nscoord aTwipsPerPixel,
+                  nscoord aOneDevPixel,
                   bool    aRoundDown = false)
 {
-  return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
+  return RoundIntToPixel(NSToCoordRound(aValue), aOneDevPixel, aRoundDown);
 }
 
 static void SetPoly(const Rect& aRect, Point* poly)
 {
   poly[0].x = aRect.x;
   poly[0].y = aRect.y;
   poly[1].x = aRect.x + aRect.width;
   poly[1].y = aRect.y;
@@ -3335,17 +3336,16 @@ static void SetPoly(const Rect& aRect, P
 }
 
 static void
 DrawDashedSegment(DrawTarget&          aDrawTarget,
                   nsRect               aRect,
                   nscoord              aDashLength,
                   nscolor              aColor,
                   int32_t              aAppUnitsPerDevPixel,
-                  nscoord              aTwipsPerPixel,
                   bool                 aHorizontal)
 {
   ColorPattern color(ToDeviceColor(aColor));
   DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
   StrokeOptions strokeOptions;
 
   Float dash[2];
   dash[0] = Float(aDashLength) / aAppUnitsPerDevPixel;
@@ -3371,27 +3371,27 @@ DrawDashedSegment(DrawTarget&          a
   }
 }
 
 static void
 DrawSolidBorderSegment(DrawTarget&          aDrawTarget,
                        nsRect               aRect,
                        nscolor              aColor,
                        int32_t              aAppUnitsPerDevPixel,
-                       nscoord              aTwipsPerPixel,
                        mozilla::Side        aStartBevelSide = mozilla::eSideTop,
                        nscoord              aStartBevelOffset = 0,
                        mozilla::Side        aEndBevelSide = mozilla::eSideTop,
                        nscoord              aEndBevelOffset = 0)
 {
   ColorPattern color(ToDeviceColor(aColor));
   DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
 
+  nscoord oneDevPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerDevPixel);
   // We don't need to bevel single pixel borders
-  if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
+  if ((aRect.width == oneDevPixel) || (aRect.height == oneDevPixel) ||
       ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
     // simple rectangle
     aDrawTarget.FillRect(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel,
                                              aDrawTarget),
                          color, drawOptions);
   }
   else {
     // polygon with beveling
@@ -3440,55 +3440,54 @@ DrawSolidBorderSegment(DrawTarget&      
     RefPtr<Path> path = builder->Finish();
     aDrawTarget.Fill(path, color, drawOptions);
   }
 }
 
 static void
 GetDashInfo(nscoord  aBorderLength,
             nscoord  aDashLength,
-            nscoord  aTwipsPerPixel,
+            nscoord  aOneDevPixel,
             int32_t& aNumDashSpaces,
             nscoord& aStartDashLength,
             nscoord& aEndDashLength)
 {
   aNumDashSpaces = 0;
   if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
     aStartDashLength = aBorderLength;
     aEndDashLength = 0;
   }
   else {
     aNumDashSpaces = (aBorderLength - aDashLength)/ (2 * aDashLength); // round down
     nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
     if (extra > 0) {
-      nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
+      nscoord half = RoundIntToPixel(extra / 2, aOneDevPixel);
       aStartDashLength += half;
       aEndDashLength += (extra - half);
     }
   }
 }
 
 void
 nsCSSRendering::DrawTableBorderSegment(DrawTarget&   aDrawTarget,
                                        uint8_t       aBorderStyle,
                                        nscolor       aBorderColor,
                                        nscolor       aBGColor,
                                        const nsRect& aBorder,
                                        int32_t       aAppUnitsPerDevPixel,
-                                       int32_t       aAppUnitsPerCSSPixel,
                                        mozilla::Side aStartBevelSide,
                                        nscoord       aStartBevelOffset,
                                        mozilla::Side aEndBevelSide,
                                        nscoord       aEndBevelOffset)
 {
   bool horizontal = ((eSideTop == aStartBevelSide) || (eSideBottom == aStartBevelSide));
-  nscoord twipsPerPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerCSSPixel);
+  nscoord oneDevPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerDevPixel);
   uint8_t ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
 
-  if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
+  if ((oneDevPixel >= aBorder.width) || (oneDevPixel >= aBorder.height) ||
       (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
     // no beveling for 1 pixel border, dash or dot
     aStartBevelOffset = 0;
     aEndBevelOffset = 0;
   }
 
   switch (aBorderStyle) {
   case NS_STYLE_BORDER_STYLE_NONE:
@@ -3498,110 +3497,116 @@ nsCSSRendering::DrawTableBorderSegment(D
   case NS_STYLE_BORDER_STYLE_DOTTED:
   case NS_STYLE_BORDER_STYLE_DASHED:
     {
       nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
       // make the dash length proportional to the border thickness
       dashLength *= (horizontal) ? aBorder.height : aBorder.width;
       // make the min dash length for the ends 1/2 the dash length
       nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle)
-                              ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
-      minDashLength = std::max(minDashLength, twipsPerPixel);
+                              ? RoundFloatToPixel(((float)dashLength) / 2.0f,
+                                                  aAppUnitsPerDevPixel)
+                              : dashLength;
+      minDashLength = std::max(minDashLength, oneDevPixel);
       nscoord numDashSpaces = 0;
       nscoord startDashLength = minDashLength;
       nscoord endDashLength   = minDashLength;
       if (horizontal) {
-        GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces,
-                    startDashLength, endDashLength);
+        GetDashInfo(aBorder.width, dashLength, aAppUnitsPerDevPixel,
+                    numDashSpaces, startDashLength, endDashLength);
         nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
+                               aAppUnitsPerDevPixel);
 
         rect.x += startDashLength + dashLength;
         rect.width = aBorder.width
                      - (startDashLength + endDashLength + dashLength);
         DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
-                          aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
+                          aAppUnitsPerDevPixel, horizontal);
 
         rect.x += rect.width;
         rect.width = endDashLength;
         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
+                               aAppUnitsPerDevPixel);
       }
       else {
-        GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces,
-                    startDashLength, endDashLength);
+        GetDashInfo(aBorder.height, dashLength, aAppUnitsPerDevPixel,
+                    numDashSpaces, startDashLength, endDashLength);
         nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
+                               aAppUnitsPerDevPixel);
 
         rect.y += rect.height + dashLength;
         rect.height = aBorder.height
                       - (startDashLength + endDashLength + dashLength);
         DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
-                          aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
+                          aAppUnitsPerDevPixel, horizontal);
 
         rect.y += rect.height;
         rect.height = endDashLength;
         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
+                               aAppUnitsPerDevPixel);
       }
     }
     break;
   case NS_STYLE_BORDER_STYLE_GROOVE:
     ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
     MOZ_FALLTHROUGH;
   case NS_STYLE_BORDER_STYLE_RIDGE:
-    if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
-        (!horizontal && (twipsPerPixel >= aBorder.width))) {
+    if ((horizontal && (oneDevPixel >= aBorder.height)) ||
+        (!horizontal && (oneDevPixel >= aBorder.width))) {
       // a one pixel border
       DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
-                             aAppUnitsPerDevPixel, twipsPerPixel,
+                             aAppUnitsPerDevPixel,
                              aStartBevelSide, aStartBevelOffset,
                              aEndBevelSide, aEndBevelOffset);
     }
     else {
       nscoord startBevel = (aStartBevelOffset > 0)
-                            ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, true) : 0;
+                            ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset,
+                                                aAppUnitsPerDevPixel, true) : 0;
       nscoord endBevel =   (aEndBevelOffset > 0)
-                            ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, true) : 0;
+                            ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset,
+                                                aAppUnitsPerDevPixel, true) : 0;
       mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
       // FIXME: In theory, this should use the visited-dependent
       // background color, but I don't care.
       nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
                                           aBGColor, aBorderColor);
       nsRect rect(aBorder);
       nscoord half;
       if (horizontal) { // top, bottom
-        half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
+        half = RoundFloatToPixel(0.5f * (float)aBorder.height,
+                                 aAppUnitsPerDevPixel);
         rect.height = half;
         if (eSideTop == aStartBevelSide) {
           rect.x += startBevel;
           rect.width -= startBevel;
         }
         if (eSideTop == aEndBevelSide) {
           rect.width -= endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
       else { // left, right
-        half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
+        half = RoundFloatToPixel(0.5f * (float)aBorder.width,
+                                 aAppUnitsPerDevPixel);
         rect.width = half;
         if (eSideLeft == aStartBevelSide) {
           rect.y += startBevel;
           rect.height -= startBevel;
         }
         if (eSideLeft == aEndBevelSide) {
           rect.height -= endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
 
       rect = aBorder;
       ridgeGrooveSide = (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
       // FIXME: In theory, this should use the visited-dependent
       // background color, but I don't care.
@@ -3613,116 +3618,123 @@ nsCSSRendering::DrawTableBorderSegment(D
         if (eSideBottom == aStartBevelSide) {
           rect.x += startBevel;
           rect.width -= startBevel;
         }
         if (eSideBottom == aEndBevelSide) {
           rect.width -= endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
       else {
         rect.x = rect.x + half;
         rect.width = aBorder.width - half;
         if (eSideRight == aStartBevelSide) {
           rect.y += aStartBevelOffset - startBevel;
           rect.height -= startBevel;
         }
         if (eSideRight == aEndBevelSide) {
           rect.height -= endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
     }
     break;
   case NS_STYLE_BORDER_STYLE_DOUBLE:
     // We can only do "double" borders if the thickness of the border
     // is more than 2px.  Otherwise, we fall through to painting a
     // solid border.
-    if ((aBorder.width > 2*twipsPerPixel || horizontal) &&
-        (aBorder.height > 2*twipsPerPixel || !horizontal)) {
+    if ((aBorder.width > 2 * oneDevPixel || horizontal) &&
+        (aBorder.height > 2 * oneDevPixel || !horizontal)) {
       nscoord startBevel = (aStartBevelOffset > 0)
-                            ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
+                            ? RoundFloatToPixel(0.333333f *
+                                                (float)aStartBevelOffset,
+                                                 aAppUnitsPerDevPixel) : 0;
       nscoord endBevel =   (aEndBevelOffset > 0)
-                            ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
+                            ? RoundFloatToPixel(0.333333f *
+                                                (float)aEndBevelOffset,
+                                                aAppUnitsPerDevPixel) : 0;
       if (horizontal) { // top, bottom
-        nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
+        nscoord thirdHeight = RoundFloatToPixel(0.333333f *
+                                                (float)aBorder.height,
+                                                aAppUnitsPerDevPixel);
 
         // draw the top line or rect
         nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
         if (eSideTop == aStartBevelSide) {
           topRect.x += aStartBevelOffset - startBevel;
           topRect.width -= aStartBevelOffset - startBevel;
         }
         if (eSideTop == aEndBevelSide) {
           topRect.width -= aEndBevelOffset - endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, topRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
 
         // draw the botom line or rect
         nscoord heightOffset = aBorder.height - thirdHeight;
         nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
         if (eSideBottom == aStartBevelSide) {
           bottomRect.x += aStartBevelOffset - startBevel;
           bottomRect.width -= aStartBevelOffset - startBevel;
         }
         if (eSideBottom == aEndBevelSide) {
           bottomRect.width -= aEndBevelOffset - endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, bottomRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
       else { // left, right
-        nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
+        nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width,
+                                               aAppUnitsPerDevPixel);
 
         nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
         if (eSideLeft == aStartBevelSide) {
           leftRect.y += aStartBevelOffset - startBevel;
           leftRect.height -= aStartBevelOffset - startBevel;
         }
         if (eSideLeft == aEndBevelSide) {
           leftRect.height -= aEndBevelOffset - endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, leftRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
 
         nscoord widthOffset = aBorder.width - thirdWidth;
         nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
         if (eSideRight == aStartBevelSide) {
           rightRect.y += aStartBevelOffset - startBevel;
           rightRect.height -= aStartBevelOffset - startBevel;
         }
         if (eSideRight == aEndBevelSide) {
           rightRect.height -= aEndBevelOffset - endBevel;
         }
         DrawSolidBorderSegment(aDrawTarget, rightRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
+                               aAppUnitsPerDevPixel,
                                aStartBevelSide, startBevel, aEndBevelSide,
                                endBevel);
       }
       break;
     }
     // else fall through to solid
     MOZ_FALLTHROUGH;
   case NS_STYLE_BORDER_STYLE_SOLID:
     DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
-                           aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide,
+                           aAppUnitsPerDevPixel, aStartBevelSide,
                            aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
     break;
   case NS_STYLE_BORDER_STYLE_OUTSET:
   case NS_STYLE_BORDER_STYLE_INSET:
     NS_ASSERTION(false, "inset, outset should have been converted to groove, ridge");
     break;
   case NS_STYLE_BORDER_STYLE_AUTO:
     NS_ASSERTION(false, "Unexpected 'auto' table border");
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -545,17 +545,16 @@ struct nsCSSRendering {
   // Draw a border segment in the table collapsing border model without
   // beveling corners
   static void DrawTableBorderSegment(DrawTarget&   aDrawTarget,
                                      uint8_t       aBorderStyle,
                                      nscolor       aBorderColor,
                                      nscolor       aBGColor,
                                      const nsRect& aBorderRect,
                                      int32_t       aAppUnitsPerDevPixel,
-                                     int32_t       aAppUnitsPerCSSPixel,
                                      mozilla::Side aStartBevelSide = mozilla::eSideTop,
                                      nscoord       aStartBevelOffset = 0,
                                      mozilla::Side aEndBevelSide = mozilla::eSideTop,
                                      nscoord       aEndBevelOffset = 0);
 
   // NOTE: pt, dirtyRect, lineSize, ascent, offset in the following
   //       structs are non-rounded device pixels, not app units.
   struct DecorationRectParams
--- a/layout/tables/celldata.h
+++ b/layout/tables/celldata.h
@@ -139,16 +139,17 @@ enum BCBorderOwner
   eRowGroupOwner     =  5,
   eAjaRowGroupOwner  =  6, // row group above
   eRowOwner          =  7,
   eAjaRowOwner       =  8, // row above
   eCellOwner         =  9,
   eAjaCellOwner      = 10  // cell to the top or to the left
 };
 
+// BCPixelSize is in device pixels.
 typedef uint16_t BCPixelSize;
 
 // These are the max sizes that are stored. If they are exceeded, then the max is stored and
 // the actual value is computed when needed.
 #define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1)
 
 // The half of border on inline/block-axis start side
 static inline BCPixelSize
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -1137,22 +1137,22 @@ nsBCTableCellFrame::GetFrameName(nsAStri
 {
   return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
 }
 #endif
 
 LogicalMargin
 nsBCTableCellFrame::GetBorderWidth(WritingMode aWM) const
 {
-  int32_t pixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
   return LogicalMargin(aWM,
-                       BC_BORDER_END_HALF_COORD(pixelsToTwips, mBStartBorder),
-                       BC_BORDER_START_HALF_COORD(pixelsToTwips, mIEndBorder),
-                       BC_BORDER_START_HALF_COORD(pixelsToTwips, mBEndBorder),
-                       BC_BORDER_END_HALF_COORD(pixelsToTwips, mIStartBorder));
+                       BC_BORDER_END_HALF_COORD(d2a, mBStartBorder),
+                       BC_BORDER_START_HALF_COORD(d2a, mIEndBorder),
+                       BC_BORDER_START_HALF_COORD(d2a, mBEndBorder),
+                       BC_BORDER_END_HALF_COORD(d2a, mIStartBorder));
 }
 
 BCPixelSize
 nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide) const
 {
   switch(aSide) {
   case eLogicalSideBStart:
     return BC_BORDER_END_HALF(mBStartBorder);
@@ -1182,22 +1182,22 @@ nsBCTableCellFrame::SetBorderWidth(Logic
     mIStartBorder = aValue;
   }
 }
 
 /* virtual */ nsMargin
 nsBCTableCellFrame::GetBorderOverflow()
 {
   WritingMode wm = GetWritingMode();
-  int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
   LogicalMargin halfBorder(wm,
-                           BC_BORDER_START_HALF_COORD(p2t, mBStartBorder),
-                           BC_BORDER_END_HALF_COORD(p2t, mIEndBorder),
-                           BC_BORDER_END_HALF_COORD(p2t, mBEndBorder),
-                           BC_BORDER_START_HALF_COORD(p2t, mIStartBorder));
+                           BC_BORDER_START_HALF_COORD(d2a, mBStartBorder),
+                           BC_BORDER_END_HALF_COORD(d2a, mIEndBorder),
+                           BC_BORDER_END_HALF_COORD(d2a, mBEndBorder),
+                           BC_BORDER_START_HALF_COORD(d2a, mIStartBorder));
   return halfBorder.GetPhysicalMargin(wm);
 }
 
 DrawResult
 nsBCTableCellFrame::PaintBackground(gfxContext&          aRenderingContext,
                                     const nsRect&        aDirtyRect,
                                     nsPoint              aPt,
                                     uint32_t             aFlags)
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -322,20 +322,20 @@ inline void nsTableColFrame::SetColIndex
 {
   mColIndex = aColIndex;
 }
 
 inline nscoord
 nsTableColFrame::GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
                                             mozilla::LogicalMargin& aBorder)
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
+  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mBStartContBorderWidth);
-  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mIEndContBorderWidth);
-  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mBEndContBorderWidth);
-  return BC_BORDER_END_HALF_COORD(aPixelsToTwips, mIEndContBorderWidth);
+  return BC_BORDER_END_HALF_COORD(d2a, mIEndContBorderWidth);
 }
 
 #endif
 
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -439,23 +439,23 @@ void nsTableColGroupFrame::SetContinuous
     default:
       NS_ERROR("invalid side arg");
   }
 }
 
 void nsTableColGroupFrame::GetContinuousBCBorderWidth(WritingMode aWM,
                                                       LogicalMargin& aBorder)
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
   nsTableColFrame* col = GetTableFrame()->
     GetColFrame(mStartColIndex + mColCount - 1);
   col->GetContinuousBCBorderWidth(aWM, aBorder);
-  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mBStartContBorderWidth);
-  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mBEndContBorderWidth);
 }
 
 /* ----- global methods ----- */
 
 nsTableColGroupFrame*
 NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -168,16 +168,19 @@ nsTableFrame::Init(nsIContent*       aCo
 
   // Let the base class do its processing
   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   // see if border collapse is on, if so set it
   const nsStyleTableBorder* tableStyle = StyleTableBorder();
   bool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
   SetBorderCollapse(borderCollapse);
+  if (borderCollapse) {
+    SetNeedToCalcHasBCBorders(true);
+  }
 
   if (!aPrevInFlow) {
     // If we're the first-in-flow, we manage the cell map & layout strategy that
     // get used by our continuation chain:
     mCellMap = new nsTableCellMap(*this, borderCollapse);
     if (IsAutoLayout()) {
       mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
     } else {
@@ -2917,44 +2920,43 @@ DivideBCBorderSize(BCPixelSize  aPixelSi
 }
 
 LogicalMargin
 nsTableFrame::GetOuterBCBorder(const WritingMode aWM) const
 {
   if (NeedToCalcBCBorders()) {
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
   }
-
-  int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
   BCPropertyData* propData = GetBCProperty();
   if (propData) {
     return LogicalMargin(aWM,
-               BC_BORDER_START_HALF_COORD(p2t, propData->mBStartBorderWidth),
-               BC_BORDER_END_HALF_COORD(p2t, propData->mIEndBorderWidth),
-               BC_BORDER_END_HALF_COORD(p2t, propData->mBEndBorderWidth),
-               BC_BORDER_START_HALF_COORD(p2t, propData->mIStartBorderWidth));
+               BC_BORDER_START_HALF_COORD(d2a, propData->mBStartBorderWidth),
+               BC_BORDER_END_HALF_COORD(d2a, propData->mIEndBorderWidth),
+               BC_BORDER_END_HALF_COORD(d2a, propData->mBEndBorderWidth),
+               BC_BORDER_START_HALF_COORD(d2a, propData->mIStartBorderWidth));
   }
   return LogicalMargin(aWM);
 }
 
 LogicalMargin
 nsTableFrame::GetIncludedOuterBCBorder(const WritingMode aWM) const
 {
   if (NeedToCalcBCBorders()) {
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
   }
 
-  int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
   BCPropertyData* propData = GetBCProperty();
   if (propData) {
     return LogicalMargin(aWM,
-               BC_BORDER_START_HALF_COORD(p2t, propData->mBStartBorderWidth),
-               BC_BORDER_END_HALF_COORD(p2t, propData->mIEndCellBorderWidth),
-               BC_BORDER_END_HALF_COORD(p2t, propData->mBEndBorderWidth),
-               BC_BORDER_START_HALF_COORD(p2t, propData->mIStartCellBorderWidth));
+               BC_BORDER_START_HALF_COORD(d2a, propData->mBStartBorderWidth),
+               BC_BORDER_END_HALF_COORD(d2a, propData->mIEndCellBorderWidth),
+               BC_BORDER_END_HALF_COORD(d2a, propData->mBEndBorderWidth),
+               BC_BORDER_START_HALF_COORD(d2a, propData->mIStartCellBorderWidth));
   }
   return LogicalMargin(aWM);
 }
 
 LogicalMargin
 nsTableFrame::GetExcludedOuterBCBorder(const WritingMode aWM) const
 {
   return GetOuterBCBorder(aWM) - GetIncludedOuterBCBorder(aWM);
@@ -5048,17 +5050,17 @@ GetColorAndStyle(const nsIFrame* aFrame,
       (NS_STYLE_BORDER_STYLE_HIDDEN == *aStyle)) {
     return;
   }
   *aColor = aFrame->StyleContext()->
     GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(physicalSide));
 
   if (aWidth) {
     nscoord width = styleData->GetComputedBorderWidth(physicalSide);
-    *aWidth = nsPresContext::AppUnitsToIntCSSPixels(width);
+    *aWidth = aFrame->PresContext()->AppUnitsToDevPixels(width);
   }
 }
 
 /** coerce the paint style as required by CSS2.1
   * @param aFrame           - query the info for this frame
   * @param aTableWM         - the writing mode of the frame
   * @param aSide            - the side of the frame
   * @param aStyle           - the border style
@@ -6816,37 +6818,41 @@ BCPaintBorderIterator::SetDamageArea(con
   nsSize containerSize = mTable->GetSize();
   LogicalRect dirtyRect(mTableWM, aDirtyRect, containerSize);
   uint32_t startRowIndex, endRowIndex, startColIndex, endColIndex;
   startRowIndex = endRowIndex = startColIndex = endColIndex = 0;
   bool done = false;
   bool haveIntersect = false;
   // find startRowIndex, endRowIndex
   nscoord rowB = mInitialOffsetB;
+  nsPresContext* presContext = mTable->PresContext();
   for (uint32_t rgIdx = 0; rgIdx < mRowGroups.Length() && !done; rgIdx++) {
     nsTableRowGroupFrame* rgFrame = mRowGroups[rgIdx];
     for (nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); rowFrame;
          rowFrame = rowFrame->GetNextRow()) {
       // get the row rect relative to the table rather than the row group
       nscoord rowBSize = rowFrame->BSize(mTableWM);
       if (haveIntersect) {
         // conservatively estimate the half border widths outside the row
-        nscoord borderHalf = mTable->GetPrevInFlow() ? 0 : nsPresContext::
-          CSSPixelsToAppUnits(rowFrame->GetBStartBCBorderWidth() + 1);
+        nscoord borderHalf = mTable->GetPrevInFlow() ? 0 :
+                               presContext->DevPixelsToAppUnits(
+                                 rowFrame->GetBStartBCBorderWidth() + 1);
+
         if (dirtyRect.BEnd(mTableWM) >= rowB - borderHalf) {
           nsTableRowFrame* fifRow =
             static_cast<nsTableRowFrame*>(rowFrame->FirstInFlow());
           endRowIndex = fifRow->GetRowIndex();
         }
         else done = true;
       }
       else {
         // conservatively estimate the half border widths outside the row
-        nscoord borderHalf = mTable->GetNextInFlow() ? 0 : nsPresContext::
-          CSSPixelsToAppUnits(rowFrame->GetBEndBCBorderWidth() + 1);
+        nscoord borderHalf = mTable->GetNextInFlow() ? 0 :
+                               presContext->DevPixelsToAppUnits(
+                                 rowFrame->GetBEndBCBorderWidth() + 1);
         if (rowB + rowBSize + borderHalf >= dirtyRect.BStart(mTableWM)) {
           mStartRg  = rgFrame;
           mStartRow = rowFrame;
           nsTableRowFrame* fifRow =
             static_cast<nsTableRowFrame*>(rowFrame->FirstInFlow());
           startRowIndex = endRowIndex = fifRow->GetRowIndex();
           haveIntersect = true;
         }
@@ -6880,27 +6886,27 @@ BCPaintBorderIterator::SetDamageArea(con
   int32_t colIdx;
   for (colIdx = 0; colIdx != mNumTableCols; colIdx++) {
     nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(colIdx);
     if (!colFrame) ABORT1(false);
     // get the col rect relative to the table rather than the col group
     nscoord colISize = colFrame->ISize(mTableWM);
     if (haveIntersect) {
       // conservatively estimate the iStart half border width outside the col
-      nscoord iStartBorderHalf = nsPresContext::
-        CSSPixelsToAppUnits(colFrame->GetIStartBorderWidth() + 1);
+      nscoord iStartBorderHalf = presContext->DevPixelsToAppUnits(
+        colFrame->GetIStartBorderWidth() + 1);
       if (dirtyRect.IEnd(mTableWM) >= x - iStartBorderHalf) {
         endColIndex = colIdx;
       }
       else break;
     }
     else {
       // conservatively estimate the iEnd half border width outside the col
-      nscoord iEndBorderHalf = nsPresContext::
-        CSSPixelsToAppUnits(colFrame->GetIEndBorderWidth() + 1);
+      nscoord iEndBorderHalf = presContext->DevPixelsToAppUnits(
+        colFrame->GetIEndBorderWidth() + 1);
       if (x + colISize + iEndBorderHalf >= dirtyRect.IStart(mTableWM)) {
         startColIndex = endColIndex = colIdx;
         haveIntersect = true;
       }
       else {
         mInitialOffsetI += colISize;
       }
     }
@@ -7129,17 +7135,18 @@ BCPaintBorderIterator::Next()
   * @param aCornerOwnerSide - which side owns the corner
   * @param aCornerSubWidth  - how wide is the nonwinning side of the corner
   * @param aHorWidth        - how wide is the horizontal edge of the corner
   * @param aIsStartOfSeg    - does this corner start a new segment
   * @param aIsBevel         - is this corner beveled
   * @return                 - offset in twips
   */
 static nscoord
-CalcVerCornerOffset(LogicalSide aCornerOwnerSide,
+CalcVerCornerOffset(nsPresContext* aPresContext,
+                    LogicalSide aCornerOwnerSide,
                     BCPixelSize aCornerSubWidth,
                     BCPixelSize aHorWidth,
                     bool        aIsStartOfSeg,
                     bool        aIsBevel)
 {
   nscoord offset = 0;
   // XXX These should be replaced with appropriate side-specific macros (which?)
   BCPixelSize smallHalf, largeHalf;
@@ -7156,29 +7163,30 @@ CalcVerCornerOffset(LogicalSide aCornerO
     DivideBCBorderSize(aHorWidth, smallHalf, largeHalf);
     if (aIsBevel) {
       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
     }
     else {
       offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
     }
   }
-  return nsPresContext::CSSPixelsToAppUnits(offset);
+  return aPresContext->DevPixelsToAppUnits(offset);
 }
 
 /** Compute the horizontal offset of a horizontal border segment
   * @param aCornerOwnerSide - which side owns the corner
   * @param aCornerSubWidth  - how wide is the nonwinning side of the corner
   * @param aVerWidth        - how wide is the vertical edge of the corner
   * @param aIsStartOfSeg    - does this corner start a new segment
   * @param aIsBevel         - is this corner beveled
   * @return                 - offset in twips
   */
 static nscoord
-CalcHorCornerOffset(LogicalSide aCornerOwnerSide,
+CalcHorCornerOffset(nsPresContext* aPresContext,
+                    LogicalSide aCornerOwnerSide,
                     BCPixelSize aCornerSubWidth,
                     BCPixelSize aVerWidth,
                     bool        aIsStartOfSeg,
                     bool        aIsBevel)
 {
   nscoord offset = 0;
   // XXX These should be replaced with appropriate side-specific macros (which?)
   BCPixelSize smallHalf, largeHalf;
@@ -7195,17 +7203,17 @@ CalcHorCornerOffset(LogicalSide aCornerO
     DivideBCBorderSize(aVerWidth, smallHalf, largeHalf);
     if (aIsBevel) {
       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
     }
     else {
       offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
     }
   }
-  return nsPresContext::CSSPixelsToAppUnits(offset);
+  return aPresContext->DevPixelsToAppUnits(offset);
 }
 
 BCBlockDirSeg::BCBlockDirSeg()
 {
   mCol = nullptr;
   mFirstCell = mLastCell = mAjaCell = nullptr;
   mOffsetI = mOffsetB = mLength = mWidth = mBStartBevelOffset = 0;
   mBStartBevelSide = eLogicalSideBStart;
@@ -7229,22 +7237,24 @@ BCBlockDirSeg::Start(BCPaintBorderIterat
   LogicalSide ownerSide   = eLogicalSideBStart;
   bool bevel       = false;
 
   nscoord cornerSubWidth  = (aIter.mBCData) ?
                                aIter.mBCData->GetCorner(ownerSide, bevel) : 0;
 
   bool    bStartBevel     = (aBlockSegISize > 0) ? bevel : false;
   BCPixelSize maxInlineSegBSize = std::max(aIter.mPrevInlineSegBSize, aInlineSegBSize);
-  nscoord offset          = CalcVerCornerOffset(ownerSide, cornerSubWidth,
+  nsPresContext* presContext = aIter.mTable->PresContext();
+  nscoord offset          = CalcVerCornerOffset(presContext,
+                                                ownerSide, cornerSubWidth,
                                                 maxInlineSegBSize, true,
                                                 bStartBevel);
 
   mBStartBevelOffset = bStartBevel ?
-    nsPresContext::CSSPixelsToAppUnits(maxInlineSegBSize): 0;
+    presContext->DevPixelsToAppUnits(maxInlineSegBSize): 0;
   // XXX this assumes that only corners where 2 segments join can be beveled
   mBStartBevelSide     = (aInlineSegBSize > 0) ? eLogicalSideIEnd : eLogicalSideIStart;
   mOffsetB      += offset;
   mLength        = -offset;
   mWidth         = aBlockSegISize;
   mOwner         = aBorderOwner;
   mFirstCell     = aIter.mCell;
   mFirstRowGroup = aIter.mRg;
@@ -7291,17 +7301,18 @@ BCBlockDirSeg::GetBEndCorner(BCPaintBord
    LogicalSide ownerSide = eLogicalSideBStart;
    nscoord cornerSubWidth = 0;
    bool bevel = false;
    if (aIter.mBCData) {
      cornerSubWidth = aIter.mBCData->GetCorner(ownerSide, bevel);
    }
    mIsBEndBevel = (mWidth > 0) ? bevel : false;
    mBEndInlineSegBSize = std::max(aIter.mPrevInlineSegBSize, aInlineSegBSize);
-   mBEndOffset = CalcVerCornerOffset(ownerSide, cornerSubWidth,
+   mBEndOffset = CalcVerCornerOffset(aIter.mTable->PresContext(),
+                                    ownerSide, cornerSubWidth,
                                     mBEndInlineSegBSize,
                                     false, mIsBEndBevel);
    mLength += mBEndOffset;
 }
 
 Maybe<BCBorderParameters>
 BCBlockDirSeg::BuildBorderParameters(BCPaintBorderIterator& aIter,
                                      BCPixelSize aInlineSegBSize)
@@ -7316,17 +7327,18 @@ BCBlockDirSeg::BuildBorderParameters(BCP
   nsTableCellFrame* cell         = mFirstCell; // ???
   nsIFrame* owner = nullptr;
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
   result.mBGColor = aIter.mTableBgColor;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
-  result.mAppUnitsPerDevPixel = col->PresContext()->AppUnitsPerDevPixel();
+  nsPresContext* presContext = aIter.mTable->PresContext();
+  result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   switch (mOwner) {
     case eTableOwner:
       owner = aIter.mTable;
       break;
     case eAjaColGroupOwner:
       side = eLogicalSideIEnd;
       if (!aIter.IsTableIEndMost() && (relColIndex > 0)) {
@@ -7372,21 +7384,21 @@ BCBlockDirSeg::BuildBorderParameters(BCP
       break;
   }
   if (owner) {
     ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &result.mBorderStyle, &result.mBorderColor);
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   LogicalRect segRect(aIter.mTableWM,
-                 mOffsetI - nsPresContext::CSSPixelsToAppUnits(largeHalf),
+                 mOffsetI - presContext->DevPixelsToAppUnits(largeHalf),
                  mOffsetB,
-                 nsPresContext::CSSPixelsToAppUnits(mWidth), mLength);
+                 presContext->DevPixelsToAppUnits(mWidth), mLength);
   nscoord bEndBevelOffset = (mIsBEndBevel) ?
-                  nsPresContext::CSSPixelsToAppUnits(mBEndInlineSegBSize) : 0;
+    presContext->DevPixelsToAppUnits(mBEndInlineSegBSize) : 0;
   LogicalSide bEndBevelSide =
     (aInlineSegBSize > 0) ? eLogicalSideIEnd : eLogicalSideIStart;
 
   // Convert logical to physical sides/coordinates for DrawTableBorderSegment.
 
   result.mBorderRect = segRect.GetPhysicalRect(aIter.mTableWM, aIter.mTable->GetSize());
   // XXX For reversed vertical writing-modes (with direction:rtl), we need to
   // invert physicalRect's y-position here, with respect to the table.
@@ -7430,17 +7442,16 @@ BCBlockDirSeg::Paint(BCPaintBorderIterat
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter, aInlineSegBSize);
   if (param.isNothing()) {
     return;
   }
 
   nsCSSRendering::DrawTableBorderSegment(aDrawTarget, param->mBorderStyle, param->mBorderColor,
                                          param->mBGColor, param->mBorderRect,
                                          param->mAppUnitsPerDevPixel,
-                                         nsPresContext::AppUnitsPerCSSPixel(),
                                          param->mStartBevelSide, param->mStartBevelOffset,
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
 void
 BCBlockDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                        BCPixelSize aInlineSegBSize,
                                        wr::DisplayListBuilder& aBuilder,
@@ -7525,17 +7536,18 @@ BCInlineDirSeg::Start(BCPaintBorderItera
   nscoord cornerSubWidth  = (aIter.mBCData) ?
                              aIter.mBCData->GetCorner(cornerOwnerSide,
                                                        bevel) : 0;
 
   bool    iStartBevel = (aInlineSegBSize > 0) ? bevel : false;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nscoord maxBlockSegISize = std::max(aIter.mBlockDirInfo[relColIndex].mWidth,
                                       aBEndBlockSegISize);
-  nscoord offset = CalcHorCornerOffset(cornerOwnerSide, cornerSubWidth,
+  nscoord offset = CalcHorCornerOffset(aIter.mTable->PresContext(),
+                                       cornerOwnerSide, cornerSubWidth,
                                        maxBlockSegISize, true, iStartBevel);
   mIStartBevelOffset = (iStartBevel && (aInlineSegBSize > 0)) ? maxBlockSegISize : 0;
   // XXX this assumes that only corners where 2 segments join can be beveled
   mIStartBevelSide   = (aBEndBlockSegISize > 0) ? eLogicalSideBEnd : eLogicalSideBStart;
   mOffsetI += offset;
   mLength          = -offset;
   mWidth           = aInlineSegBSize;
   mFirstCell       = aIter.mCell;
@@ -7559,21 +7571,22 @@ BCInlineDirSeg::GetIEndCorner(BCPaintBor
   if (aIter.mBCData) {
     cornerSubWidth = aIter.mBCData->GetCorner(ownerSide, bevel);
   }
 
   mIsIEndBevel = (mWidth > 0) ? bevel : 0;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nscoord verWidth = std::max(aIter.mBlockDirInfo[relColIndex].mWidth,
                               aIStartSegISize);
-  mEndOffset = CalcHorCornerOffset(ownerSide, cornerSubWidth, verWidth,
-                                   false, mIsIEndBevel);
+  nsPresContext* presContext = aIter.mTable->PresContext();
+  mEndOffset = CalcHorCornerOffset(presContext, ownerSide, cornerSubWidth,
+                                   verWidth, false, mIsIEndBevel);
   mLength += mEndOffset;
   mIEndBevelOffset = (mIsIEndBevel) ?
-                       nsPresContext::CSSPixelsToAppUnits(verWidth) : 0;
+                       presContext->DevPixelsToAppUnits(verWidth) : 0;
   mIEndBevelSide = (aIStartSegISize > 0) ? eLogicalSideBEnd : eLogicalSideBStart;
 }
 
 Maybe<BCBorderParameters>
 BCInlineDirSeg::BuildBorderParameters(BCPaintBorderIterator& aIter)
 {
   BCBorderParameters result;
 
@@ -7583,17 +7596,18 @@ BCInlineDirSeg::BuildBorderParameters(BC
   nsIFrame* rg   = aIter.mRg;  if (!rg) ABORT1(Nothing());
   nsIFrame* row  = aIter.mRow; if (!row) ABORT1(Nothing());
   nsIFrame* cell = mFirstCell;
   nsIFrame* col;
   nsIFrame* owner = nullptr;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
-  result.mAppUnitsPerDevPixel = row->PresContext()->AppUnitsPerDevPixel();
+  nsPresContext* presContext = aIter.mTable->PresContext();
+  result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
   result.mBGColor = aIter.mTableBgColor;
 
   switch (mOwner) {
     case eTableOwner:
       owner = aIter.mTable;
@@ -7641,26 +7655,26 @@ BCInlineDirSeg::BuildBorderParameters(BC
       break;
   }
   if (owner) {
     ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &result.mBorderStyle, &result.mBorderColor);
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   LogicalRect segRect(aIter.mTableWM, mOffsetI,
-                      mOffsetB - nsPresContext::CSSPixelsToAppUnits(largeHalf),
+                      mOffsetB - presContext->DevPixelsToAppUnits(largeHalf),
                       mLength,
-                      nsPresContext::CSSPixelsToAppUnits(mWidth));
+                      presContext->DevPixelsToAppUnits(mWidth));
 
   // Convert logical to physical sides/coordinates for DrawTableBorderSegment.
   result.mBorderRect = segRect.GetPhysicalRect(aIter.mTableWM, aIter.mTable->GetSize());
   result.mStartBevelSide = aIter.mTableWM.PhysicalSide(mIStartBevelSide);
   result.mEndBevelSide = aIter.mTableWM.PhysicalSide(mIEndBevelSide);
   result.mStartBevelOffset =
-    nsPresContext::CSSPixelsToAppUnits(mIStartBevelOffset);
+    presContext->DevPixelsToAppUnits(mIStartBevelOffset);
   result.mEndBevelOffset = mIEndBevelOffset;
   // With inline-RTL directionality, the 'start' and 'end' of the inline-dir
   // border segment need to be swapped because DrawTableBorderSegment will
   // apply the 'start' bevel physically at the left or top edge, and 'end' at
   // the right or bottom.
   // (Note: startBevelSide/endBevelSide will be "top" or "bottom" in horizontal
   // writing mode, or "left" or "right" in vertical mode.
   // DrawTableBorderSegment works purely with physical coordinates, so it
@@ -7688,17 +7702,16 @@ BCInlineDirSeg::Paint(BCPaintBorderItera
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter);
   if (param.isNothing()) {
     return;
   }
 
   nsCSSRendering::DrawTableBorderSegment(aDrawTarget, param->mBorderStyle, param->mBorderColor,
                                          param->mBGColor, param->mBorderRect,
                                          param->mAppUnitsPerDevPixel,
-                                         nsPresContext::AppUnitsPerCSSPixel(),
                                          param->mStartBevelSide, param->mStartBevelOffset,
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
 void
 BCInlineDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                         wr::DisplayListBuilder& aBuilder,
                                         const layers::StackingContextHelper& aSc,
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -1023,18 +1023,18 @@ inline bool nsTableFrame::HasBCBorders()
 inline void nsTableFrame::SetHasBCBorders(bool aValue)
 {
   mBits.mHasBCBorders = (unsigned)aValue;
 }
 
 inline nscoord
 nsTableFrame::GetContinuousIStartBCBorderWidth() const
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  return BC_BORDER_END_HALF_COORD(aPixelsToTwips, mBits.mIStartContBCBorder);
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
+  return BC_BORDER_END_HALF_COORD(d2a, mBits.mIStartContBCBorder);
 }
 
 inline void nsTableFrame::SetContinuousIStartBCBorderWidth(nscoord aValue)
 {
   mBits.mIStartContBCBorder = (unsigned) aValue;
 }
 
 #define ABORT0() \
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -419,31 +419,32 @@ inline void nsTableRowFrame::SetHasUnpag
   } else {
     RemoveStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
   }
 }
 
 inline mozilla::LogicalMargin
 nsTableRowFrame::GetBCBorderWidth(mozilla::WritingMode aWM)
 {
+  nsPresContext* presContext = PresContext();
   return mozilla::LogicalMargin(
-    aWM, nsPresContext::CSSPixelsToAppUnits(mBStartBorderWidth), 0,
-    nsPresContext::CSSPixelsToAppUnits(mBEndBorderWidth), 0);
+    aWM, presContext->DevPixelsToAppUnits(mBStartBorderWidth), 0,
+    presContext->DevPixelsToAppUnits(mBEndBorderWidth), 0);
 }
 
 inline void
 nsTableRowFrame::GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
                                             mozilla::LogicalMargin& aBorder)
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
+  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mIStartContBorderWidth);
-  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mBStartContBorderWidth);
-  aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+  aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mIEndContBorderWidth);
 }
 
 inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth()
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
   return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth);
 }
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -1679,20 +1679,20 @@ nsTableRowGroupFrame::GetBCBorderWidth(W
   nsTableRowFrame* lastRowFrame = nullptr;
   for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
     if (!firstRowFrame) {
       firstRowFrame = rowFrame;
     }
     lastRowFrame = rowFrame;
   }
   if (firstRowFrame) {
-    border.BStart(aWM) = nsPresContext::
-      CSSPixelsToAppUnits(firstRowFrame->GetBStartBCBorderWidth());
-    border.BEnd(aWM) = nsPresContext::
-      CSSPixelsToAppUnits(lastRowFrame->GetBEndBCBorderWidth());
+    border.BStart(aWM) = PresContext()->DevPixelsToAppUnits(
+      firstRowFrame->GetBStartBCBorderWidth());
+    border.BEnd(aWM) = PresContext()->DevPixelsToAppUnits(
+      lastRowFrame->GetBEndBCBorderWidth());
   }
   return border;
 }
 
 void nsTableRowGroupFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
                                                       BCPixelSize aPixelValue)
 {
   switch (aForSide) {
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -445,17 +445,17 @@ inline void nsTableRowGroupFrame::SetHas
     RemoveStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE);
   }
 }
 
 inline void
 nsTableRowGroupFrame::GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
                                                  mozilla::LogicalMargin& aBorder)
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
+  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mIEndContBorderWidth);
-  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
                                                  mBEndContBorderWidth);
-  aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+  aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mIStartContBorderWidth);
 }
 #endif
--- a/media/webrtc/signaling/gtest/mediaconduit_unittests.cpp
+++ b/media/webrtc/signaling/gtest/mediaconduit_unittests.cpp
@@ -536,168 +536,16 @@ class TransportConduitTest : public ::te
     cerr << "   *************************************************" << endl;
     cerr << "    3. Null Codec Parameter  " << endl;
     cerr << "   *************************************************" << endl;
 
     err = videoSession->ConfigureSendMediaCodec(nullptr);
     EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
   }
 
-  void DumpMaxFs(int orig_width, int orig_height, int max_fs,
-                 int new_width, int new_height)
-  {
-    cerr << "Applying max_fs=" << max_fs << " to input resolution " <<
-                 orig_width << "x" << orig_height << endl;
-    cerr << "New resolution: " << new_width << "x" << new_height << endl;
-    cerr << endl;
-  }
-
-  // Calculate new resolution for sending video by applying max-fs constraint.
-  void GetVideoResolutionWithMaxFs(unsigned short orig_width,
-                                   unsigned short orig_height,
-                                   int max_fs,
-                                   unsigned short &new_width,
-                                   unsigned short &new_height)
-  {
-    int err = 0;
-
-    // Get pointer to VideoSessionConduit.
-    mVideoSession = VideoSessionConduit::Create(WebRtcCallWrapper::Create());
-    if( !mVideoSession ) {
-      ASSERT_NE(mVideoSession, (void*)nullptr);
-    }
-
-    std::vector<unsigned int> ssrcs = {SSRC};
-    mVideoSession->SetLocalSSRCs(ssrcs);
-
-    mozilla::EncodingConstraints constraints;
-    constraints.maxFs = max_fs;
-    // Configure send codecs on the conduit.
-    mozilla::VideoCodecConfig cinst1(120, "VP8", constraints);
-    VideoCodecConfig::SimulcastEncoding encoding;
-    cinst1.mSimulcastEncodings.push_back(encoding);
-
-    err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-    err = mVideoSession->StartTransmitting();
-    ASSERT_EQ(mozilla::kMediaConduitNoError, err);
-
-    // Send one frame.
-    MOZ_ASSERT(!(orig_width & 1));
-    MOZ_ASSERT(!(orig_height & 1));
-
-    // Get the new resolution as adjusted by the max-fs constraint.
-    mVideoSession->SetSendingWidthAndHeight(orig_width, orig_height,
-                                            new_width, new_height);
-  }
-
-  void TestVideoConduitMaxFs()
-  {
-    unsigned short orig_width, orig_height, width, height;
-    int max_fs;
-
-    // No limitation.
-    cerr << "Test no max-fs limition" << endl;
-    orig_width = 640;
-    orig_height = 480;
-    max_fs = 0;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 640);
-    ASSERT_EQ(height, 480);
-
-    // VGA to QVGA.
-    cerr << "Test resizing from VGA to QVGA" << endl;
-    orig_width = 640;
-    orig_height = 480;
-    max_fs = 300;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 320);
-    ASSERT_EQ(height, 240);
-
-    // Extreme input resolution.
-    cerr << "Test extreme input resolution" << endl;
-    orig_width = 3072;
-    orig_height = 100;
-    max_fs = 300;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 768);
-    ASSERT_EQ(height, 25);
-
-    // Small max-fs.
-    cerr << "Test small max-fs (case 1)" << endl;
-    orig_width = 8;
-    orig_height = 32;
-    max_fs = 1;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 4);
-    ASSERT_EQ(height, 16);
-
-    // Small max-fs.
-    cerr << "Test small max-fs (case 2)" << endl;
-    orig_width = 4;
-    orig_height = 50;
-    max_fs = 1;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 1);
-    ASSERT_EQ(height, 16);
-
-    // Small max-fs.
-    cerr << "Test small max-fs (case 3)" << endl;
-    orig_width = 872;
-    orig_height = 136;
-    max_fs = 3;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 48);
-    ASSERT_EQ(height, 7);
-
-    // Small max-fs.
-    cerr << "Test small max-fs (case 4)" << endl;
-    orig_width = 160;
-    orig_height = 8;
-    max_fs = 5;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 80);
-    ASSERT_EQ(height, 4);
-
-     // Extremely small width and height(see bug 919979).
-    cerr << "Test with extremely small width and height" << endl;
-    orig_width = 2;
-    orig_height = 2;
-    max_fs = 5;
-    GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, width, height);
-    DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-    ASSERT_EQ(width, 2);
-    ASSERT_EQ(height, 2);
-
-    // Random values.
-    cerr << "Test with random values" << endl;
-    for (int i = 0; i < 30; i++) {
-      cerr << ".";
-      max_fs = rand() % 1000;
-      orig_width = ((rand() % 2000) & ~1) + 2;
-      orig_height = ((rand() % 2000) & ~1) + 2;
-
-      GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs,
-                                  width, height);
-      if (max_fs > 0 &&
-          ceil(width / 16.) * ceil(height / 16.) > max_fs) {
-        DumpMaxFs(orig_width, orig_height, max_fs, width, height);
-        ADD_FAILURE();
-      }
-    }
-    cerr << endl;
- }
-
  private:
   //Audio Conduit Test Objects
   RefPtr<mozilla::AudioSessionConduit> mAudioSession;
   RefPtr<mozilla::AudioSessionConduit> mAudioSession2;
   RefPtr<mozilla::TransportInterface> mAudioTransport;
   AudioSendAndReceive audioTester;
 
   //Video Conduit Test Objects
@@ -715,15 +563,11 @@ class TransportConduitTest : public ::te
 
 // Disabled, see Bug 1319121
 TEST_F(TransportConduitTest, DISABLED_TestDummyAudioWithTransport) {
   TestDummyAudioAndTransport();
 }
 
 TEST_F(TransportConduitTest, TestVideoConduitCodecAPI) {
   TestVideoConduitCodecAPI();
- }
-
-TEST_F(TransportConduitTest, TestVideoConduitMaxFs) {
-  TestVideoConduitMaxFs();
- }
+}
 
 }  // end namespace
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -389,25 +389,16 @@ public:
    * @param sendSessionConfig: CodecConfiguration
    * NOTE: This API can be invoked multiple time. Invoking this API may involve restarting
    *        reception sub-system on the engine
    *
    */
   virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
       const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0;
 
-  /**
-   * This method allows unit tests to double-check that the
-   * max-fs and max-fr related settings are as expected.
-   */
-  virtual void SetSendingWidthAndHeight(unsigned short frame_width,
-                                        unsigned short frame_height,
-                                        unsigned short &result_width,
-                                        unsigned short &result_height) = 0;
-
   virtual unsigned int SendingMaxFs() = 0;
 
   virtual unsigned int SendingMaxFr() = 0;
 
   /**
     * These methods allow unit tests to double-check that the
     * rtcp-fb settings are as expected.
     */
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -1686,60 +1686,28 @@ WebrtcVideoConduit::SelectSendResolution
     uint16_t max_width = mCurSendCodecConfig->mEncodingConstraints.maxWidth;
     uint16_t max_height = mCurSendCodecConfig->mEncodingConstraints.maxHeight;
     if (max_width || max_height) {
       max_width = max_width ? max_width : UINT16_MAX;
       max_height = max_height ? max_height : UINT16_MAX;
       ConstrainPreservingAspectRatio(max_width, max_height, &width, &height);
     }
 
-    // Limit resolution to max-fs while keeping same aspect ratio as the
-    // incoming image.
+    // Limit resolution to max-fs
     if (mCurSendCodecConfig->mEncodingConstraints.maxFs) {
-      uint32_t max_fs = mCurSendCodecConfig->mEncodingConstraints.maxFs;
-      unsigned int cur_fs, mb_width, mb_height, mb_max;
-
-      // Could we make this simpler by picking the larger of width and height,
-      // calculating a max for just that value based on the scale parameter,
-      // and then let ConstrainPreservingAspectRatio do the rest?
-      mb_width = (width + 15) >> 4;
-      mb_height = (height + 15) >> 4;
-
-      cur_fs = mb_width * mb_height;
-
-      // Limit resolution to max_fs, but don't scale up.
-      if (cur_fs > max_fs) {
-        double scale_ratio;
-
-        scale_ratio = sqrt((double)max_fs / (double)cur_fs);
-
-        mb_width = mb_width * scale_ratio;
-        mb_height = mb_height * scale_ratio;
-
-        // Adjust mb_width and mb_height if they were truncated to zero.
-        if (mb_width == 0) {
-          mb_width = 1;
-          mb_height = std::min(mb_height, max_fs);
-        }
-        if (mb_height == 0) {
-          mb_height = 1;
-          mb_width = std::min(mb_width, max_fs);
-        }
+      // max-fs is in macroblocks, convert to pixels
+      int max_fs(mCurSendCodecConfig->mEncodingConstraints.maxFs*(16*16));
+      if (max_fs > mLastSinkWanted.max_pixel_count.value_or(max_fs)) {
+        max_fs = mLastSinkWanted.max_pixel_count.value_or(max_fs);
       }
-
-      // Limit width/height seperately to limit effect of extreme aspect ratios.
-      mb_max = (unsigned)sqrt(8 * (double)max_fs);
-
-      max_width = 16 * std::min(mb_width, mb_max);
-      max_height = 16 * std::min(mb_height, mb_max);
-      ConstrainPreservingAspectRatio(max_width, max_height, &width, &height);
+      mVideoAdapter.OnResolutionRequest(rtc::Optional<int>(max_fs),
+                                        rtc::Optional<int>());
     }
   }
 
-
   // Adapt to getUserMedia resolution changes
   // check if we need to reconfigure the sending resolution.
   // NOTE: mSendingWidth != mLastWidth, because of maxwidth/height/etc above
   bool changed = false;
   if (mSendingWidth != width || mSendingHeight != height) {
     CSFLogDebug(logTag, "%s: resolution changing to %ux%u (from %ux%u)",
                 __FUNCTION__, width, height, mSendingWidth, mSendingHeight);
     // This will avoid us continually retrying this operation if it fails.
@@ -1929,18 +1897,33 @@ WebrtcVideoConduit::RemoveSink(
   OnSinkWantsChanged(mVideoBroadcaster.wants());
 }
 
 void
 WebrtcVideoConduit::OnSinkWantsChanged(
   const rtc::VideoSinkWants& wants) {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   if (!mLockScaling) {
-    mVideoAdapter.OnResolutionRequest(wants.max_pixel_count,
-                                      wants.max_pixel_count_step_up);
+    mLastSinkWanted = wants;
+
+    // limit sink wants based upon max-fs constraint
+    int max_fs = mCurSendCodecConfig->mEncodingConstraints.maxFs*(16*16);
+    rtc::Optional<int> max_pixel_count = wants.max_pixel_count;
+    rtc::Optional<int> max_pixel_count_step_up = wants.max_pixel_count_step_up;
+
+    if (max_pixel_count.value_or(max_fs) > max_fs) {
+      max_pixel_count = rtc::Optional<int>(max_fs);
+    }
+
+    if (max_pixel_count_step_up.value_or(max_fs) > max_fs) {
+      max_pixel_count_step_up = rtc::Optional<int>(max_fs);
+    }
+
+    mVideoAdapter.OnResolutionRequest(max_pixel_count,
+                                      max_pixel_count_step_up);
   }
 }
 
 MediaConduitErrorCode
 WebrtcVideoConduit::SendVideoFrame(webrtc::VideoFrame& frame)
 {
   // XXX Google uses a "timestamp_aligner" to translate timestamps from the
   // camera via TranslateTimestamp(); we should look at doing the same.  This
@@ -2412,30 +2395,16 @@ WebrtcVideoConduit::CodecPluginID()
   }
   if (mRecvCodecPlugin) {
     return mRecvCodecPlugin->PluginID();
   }
 
   return 0;
 }
 
-void
-WebrtcVideoConduit::SetSendingWidthAndHeight(unsigned short frame_width,
-                                             unsigned short frame_height,
-                                             unsigned short &result_width,
-                                             unsigned short &result_height)
-{
-  MutexAutoLock lock(mCodecMutex);
-  result_width = 0;
-  result_height = 0;
-  (void)SelectSendResolution(frame_width, frame_height, nullptr);
-  result_width = mSendingWidth;
-  result_height = mSendingHeight;
-}
-
 bool
 WebrtcVideoConduit::RequiresNewSendStream(const VideoCodecConfig& newConfig) const
 {
   return !mCurSendCodecConfig
     || mCurSendCodecConfig->mName != newConfig.mName
     || mCurSendCodecConfig->mType != newConfig.mType
     || mCurSendCodecConfig->RtcpFbNackIsSet("") != newConfig.RtcpFbNackIsSet("")
     || mCurSendCodecConfig->RtcpFbFECIsSet() != newConfig.RtcpFbFECIsSet()
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -251,25 +251,16 @@ public:
   void OnSinkWantsChanged(const rtc::VideoSinkWants& wants);
 
   virtual uint64_t CodecPluginID() override;
 
   virtual void SetPCHandle(const std::string& aPCHandle) override {
     mPCHandle = aPCHandle;
   }
 
-  /**
-   * This method allows unit tests to double-check that the
-   * max-fs and max-fr related settings are as expected.
-   */
-  virtual void SetSendingWidthAndHeight(unsigned short frame_width,
-                                        unsigned short frame_height,
-                                        unsigned short &result_width,
-                                        unsigned short &result_height) override;
-
   unsigned int SendingMaxFs() override {
     if(mCurSendCodecConfig) {
       return mCurSendCodecConfig->mEncodingConstraints.maxFs;
     }
     return 0;
   }
 
   unsigned int SendingMaxFr() override {
@@ -544,16 +535,18 @@ private:
   int mPrefMaxBitrate;
   int mNegotiatedMaxBitrate;
   int mMinBitrateEstimate;
   bool mDenoising;
   bool mLockScaling; // for tests that care about output resolution
   uint8_t mSpatialLayers;
   uint8_t mTemporalLayers;
 
+  rtc::VideoSinkWants mLastSinkWanted;
+
   static const unsigned int sAlphaNum = 7;
   static const unsigned int sAlphaDen = 8;
   static const unsigned int sRoundingPadding = 1024;
 
   RefPtr<WebrtcAudioConduit> mSyncedTo;
 
   webrtc::VideoCodecMode mCodecMode;
 
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -57,9 +57,11 @@ function startup() {
   ModuleManager.add("resource://gre/modules/GeckoViewSettings.jsm",
                     "GeckoViewSettings");
   ModuleManager.add("resource://gre/modules/GeckoViewContent.jsm",
                     "GeckoViewContent");
   ModuleManager.add("resource://gre/modules/GeckoViewProgress.jsm",
                     "GeckoViewProgress");
   ModuleManager.add("resource://gre/modules/GeckoViewScroll.jsm",
                     "GeckoViewScroll");
+  ModuleManager.add("resource://gre/modules/GeckoViewTab.jsm",
+                    "GeckoViewTab");
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/modules/geckoview/GeckoViewTab.jsm
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["GeckoViewTab"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/GeckoViewModule.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "dump", () =>
+    Cu.import("resource://gre/modules/AndroidLog.jsm",
+              {}).AndroidLog.d.bind(null, "ViewTab"));
+
+function debug(aMsg) {
+  // dump(aMsg);
+}
+
+// Stub BrowserApp implementation for WebExtensions support.
+class GeckoViewTab extends GeckoViewModule {
+  init() {
+    this.browser.tab = { id: 0 };
+
+    this.window.BrowserApp = {
+      tabs: [this.browser.tab],
+      selectedTab: this.browser.tab,
+
+      getTabForId: function(aId) {
+        return this.selectedTab;
+      },
+
+      getTabForBrowser: function(aBrowser) {
+        return this.selectedTab;
+      },
+
+      getTabForWindow: function(aWindow) {
+        return this.selectedTab;
+      },
+
+      getTabForDocument: function(aDocument) {
+        return this.selectedTab;
+      },
+    };
+  }
+}
--- a/mobile/android/modules/geckoview/moz.build
+++ b/mobile/android/modules/geckoview/moz.build
@@ -8,10 +8,11 @@ EXTRA_JS_MODULES += [
     'AndroidLog.jsm',
     'GeckoViewContent.jsm',
     'GeckoViewContentModule.jsm',
     'GeckoViewModule.jsm',
     'GeckoViewNavigation.jsm',
     'GeckoViewProgress.jsm',
     'GeckoViewScroll.jsm',
     'GeckoViewSettings.jsm',
+    'GeckoViewTab.jsm',
     'Messaging.jsm',
 ]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5825,23 +5825,22 @@ pref("security.mixed_content.hsts_primin
 pref("security.data_uri.unique_opaque_origin", true);
 
 // TODO: Bug 1380959: Block toplevel data: URI navigations
 // If true, all toplevel data: URI navigations will be blocked.
 // Please note that manually entering a data: URI in the
 // URL-Bar will not be blocked when flipping this pref.
 pref("security.data_uri.block_toplevel_data_uri_navigations", false);
 
-// Disable Storage api in release builds.
-#if defined(NIGHTLY_BUILD) && !defined(MOZ_WIDGET_ANDROID)
+// Enable Storage API for all platforms except Android.
+#if !defined(MOZ_WIDGET_ANDROID)
 pref("dom.storageManager.enabled", true);
 #else
 pref("dom.storageManager.enabled", false);
 #endif
-
 pref("dom.storageManager.prompt.testing", false);
 pref("dom.storageManager.prompt.testing.allow", false);
 
 // Enable the Storage management in about:preferences and persistent-storage permission request
 // To enable the DOM implementation, turn on "dom.storageManager.enabled"
 #ifdef NIGHTLY_BUILD
 pref("browser.storageManager.enabled", true);
 #else
--- a/netwerk/base/nsISocketTransport.idl
+++ b/netwerk/base/nsISocketTransport.idl
@@ -233,21 +233,16 @@ interface nsISocketTransport : nsITransp
     /**
      * If set, do not use newer protocol features that might have interop problems
      * on the Internet. Intended only for use with critical infra like the updater.
      * default is false.
      */
     const unsigned long BE_CONSERVATIVE = (1 << 7);
 
     /**
-     * This transport has been created by a speculative connection attempt.
-     */
-    const unsigned long SPECULATIVE = (1 << 8);
-
-    /**
      * An opaque flags for non-standard behavior of the TLS system.
      * It is unlikely this will need to be set outside of telemetry studies
      * relating to the TLS implementation.
      */
     attribute unsigned long tlsFlags;
 
     /**
      * Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -1258,22 +1258,18 @@ nsSocketTransport::BuildSocket(PRFileDes
                 {
                     MutexAutoLock lock(mLock);
                     mSecInfo = secinfo;
                     callbacks = mCallbacks;
                     SOCKET_LOG(("  [secinfo=%p callbacks=%p]\n", mSecInfo.get(), mCallbacks.get()));
                 }
                 // don't call into PSM while holding mLock!!
                 nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
-                if (secCtrl) {
-                    if (mConnectionFlags & nsISocketTransport::SPECULATIVE) {
-                        secCtrl->SetSpeculative(true);
-                    }
+                if (secCtrl)
                     secCtrl->SetNotificationCallbacks(callbacks);
-                }
                 // remember if socket type is SSL so we can ProxyStartSSL if need be.
                 usingSSL = isSSL;
             }
             else if ((strcmp(mTypes[i], "socks") == 0) ||
                      (strcmp(mTypes[i], "socks4") == 0)) {
                 // since socks is transparent, any layers above
                 // it do not have to worry about proxy stuff
                 proxyInfo = nullptr;
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4432,17 +4432,26 @@ nsHttpChannel::OnCacheEntryAvailable(nsI
     if (!mIsPending) {
         mCacheInputStream.CloseAndRelease();
         return NS_OK;
     }
 
     rv = OnCacheEntryAvailableInternal(entry, aNew, aAppCache, status);
     if (NS_FAILED(rv)) {
         CloseCacheEntry(false);
-        Unused << AsyncAbort(rv);
+        if (mRaceCacheWithNetwork && mNetworkTriggered &&
+            mFirstResponseSource != RESPONSE_FROM_CACHE) {
+            // Ignore the error if we're racing cache with network and the cache
+            // didn't win, The network part will handle cancelation or any other
+            // error. Otherwise we could end up calling the listener twice, see
+            // bug 1397593.
+            LOG(("  not calling AsyncAbort() because we're racing cache with network"));
+        } else {
+            Unused << AsyncAbort(rv);
+        }
     }
 
     return NS_OK;
 }
 
 nsresult
 nsHttpChannel::OnCacheEntryAvailableInternal(nsICacheEntry *entry,
                                              bool aNew,
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -951,28 +951,16 @@ nsHttpConnection::CanReuse()
         return false;
     }
 
     if ((mTransaction ? (mTransaction->IsDone() ? 0U : 1U) : 0U) >=
         mRemainingConnectionUses) {
         return false;
     }
 
-    if (!mExperienced) {
-        uint32_t flags = 0;
-        mSocketTransport->GetConnectionFlags(&flags);
-        if (flags & nsISocketTransport::SPECULATIVE) {
-            if (gHttpHandler->ConnMgr()->IsSpeculativeConnectDisabled(mConnInfo)) {
-                LOG(("nsHttpConnection::CanReuse %p can't reuse because speculative"
-                      " connections are disabled for this host", this));
-                return false;
-            }
-        }
-    }
-
     bool canReuse;
     if (mSpdySession) {
         canReuse = mSpdySession->CanReuse();
     } else {
         canReuse = IsKeepAlive();
     }
     canReuse = canReuse && (IdleTime() < mIdleTimeout) && IsAlive();
 
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -80,17 +80,16 @@ public:
     void SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId);
 
     // OK to treat these as an infalible allocation
     nsHttpConnectionInfo* Clone() const;
     void CloneAsDirectRoute(nsHttpConnectionInfo **outParam);
     MOZ_MUST_USE nsresult CreateWildCard(nsHttpConnectionInfo **outParam);
 
     const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nullptr; }
-    const nsCString& GetProxyHost() const { return mProxyInfo ? mProxyInfo->Host() : EmptyCString(); }
     int32_t     ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
     const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nullptr; }
     const char *ProxyUsername() const { return mProxyInfo ? mProxyInfo->Username().get() : nullptr; }
     const char *ProxyPassword() const { return mProxyInfo ? mProxyInfo->Password().get() : nullptr; }
 
     // Compare this connection info to another...
     // Two connections are 'equal' if they end up talking the same
     // protocol to the same server. This is needed to properly manage
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3227,42 +3227,16 @@ bool nsHttpConnectionMgr::IsConnEntryUnd
     }
 
     nsTArray<RefPtr<PendingTransactionInfo>> *transactions =
         ent->mPendingTransactionTable.Get(mCurrentTopLevelOuterContentWindowId);
 
     return transactions && !transactions->IsEmpty();
 }
 
-void nsHttpConnectionMgr::DontPreconnect(nsACString const & host, int32_t port)
-{
-    MOZ_ASSERT(OnSocketThread(), "not on socket thread");
-
-    for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
-        RefPtr<nsConnectionEntry> ent = iter.Data();
-        nsHttpConnectionInfo* info = ent->mConnInfo;
-
-        if ((info->GetOrigin() == host && info->OriginPort() == port) ||
-            (info->ProxyInfo() && info->GetProxyHost() == host && info->ProxyPort() == port)) {
-
-            LOG(("nsHttpConnectionMgr::DontPreconnect disabling preconnects on %s",
-                 info->HashKey().get()));
-
-            ent->mDisallowPreconnects = true;
-        }
-    }
-}
-
-bool nsHttpConnectionMgr::IsSpeculativeConnectDisabled(nsHttpConnectionInfo *connInfo)
-{
-    nsConnectionEntry *ent = mCT.GetWeak(connInfo->HashKey());
-    return ent && ent->mDisallowPreconnects;
-}
-
-
 bool nsHttpConnectionMgr::IsThrottleTickerNeeded()
 {
     LOG(("nsHttpConnectionMgr::IsThrottleTickerNeeded"));
 
     if (mActiveTabUnthrottledTransactionsExist &&
         mActiveTransactions[false].Count() > 1) {
         LOG(("  there are unthrottled transactions for both active and bck"));
         return true;
@@ -3696,21 +3670,16 @@ nsHttpConnectionMgr::OnMsgSpeculativeCon
     SpeculativeConnectArgs *args = static_cast<SpeculativeConnectArgs *>(param);
 
     LOG(("nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=%s]\n",
          args->mTrans->ConnectionInfo()->HashKey().get()));
 
     nsConnectionEntry *ent =
         GetOrCreateConnectionEntry(args->mTrans->ConnectionInfo(), false);
 
-    if (ent->mDisallowPreconnects) {
-        LOG(("  explicitely disabled for this host:port"));
-        return;
-    }
-
     uint32_t parallelSpeculativeConnectLimit =
         gHttpHandler->ParallelSpeculativeConnectLimit();
     bool ignoreIdle = false;
     bool isFromPredictor = false;
     bool allow1918 = false;
 
     if (args->mOverridesOK) {
         parallelSpeculativeConnectLimit = args->mParallelSpeculativeConnectLimit;
@@ -3920,20 +3889,16 @@ nsHalfOpenSocket::SetupStreams(nsISocket
              (isBackup && gHttpHandler->FastFallbackToIPv4())) {
         tmpFlags |= nsISocketTransport::DISABLE_IPV6;
     }
 
     if (!Allow1918()) {
         tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
     }
 
-    if (mSpeculative) {
-        tmpFlags |= nsISocketTransport::SPECULATIVE;
-    }
-
     if (!isBackup && mEnt->mUseFastOpen) {
         socketTransport->SetFastOpenCallback(this);
     }
 
     socketTransport->SetConnectionFlags(tmpFlags);
     socketTransport->SetTlsFlags(ci->GetTlsFlags());
 
     const OriginAttributes& originAttributes = mEnt->mConnInfo->GetOriginAttributes();
@@ -4988,17 +4953,16 @@ ConnectionHandle::TopLevelOuterContentWi
 nsHttpConnectionMgr::
 nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
     : mConnInfo(ci)
     , mUsingSpdy(false)
     , mPreferIPv4(false)
     , mPreferIPv6(false)
     , mUsedForConnection(false)
     , mDoNotDestroy(false)
-    , mDisallowPreconnects(false)
 {
     MOZ_COUNT_CTOR(nsConnectionEntry);
 
     if (mConnInfo->FirstHopSSL()) {
 #if defined(_WIN64) && defined(WIN95)
         mUseFastOpen = gHttpHandler->UseFastOpen() &&
                        gSocketTransportService->HasFileDesc2PlatformOverlappedIOHandleFunc();
 #else
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -237,25 +237,16 @@ public:
     void TouchThrottlingTimeWindow(bool aEnsureTicker = true);
 
     // return true iff the connection has pending transactions for the active tab.
     // it's mainly used to disallow throttling (stop reading) of a response
     // belonging to the same conn info to free up a connection ASAP.
     // NOTE: relatively expensive to call, there are two hashtable lookups.
     bool IsConnEntryUnderPressure(nsHttpConnectionInfo*);
 
-    // This disables preconnecting for all existing connection entries matching
-    // the host and port.  Existing speculative connections that have never been
-    // used will not be used.
-    void DontPreconnect(nsACString const &host, int32_t port);
-
-    // The information is stored on the entry, not on conn-info (which is just
-    // a passive descriptor).
-    bool IsSpeculativeConnectDisabled(nsHttpConnectionInfo*);
-
     uint64_t CurrentTopLevelOuterContentWindowId()
     {
         return mCurrentTopLevelOuterContentWindowId;
     }
 
 private:
     virtual ~nsHttpConnectionMgr();
 
@@ -323,18 +314,16 @@ private:
         // True if this connection entry has initiated a socket
         bool mUsedForConnection : 1;
 
         // Try using TCP Fast Open.
         bool mUseFastOpen : 1;
 
         bool mDoNotDestroy : 1;
 
-        bool mDisallowPreconnects : 1;
-
         // Set the IP family preference flags according the connected family
         void RecordIPFamilyPreference(uint16_t family);
         // Resets all flags to their default values
         void ResetIPFamilyPreference();
 
         // Return the count of pending transactions for all window ids.
         size_t PendingQLength() const;
 
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -2270,25 +2270,16 @@ nsHttpHandler::GetOscpu(nsACString &valu
 
 NS_IMETHODIMP
 nsHttpHandler::GetMisc(nsACString &value)
 {
     value = mMisc;
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHttpHandler::DontPreconnect(nsACString const &host, int32_t port)
-{
-    if (mConnMgr) {
-        mConnMgr->DontPreconnect(host, port);
-    }
-    return NS_OK;
-};
-
 //-----------------------------------------------------------------------------
 // nsHttpHandler::nsIObserver
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpHandler::Observe(nsISupports *subject,
                        const char *topic,
                        const char16_t *data)
--- a/netwerk/protocol/http/nsIHttpProtocolHandler.idl
+++ b/netwerk/protocol/http/nsIHttpProtocolHandler.idl
@@ -42,22 +42,16 @@ interface nsIHttpProtocolHandler : nsIPr
      */
     [must_use] readonly attribute ACString oscpu;
 
     /**
      * Get the application comment misc portion.
      */
     [must_use] readonly attribute ACString misc;
 
-    /**
-     * Blocks preconnection for the given host:port
-     * This is used mainly to prevent client cert selection dialogs
-     * to pop-up too early.
-     */
-    void dontPreconnect(in ACString host, in int32_t port);
 };
 
 %{C++
 // ----------- Categories -----------
 /**
  * At initialization time, the HTTP handler will initialize each service
  * registered under this category:
  */
--- a/netwerk/socket/nsISSLSocketControl.idl
+++ b/netwerk/socket/nsISSLSocketControl.idl
@@ -17,23 +17,16 @@ interface nsIX509Cert;
 
 [scriptable, builtinclass, uuid(418265c8-654e-4fbb-ba62-4eed27de1f03)]
 interface nsISSLSocketControl : nsISupports {
     attribute nsIInterfaceRequestor     notificationCallbacks;
 
     void proxyStartSSL();
     void StartTLS();
 
-    /**
-     * Whether this socket has been created by a speculative connection
-     * attempt.  This will mainly prevent client certificate dialog to
-     * pop-up.
-     */
-    attribute boolean speculative;
-
     /* NPN (Next Protocol Negotiation) is a mechanism for
        negotiating the protocol to be spoken inside the SSL
        tunnel during the SSL handshake. The NPNList is the list
        of offered client side protocols. setNPNList() needs to
        be called before any data is read or written (including the
        handshake to be setup correctly. The server determines the
        priority when multiple matches occur, but if there is no overlap
        the first protocol in the list is used. */
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -440,17 +440,19 @@ nsHtml5TreeOperation::CreateHTMLElement(
       } else {
         newContent->SetAttr(nsuri,
                             localName,
                             prefix,
                             value,
                             false);
 
         // Custom element setup may be needed if there is an "is" attribute.
-        if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
+        if (nsContentUtils::IsWebComponentsEnabled() &&
+            kNameSpaceID_None == nsuri &&
+            !prefix && nsGkAtoms::is == localName) {
           nsContentUtils::SetupCustomElement(newContent, &value);
         }
       }
     }
   }
   return newContent;
 }
 
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -24,17 +24,16 @@
 #include "nsArray.h"
 #include "nsArrayUtils.h"
 #include "nsCRT.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsClientAuthRemember.h"
 #include "nsContentUtils.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsIConsoleService.h"
-#include "nsIHttpProtocolHandler.h"
 #include "nsIPrefService.h"
 #include "nsISocketProvider.h"
 #include "nsIWebProgressListener.h"
 #include "nsNSSCertHelper.h"
 #include "nsNSSComponent.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "pkix/pkixtypes.h"
@@ -119,17 +118,16 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedS
                                  uint32_t providerTlsFlags)
   : mFd(nullptr),
     mCertVerificationState(before_cert_verification),
     mSharedState(aState),
     mForSTARTTLS(false),
     mHandshakePending(true),
     mRememberClientAuthCertificate(false),
     mPreliminaryHandshakeDone(false),
-    mSpeculative(false),
     mNPNCompleted(false),
     mEarlyDataAccepted(false),
     mFalseStartCallbackCalled(false),
     mFalseStarted(false),
     mIsFullHandshake(false),
     mHandshakeCompleted(false),
     mJoined(false),
     mSentClientCert(false),
@@ -332,30 +330,16 @@ nsNSSSocketInfo::SetHandshakeCompleted()
     mHandshakeCompleted = true;
 
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*) mFd));
 
     mIsFullHandshake = false; // reset for next handshake on this connection
 }
 
-NS_IMETHODIMP
-nsNSSSocketInfo::GetSpeculative(bool *aSpeculative)
-{
-  *aSpeculative = mSpeculative;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNSSSocketInfo::SetSpeculative(bool aSpeculative)
-{
-  mSpeculative = aSpeculative;
-  return NS_OK;
-}
-
 void
 nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length)
 {
   if (!value) {
     mNegotiatedNPN.Truncate();
   } else {
     mNegotiatedNPN.Assign(value, length);
   }
@@ -2187,47 +2171,31 @@ nsNSS_SSLGetClientAuthData(void* arg, PR
   if (!socket || !caNames || !pRetCert || !pRetKey) {
     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     return SECFailure;
   }
 
   RefPtr<nsNSSSocketInfo> info(
     BitwiseCast<nsNSSSocketInfo*, PRFilePrivate*>(socket->higher->secret));
 
-  if (info->IsSpeculative()) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-      ("[%p] Blocking speculative SSL connections that ask for client cert creds\n", socket->higher));
-
-    nsCOMPtr<nsIHttpProtocolHandler> handler(
-      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
-
-    if (handler) {
-      handler->DontPreconnect(info->GetHostName(), info->GetPort());
-
-      // Bail, this socket will not be used anyway.
-      PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
-      return SECFailure;
-    }
-  }
-
   UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket));
   if (!serverCert) {
     MOZ_ASSERT_UNREACHABLE(
       "Missing server cert should have been detected during server cert auth.");
     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
     return SECFailure;
   }
 
   if (info->GetJoined()) {
     // We refuse to send a client certificate when there are multiple hostnames
     // joined on this connection, because we only show the user one hostname
     // (mHostName) in the client certificate UI.
 
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-           ("[%p] Not returning client cert due to previous join\n", socket->higher));
+           ("[%p] Not returning client cert due to previous join\n", socket));
     *pRetCert = nullptr;
     *pRetKey = nullptr;
     return SECSuccess;
   }
 
   // XXX: This should be done asynchronously; see bug 696976
   RefPtr<ClientAuthDataRunnable> runnable(
     new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
--- a/security/manager/ssl/nsNSSIOLayer.h
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -44,18 +44,16 @@ public:
   NS_DECL_NSICLIENTAUTHUSERDECISION
 
   void SetForSTARTTLS(bool aForSTARTTLS);
   bool GetForSTARTTLS();
 
   nsresult GetFileDescPtr(PRFileDesc** aFilePtr);
   nsresult SetFileDescPtr(PRFileDesc* aFilePtr);
 
-  bool IsSpeculative() { return mSpeculative; }
-
   bool IsHandshakePending() const { return mHandshakePending; }
   void SetHandshakeNotPending() { mHandshakePending = false; }
 
   void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; }
   SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; };
 
   PRStatus CloseSocketAndDestroy(
                 const nsNSSShutDownPreventionLock& proofOfLock);
@@ -181,17 +179,16 @@ private:
   SSLVersionRange mTLSVersionRange;
   bool mHandshakePending;
   bool mRememberClientAuthCertificate;
   bool mPreliminaryHandshakeDone; // after false start items are complete
 
   nsresult ActivateSSL();
 
   nsCString mNegotiatedNPN;
-  bool      mSpeculative;
   bool      mNPNCompleted;
   bool      mEarlyDataAccepted;
   bool      mFalseStartCallbackCalled;
   bool      mFalseStarted;
   bool      mIsFullHandshake;
   bool      mHandshakeCompleted;
   bool      mJoined;
   bool      mSentClientCert;
--- a/security/nss.symbols
+++ b/security/nss.symbols
@@ -709,16 +709,17 @@ VFY_Update
 VFY_VerifyData
 VFY_VerifyDataWithAlgorithmID
 VFY_VerifyDigestDirect
 _SGN_VerifyPKCS1DigestInfo
 __PK11_SetCertificateNickname
 # These symbols are not used by Firefox but are used across NSS library boundaries.
 NSS_SecureMemcmpZero
 PORT_ZAllocAlignedOffset_Util
+CERT_FindCertByNicknameOrEmailAddrCX
 # These symbols are not used by Firefox itself, but are used by Java's security
 # libraries, which in turn are used by Java applets/plugins/etc.  Provide them
 # to make Java code happy.
 NSS_VersionCheck
 NSS_Initialize
 #ifdef NSS_EXTRA_SYMBOLS_FILE
 #include @NSS_EXTRA_SYMBOLS_FILE@
 #endif
--- a/security/nss/.taskcluster.yml
+++ b/security/nss/.taskcluster.yml
@@ -52,17 +52,17 @@ tasks:
       tags:
         createdForUser: {{owner}}
 
       routes:
         - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
         - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
       payload:
-        image: ttaubert/nss-decision:0.0.2
+        image: nssdev/nss-decision:0.0.2
 
         env:
           TC_OWNER: {{owner}}
           TC_SOURCE: {{{source}}}
           TC_PROJECT: {{project}}
           TC_COMMENT: '{{comment}}'
           NSS_PUSHLOG_ID: '{{pushlog_id}}'
           NSS_HEAD_REPOSITORY: '{{{url}}}'
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-4bf658832d89
+a83094ccf952
--- a/security/nss/automation/taskcluster/docker-decision/Dockerfile
+++ b/security/nss/automation/taskcluster/docker-decision/Dockerfile
@@ -7,16 +7,19 @@ WORKDIR /home/worker
 # Add build and test scripts.
 ADD bin /home/worker/bin
 RUN chmod +x /home/worker/bin/*
 
 # Install dependencies.
 ADD setup.sh /tmp/setup.sh
 RUN bash /tmp/setup.sh
 
+# Change user.
+USER worker
+
 # Env variables.
 ENV HOME /home/worker
 ENV SHELL /bin/bash
 ENV USER worker
 ENV LOGNAME worker
 ENV HOSTNAME taskcluster-worker
 ENV LANG en_US.UTF-8
 ENV LC_ALL en_US.UTF-8
--- a/security/nss/automation/taskcluster/docker-decision/bin/checkout.sh
+++ b/security/nss/automation/taskcluster/docker-decision/bin/checkout.sh
@@ -1,17 +1,12 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
-if [ $(id -u) = 0 ]; then
-    # Drop privileges by re-running this script.
-    exec su worker $0
-fi
-
 # Default values for testing.
 REVISION=${NSS_HEAD_REVISION:-default}
 REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
 
 # Clone NSS.
 for i in 0 2 5; do
     sleep $i
     hg clone -r $REVISION $REPOSITORY nss && exit 0
--- a/security/nss/automation/taskcluster/graph/src/context_hash.js
+++ b/security/nss/automation/taskcluster/graph/src/context_hash.js
@@ -22,22 +22,32 @@ function collectFilesInDirectory(dir) {
     if (fs.lstatSync(entry_path).isDirectory()) {
       return collectFilesInDirectory(entry_path);
     }
 
     return [entry_path];
   });
 }
 
-// Compute a context hash for the given context path.
-export default function (context_path) {
+// A list of hashes for each file in the given path.
+function collectFileHashes(context_path) {
   let root = path.join(__dirname, "../../../..");
   let dir = path.join(root, context_path);
   let files = collectFilesInDirectory(dir).sort();
-  let hashes = files.map(file => {
+
+  return files.map(file => {
     return sha256(file + "|" + fs.readFileSync(file, "utf-8"));
   });
+}
+
+// Compute a context hash for the given context path.
+export default function (context_path) {
+  // Regenerate all images when the image_builder changes.
+  let hashes = collectFileHashes("automation/taskcluster/image_builder");
+
+  // Regenerate images when the image itself changes.
+  hashes = hashes.concat(collectFileHashes(context_path));
 
   // Generate a new prefix every month to ensure the image stays buildable.
   let now = new Date();
   let prefix = `${now.getUTCFullYear()}-${now.getUTCMonth() + 1}:`;
   return sha256(prefix + hashes.join(","));
 }
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -554,22 +554,23 @@ async function scheduleFuzzing() {
 
   // Schedule fuzzing runs.
   let run_base = merge(base, {parent: task_build, kind: "test"});
   scheduleFuzzingRun(run_base, "CertDN", "certDN", 4096);
   scheduleFuzzingRun(run_base, "QuickDER", "quickder", 10000);
 
   // Schedule MPI fuzzing runs.
   let mpi_base = merge(run_base, {group: "MPI"});
-  let mpi_names = ["add", "addmod", "div", "expmod", "mod", "mulmod", "sqr",
+  let mpi_names = ["add", "addmod", "div", "mod", "mulmod", "sqr",
                    "sqrmod", "sub", "submod"];
   for (let name of mpi_names) {
     scheduleFuzzingRun(mpi_base, `MPI (${name})`, `mpi-${name}`, 4096, name);
   }
   scheduleFuzzingRun(mpi_base, `MPI (invmod)`, `mpi-invmod`, 256, "invmod");
+  scheduleFuzzingRun(mpi_base, `MPI (expmod)`, `mpi-expmod`, 2048, "expmod");
 
   // Schedule TLS fuzzing runs (non-fuzzing mode).
   let tls_base = merge(run_base, {group: "TLS"});
   scheduleFuzzingRun(tls_base, "TLS Client", "tls-client", 20000, "client-nfm",
                      "tls-client-no_fuzzer_mode");
   scheduleFuzzingRun(tls_base, "TLS Server", "tls-server", 20000, "server-nfm",
                      "tls-server-no_fuzzer_mode");
   scheduleFuzzingRun(tls_base, "DTLS Client", "dtls-client", 20000,
--- a/security/nss/automation/taskcluster/graph/src/image_builder.js
+++ b/security/nss/automation/taskcluster/graph/src/image_builder.js
@@ -26,37 +26,35 @@ export async function findTask({name, pa
 }
 
 export async function buildTask({name, path}) {
   let hash = await context_hash(path);
   let ns = `docker.images.v1.${process.env.TC_PROJECT}.${name}.hash.${hash}`;
 
   return {
     name: "Image Builder",
-    image: "taskcluster/image_builder:0.1.5",
+    image: "nssdev/image_builder:0.1.5",
     routes: ["index." + ns],
     env: {
-      HEAD_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
-      BASE_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
-      HEAD_REV: process.env.NSS_HEAD_REVISION,
-      HEAD_REF: process.env.NSS_HEAD_REVISION,
+      NSS_HEAD_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
+      NSS_HEAD_REVISION: process.env.NSS_HEAD_REVISION,
       PROJECT: process.env.TC_PROJECT,
       CONTEXT_PATH: path,
       HASH: hash
     },
     artifacts: {
       "public/image.tar": {
         type: "file",
         expires: 24 * 90,
         path: "/artifacts/image.tar"
       }
     },
     command: [
       "/bin/bash",
       "-c",
-      "/home/worker/bin/build_image.sh"
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/build_image.sh"
     ],
     platform: "nss-decision",
     features: ["dind"],
     kind: "build",
     symbol: "I"
   };
 }
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/image_builder/Dockerfile
@@ -0,0 +1,23 @@
+FROM ubuntu:16.04
+MAINTAINER Tim Taubert <ttaubert@mozilla.com>
+
+WORKDIR /home/worker
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get update && apt-get install -y apt-transport-https apt-utils
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \
+    sh -c "echo deb https://get.docker.io/ubuntu docker main \
+    > /etc/apt/sources.list.d/docker.list"
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE && \
+    sh -c "echo deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu xenial main \
+    > /etc/apt/sources.list.d/mercurial.list"
+RUN apt-get update && apt-get install -y \
+    lxc-docker-1.6.1 \
+    mercurial
+
+ADD bin /home/worker/bin
+RUN chmod +x /home/worker/bin/*
+
+# Set a default command useful for debugging
+CMD ["/bin/bash", "--login"]
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/image_builder/VERSION
@@ -0,0 +1,1 @@
+0.1.5
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/image_builder/bin/checkout.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Default values for testing.
+REVISION=${NSS_HEAD_REVISION:-default}
+REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
+
+# Clone NSS.
+for i in 0 2 5; do
+    sleep $i
+    hg clone -r $REVISION $REPOSITORY nss && exit 0
+    rm -rf nss
+done
+exit 1
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/build_image.sh
@@ -0,0 +1,24 @@
+#!/bin/bash -vex
+
+set -x -e -v
+
+# Prefix errors with taskcluster error prefix so that they are parsed by Treeherder
+raise_error() {
+   echo
+   echo "[taskcluster-image-build:error] $1"
+   exit 1
+}
+
+# Ensure that the PROJECT is specified so the image can be indexed
+test -n "$PROJECT" || raise_error "Project must be provided."
+test -n "$HASH" || raise_error "Context Hash must be provided."
+
+CONTEXT_PATH=/home/worker/nss/$CONTEXT_PATH
+
+test -d $CONTEXT_PATH || raise_error "Context Path $CONTEXT_PATH does not exist."
+test -f "$CONTEXT_PATH/Dockerfile" || raise_error "Dockerfile must be present in $CONTEXT_PATH."
+
+docker build -t $PROJECT:$HASH $CONTEXT_PATH
+
+mkdir /artifacts
+docker save $PROJECT:$HASH > /artifacts/image.tar
--- a/security/nss/cmd/bltest/blapitest.c
+++ b/security/nss/cmd/bltest/blapitest.c
@@ -15,26 +15,24 @@
 #include "nssb64.h"
 #include "basicutil.h"
 #include "plgetopt.h"
 #include "softoken.h"
 #include "nspr.h"
 #include "secport.h"
 #include "secoid.h"
 #include "nssutil.h"
+#include "ecl-curve.h"
 
 #include "pkcs1_vectors.h"
 
-#ifndef NSS_DISABLE_ECC
-#include "ecl-curve.h"
 SECStatus EC_DecodeParams(const SECItem *encodedParams,
                           ECParams **ecparams);
 SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
                         const ECParams *srcParams);
-#endif
 
 char *progName;
 char *testdir = NULL;
 
 #define BLTEST_DEFAULT_CHUNKSIZE 4096
 
 #define WORDSIZE sizeof(unsigned long)
 
@@ -130,28 +128,24 @@ Usage()
     PRINTUSAGE("", "-b", "size of input buffer");
     PRINTUSAGE("", "-p", "do performance test");
     PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads");
     PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)");
     fprintf(stderr, "\n");
     PRINTUSAGE(progName, "-S -m mode", "Sign a buffer");
     PRINTUSAGE("", "", "[-i plaintext] [-o signature] [-k key]");
     PRINTUSAGE("", "", "[-b bufsize]");
-#ifndef NSS_DISABLE_ECC
     PRINTUSAGE("", "", "[-n curvename]");
-#endif
     PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]");
     PRINTUSAGE("", "-m", "cipher mode to use");
     PRINTUSAGE("", "-i", "file which contains input buffer");
     PRINTUSAGE("", "-o", "file for signature");
     PRINTUSAGE("", "-k", "file which contains key");
-#ifndef NSS_DISABLE_ECC
     PRINTUSAGE("", "-n", "name of curve for EC key generation; one of:");
     PRINTUSAGE("", "", "  nistp256, nistp384, nistp521");
-#endif
     PRINTUSAGE("", "-p", "do performance test");
     PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads");
     PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)");
     fprintf(stderr, "\n");
     PRINTUSAGE(progName, "-V -m mode", "Verify a signed buffer");
     PRINTUSAGE("", "", "[-i plaintext] [-s signature] [-k key]");
     PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]");
     PRINTUSAGE("", "-m", "cipher mode to use");
@@ -364,17 +358,16 @@ dsakey_from_filedata(PLArenaPool *arena,
 {
     DSAPrivateKey *key;
     key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
     key->params.arena = arena;
     key_from_filedata(arena, &key->params.prime, 0, 5, filedata);
     return key;
 }
 
-#ifndef NSS_DISABLE_ECC
 static ECPrivateKey *
 eckey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     ECPrivateKey *key;
     SECStatus rv;
     ECParams *tmpECParams = NULL;
     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
     /* read and convert params */
@@ -514,17 +507,16 @@ getECParams(const char *curve)
      * oidData->oid.data so we simply prepend 0x06 and OID length
      */
     ecparams->data[0] = SEC_ASN1_OBJECT_ID;
     ecparams->data[1] = oidData->oid.len;
     memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
 
     return ecparams;
 }
-#endif /* NSS_DISABLE_ECC */
 
 static void
 dump_pqg(PQGParams *pqg)
 {
     SECU_PrintInteger(stdout, &pqg->prime, "PRIME:", 0);
     SECU_PrintInteger(stdout, &pqg->subPrime, "SUBPRIME:", 0);
     SECU_PrintInteger(stdout, &pqg->base, "BASE:", 0);
 }
@@ -532,32 +524,30 @@ dump_pqg(PQGParams *pqg)
 static void
 dump_dsakey(DSAPrivateKey *key)
 {
     dump_pqg(&key->params);
     SECU_PrintInteger(stdout, &key->publicValue, "PUBLIC VALUE:", 0);
     SECU_PrintInteger(stdout, &key->privateValue, "PRIVATE VALUE:", 0);
 }
 
-#ifndef NSS_DISABLE_ECC
 static void
 dump_ecp(ECParams *ecp)
 {
     /* TODO other fields */
     SECU_PrintInteger(stdout, &ecp->base, "BASE POINT:", 0);
 }
 
 static void
 dump_eckey(ECPrivateKey *key)
 {
     dump_ecp(&key->ecParams);
     SECU_PrintInteger(stdout, &key->publicValue, "PUBLIC VALUE:", 0);
     SECU_PrintInteger(stdout, &key->privateValue, "PRIVATE VALUE:", 0);
 }
-#endif
 
 static void
 dump_rsakey(RSAPrivateKey *key)
 {
     SECU_PrintInteger(stdout, &key->version, "VERSION:", 0);
     SECU_PrintInteger(stdout, &key->modulus, "MODULUS:", 0);
     SECU_PrintInteger(stdout, &key->publicExponent, "PUBLIC EXP:", 0);
     SECU_PrintInteger(stdout, &key->privateExponent, "PRIVATE EXP:", 0);
@@ -633,27 +623,25 @@ typedef enum {
     bltestCAMELLIA_ECB, /* .                     */
     bltestCAMELLIA_CBC, /* .                     */
     bltestSEED_ECB,     /* SEED algorithm      */
     bltestSEED_CBC,     /* SEED algorithm      */
     bltestCHACHA20,     /* ChaCha20 + Poly1305   */
     bltestRSA,          /* Public Key Ciphers    */
     bltestRSA_OAEP,     /* . (Public Key Enc.)   */
     bltestRSA_PSS,      /* . (Public Key Sig.)   */
-#ifndef NSS_DISABLE_ECC
-    bltestECDSA, /* . (Public Key Sig.)   */
-#endif
-    bltestDSA,    /* . (Public Key Sig.)   */
-    bltestMD2,    /* Hash algorithms       */
-    bltestMD5,    /* .             */
-    bltestSHA1,   /* .             */
-    bltestSHA224, /* .             */
-    bltestSHA256, /* .             */
-    bltestSHA384, /* .             */
-    bltestSHA512, /* .             */
+    bltestECDSA,        /* . (Public Key Sig.)   */
+    bltestDSA,          /* . (Public Key Sig.)   */
+    bltestMD2,          /* Hash algorithms       */
+    bltestMD5,          /* .             */
+    bltestSHA1,         /* .             */
+    bltestSHA224,       /* .             */
+    bltestSHA256,       /* .             */
+    bltestSHA384,       /* .             */
+    bltestSHA512,       /* .             */
     NUMMODES
 } bltestCipherMode;
 
 static char *mode_strings[] =
     {
       "des_ecb",
       "des_cbc",
       "des3_ecb",
@@ -673,19 +661,17 @@ static char *mode_strings[] =
       "camellia_ecb",
       "camellia_cbc",
       "seed_ecb",
       "seed_cbc",
       "chacha20_poly1305",
       "rsa",
       "rsa_oaep",
       "rsa_pss",
-#ifndef NSS_DISABLE_ECC
       "ecdsa",
-#endif
       /*"pqg",*/
       "dsa",
       "md2",
       "md5",
       "sha1",
       "sha224",
       "sha256",
       "sha384",
@@ -727,38 +713,34 @@ typedef struct
 {
     bltestIO pqgdata;
     unsigned int keysize;
     bltestIO keyseed;
     bltestIO sigseed;
     PQGParams *pqg;
 } bltestDSAParams;
 
-#ifndef NSS_DISABLE_ECC
 typedef struct
 {
     char *curveName;
     bltestIO sigseed;
 } bltestECDSAParams;
-#endif
 
 typedef struct
 {
     bltestIO key;
     void *privKey;
     void *pubKey;
     bltestIO sig; /* if doing verify, the signature (which may come
                    * from sigfile. */
 
     union {
         bltestRSAParams rsa;
         bltestDSAParams dsa;
-#ifndef NSS_DISABLE_ECC
         bltestECDSAParams ecdsa;
-#endif
     } cipherParams;
 } bltestAsymKeyParams;
 
 typedef struct
 {
     bltestIO key; /* unused */
     PRBool restart;
 } bltestHashParams;
@@ -1305,17 +1287,16 @@ dsa_signDigest(void *cx, SECItem *output
 
 SECStatus
 dsa_verifyDigest(void *cx, SECItem *output, const SECItem *input)
 {
     bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx;
     return DSA_VerifyDigest((DSAPublicKey *)params->pubKey, output, input);
 }
 
-#ifndef NSS_DISABLE_ECC
 SECStatus
 ecdsa_signDigest(void *cx, SECItem *output, const SECItem *input)
 {
     bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx;
     if (params->cipherParams.ecdsa.sigseed.buf.len > 0) {
         return ECDSA_SignDigestWithSeed(
             (ECPrivateKey *)params->privKey,
             output, input,
@@ -1326,17 +1307,16 @@ ecdsa_signDigest(void *cx, SECItem *outp
 }
 
 SECStatus
 ecdsa_verifyDigest(void *cx, SECItem *output, const SECItem *input)
 {
     bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx;
     return ECDSA_VerifyDigest((ECPublicKey *)params->pubKey, output, input);
 }
-#endif
 
 SECStatus
 bltest_des_init(bltestCipherInfo *cipherInfo, PRBool encrypt)
 {
     PRIntervalTime time1, time2;
     bltestSymmKeyParams *desp = &cipherInfo->params.sk;
     int minorMode;
     int i;
@@ -1806,17 +1786,16 @@ bltest_dsa_init(bltestCipherInfo *cipher
         pubkey->publicValue.len = key->publicValue.len;
         pubkey->publicValue.data = key->publicValue.data;
         asymk->pubKey = pubkey;
         cipherInfo->cipher.pubkeyCipher = dsa_verifyDigest;
     }
     return SECSuccess;
 }
 
-#ifndef NSS_DISABLE_ECC
 SECStatus
 bltest_ecdsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt)
 {
     int i;
     ECPrivateKey **dummyKey;
     PRIntervalTime time1, time2;
     bltestAsymKeyParams *asymk = &cipherInfo->params.asymk;
     cipherInfo->cx = asymk;
@@ -1872,17 +1851,16 @@ bltest_ecdsa_init(bltestCipherInfo *ciph
         pubkey->ecParams.name = key->ecParams.name;
         pubkey->publicValue.len = key->publicValue.len;
         pubkey->publicValue.data = key->publicValue.data;
         asymk->pubKey = pubkey;
         cipherInfo->cipher.pubkeyCipher = ecdsa_verifyDigest;
     }
     return SECSuccess;
 }
-#endif
 
 /* XXX unfortunately, this is not defined in blapi.h */
 SECStatus
 md2_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length)
 {
     unsigned int len;
     MD2Context *cx = MD2_NewContext();
     if (cx == NULL)
@@ -2164,35 +2142,29 @@ SHA512_restart(unsigned char *dest, cons
     SHA512_End(cx, dest, &len, MD5_LENGTH);
 finish:
     SHA512_DestroyContext(cx, PR_TRUE);
     return rv;
 }
 
 SECStatus
 pubkeyInitKey(bltestCipherInfo *cipherInfo, PRFileDesc *file,
-#ifndef NSS_DISABLE_ECC
               int keysize, int exponent, char *curveName)
-#else
-              int keysize, int exponent)
-#endif
 {
     int i;
     SECStatus rv = SECSuccess;
     bltestAsymKeyParams *asymk = &cipherInfo->params.asymk;
     bltestRSAParams *rsap;
     RSAPrivateKey **rsaKey = NULL;
     bltestDSAParams *dsap;
     DSAPrivateKey **dsaKey = NULL;
-#ifndef NSS_DISABLE_ECC
     SECItem *tmpECParamsDER;
     ECParams *tmpECParams = NULL;
     SECItem ecSerialize[3];
     ECPrivateKey **ecKey = NULL;
-#endif
     switch (cipherInfo->mode) {
         case bltestRSA:
         case bltestRSA_PSS:
         case bltestRSA_OAEP:
             rsap = &asymk->cipherParams.rsa;
             rsaKey = (RSAPrivateKey **)&asymk->privKey;
             if (keysize > 0) {
                 SECItem expitem = { 0, 0, 0 };
@@ -2219,17 +2191,16 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 CHECKERROR(rv, __LINE__);
                 serialize_key(&(*dsaKey)->params.prime, 5, file);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
                 *dsaKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
                 dsap->keysize = (*dsaKey)->params.prime.len * 8;
             }
             break;
-#ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             ecKey = (ECPrivateKey **)&asymk->privKey;
             if (curveName != NULL) {
                 tmpECParamsDER = getECParams(curveName);
                 rv = SECOID_Init();
                 CHECKERROR(rv, __LINE__);
                 rv = EC_DecodeParams(tmpECParamsDER, &tmpECParams) == SECFailure;
                 CHECKERROR(rv, __LINE__);
@@ -2249,17 +2220,16 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 PORT_FreeArena(tmpECParams->arena, PR_TRUE);
                 rv = SECOID_Shutdown();
                 CHECKERROR(rv, __LINE__);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
                 *ecKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
             }
             break;
-#endif
         default:
             return SECFailure;
     }
     return SECSuccess;
 }
 
 SECStatus
 cipherInit(bltestCipherInfo *cipherInfo, PRBool encrypt)
@@ -2336,25 +2306,23 @@ cipherInit(bltestCipherInfo *cipherInfo,
             break;
         case bltestDSA:
             if (encrypt) {
                 SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf,
                                   DSA_MAX_SIGNATURE_LEN);
             }
             return bltest_dsa_init(cipherInfo, encrypt);
             break;
-#ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             if (encrypt) {
                 SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf,
                                   2 * MAX_ECKEY_LEN);
             }
             return bltest_ecdsa_init(cipherInfo, encrypt);
             break;
-#endif
         case bltestMD2:
             restart = cipherInfo->params.hash.restart;
             SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf,
                               MD2_LENGTH);
             cipherInfo->cipher.hashCipher = (restart) ? md2_restart : md2_HashBuf;
             return SECSuccess;
             break;
         case bltestMD5:
@@ -2639,19 +2607,17 @@ cipherFinish(bltestCipherInfo *cipherInf
         case bltestRC5_CBC:
             RC5_DestroyContext((RC5Context *)cipherInfo->cx, PR_TRUE);
             break;
 #endif
         case bltestRSA:     /* keys are alloc'ed within cipherInfo's arena, */
         case bltestRSA_PSS: /* will be freed with it. */
         case bltestRSA_OAEP:
         case bltestDSA:
-#ifndef NSS_DISABLE_ECC
         case bltestECDSA:
-#endif
         case bltestMD2: /* hash contexts are ephemeral */
         case bltestMD5:
         case bltestSHA1:
         case bltestSHA224:
         case bltestSHA256:
         case bltestSHA384:
         case bltestSHA512:
             return SECSuccess;
@@ -2817,28 +2783,26 @@ print_td:
             break;
         case bltestDSA:
             if (td) {
                 fprintf(stdout, "%8s", "pqg_mod");
             } else {
                 fprintf(stdout, "%8d", info->params.asymk.cipherParams.dsa.keysize);
             }
             break;
-#ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             if (td) {
                 fprintf(stdout, "%12s", "ec_curve");
             } else {
                 ECPrivateKey *key = (ECPrivateKey *)info->params.asymk.privKey;
                 ECCurveName curveName = key->ecParams.name;
                 fprintf(stdout, "%12s",
                         ecCurve_map[curveName] ? ecCurve_map[curveName]->text : "Unsupported curve");
             }
             break;
-#endif
         case bltestMD2:
         case bltestMD5:
         case bltestSHA1:
         case bltestSHA256:
         case bltestSHA384:
         case bltestSHA512:
         default:
             break;
@@ -3058,29 +3022,27 @@ get_params(PLArenaPool *arena, bltestPar
             load_file_data(arena, &params->asymk.cipherParams.dsa.keyseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.sigseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
-#ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename, bltestBase64Encoded);
             params->asymk.privKey =
                 (void *)eckey_from_filedata(arena, &params->asymk.key.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.ecdsa.sigseed,
                            filename, bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
-#endif
         case bltestMD2:
         case bltestMD5:
         case bltestSHA1:
         case bltestSHA224:
         case bltestSHA256:
         case bltestSHA384:
         case bltestSHA512:
             /*params->hash.restart = PR_TRUE;*/
@@ -3292,23 +3254,21 @@ dump_file(bltestCipherMode mode, char *f
     get_file_data(filename, &item, PR_TRUE);
     pqg = pqg_from_filedata(&item);
     dump_pqg(pqg);
 #endif
         DSAPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
         key = dsakey_from_filedata(arena, &keydata.buf);
         dump_dsakey(key);
-#ifndef NSS_DISABLE_ECC
     } else if (mode == bltestECDSA) {
         ECPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
         key = eckey_from_filedata(arena, &keydata.buf);
         dump_eckey(key);
-#endif
     }
     PORT_FreeArena(arena, PR_FALSE);
     return SECFailure;
 }
 
 void
 ThreadExecTest(void *data)
 {
@@ -3585,19 +3545,17 @@ enum {
     opt_SigFile,
     opt_KeySize,
     opt_Hex,
     opt_Input,
     opt_PQGFile,
     opt_Key,
     opt_HexWSpc,
     opt_Mode,
-#ifndef NSS_DISABLE_ECC
     opt_CurveName,
-#endif
     opt_Output,
     opt_Repetitions,
     opt_ZeroBuf,
     opt_Rounds,
     opt_Seed,
     opt_SigSeedFile,
     opt_CXReps,
     opt_IV,
@@ -3639,19 +3597,17 @@ static secuCommandFlag bltest_options[] 
       { /* opt_SigFile */ 'f', PR_TRUE, 0, PR_FALSE },
       { /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE },
       { /* opt_Hex */ 'h', PR_FALSE, 0, PR_FALSE },
       { /* opt_Input */ 'i', PR_TRUE, 0, PR_FALSE },
       { /* opt_PQGFile */ 'j', PR_TRUE, 0, PR_FALSE },
       { /* opt_Key */ 'k', PR_TRUE, 0, PR_FALSE },
       { /* opt_HexWSpc */ 'l', PR_FALSE, 0, PR_FALSE },
       { /* opt_Mode */ 'm', PR_TRUE, 0, PR_FALSE },
-#ifndef NSS_DISABLE_ECC
       { /* opt_CurveName */ 'n', PR_TRUE, 0, PR_FALSE },
-#endif
       { /* opt_Output */ 'o', PR_TRUE, 0, PR_FALSE },
       { /* opt_Repetitions */ 'p', PR_TRUE, 0, PR_FALSE },
       { /* opt_ZeroBuf */ 'q', PR_FALSE, 0, PR_FALSE },
       { /* opt_Rounds */ 'r', PR_TRUE, 0, PR_FALSE },
       { /* opt_Seed */ 's', PR_TRUE, 0, PR_FALSE },
       { /* opt_SigSeedFile */ 't', PR_TRUE, 0, PR_FALSE },
       { /* opt_CXReps */ 'u', PR_TRUE, 0, PR_FALSE },
       { /* opt_IV */ 'v', PR_TRUE, 0, PR_FALSE },
@@ -3674,19 +3630,17 @@ main(int argc, char **argv)
     SECStatus rv = SECFailure;
 
     double totalTime = 0.0;
     PRIntervalTime time1, time2;
     PRFileDesc *outfile = NULL;
     bltestCipherInfo *cipherInfoListHead, *cipherInfo = NULL;
     bltestIOMode ioMode;
     int bufsize, exponent, curThrdNum;
-#ifndef NSS_DISABLE_ECC
     char *curveName = NULL;
-#endif
     int i, commandsEntered;
     int inoff, outoff;
     int threads = 1;
 
     secuCommand bltest;
     bltest.numCommands = sizeof(bltest_commands) / sizeof(secuCommandFlag);
     bltest.numOptions = sizeof(bltest_options) / sizeof(secuCommandFlag);
     bltest.commands = bltest_commands;
@@ -3912,22 +3866,20 @@ main(int argc, char **argv)
                        : (bltest.options[opt_HexWSpc].activated) ? bltestHexSpaceDelim
                                                                  : bltestBinary;
 
     if (bltest.options[opt_Exponent].activated)
         exponent = PORT_Atoi(bltest.options[opt_Exponent].arg);
     else
         exponent = 65537;
 
-#ifndef NSS_DISABLE_ECC
     if (bltest.options[opt_CurveName].activated)
         curveName = PORT_Strdup(bltest.options[opt_CurveName].arg);
     else
         curveName = NULL;
-#endif
 
     if (bltest.commands[cmd_Verify].activated &&
         !bltest.options[opt_SigFile].activated) {
         fprintf(stderr, "%s: You must specify a signature file with -f.\n",
                 progName);
 
     print_usage:
         if (cipherInfo) {
@@ -4003,21 +3955,17 @@ main(int argc, char **argv)
             } else {
                 if (bltest.options[opt_KeySize].activated)
                     keysize = PORT_Atoi(bltest.options[opt_KeySize].arg);
                 else
                     keysize = 64; /* use 512-bit default */
                 file = PR_Open("tmp.key", PR_WRONLY | PR_CREATE_FILE, 00660);
             }
             params->key.mode = bltestBase64Encoded;
-#ifndef NSS_DISABLE_ECC
             pubkeyInitKey(cipherInfo, file, keysize, exponent, curveName);
-#else
-            pubkeyInitKey(cipherInfo, file, keysize, exponent);
-#endif
             PR_Close(file);
         }
 
         /* set up an initialization vector. */
         if (cipher_requires_IV(cipherInfo->mode)) {
             char *ivstr = NULL;
             bltestSymmKeyParams *skp;
             file = NULL;
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -360,17 +360,17 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
 static SECStatus
 ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
                       char *name, char *trusts, void *pwdata)
 {
     SECStatus rv;
     CERTCertificate *cert;
     CERTCertTrust *trust;
 
-    cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
+    cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
     if (!cert) {
         SECU_PrintError(progName, "could not find certificate named \"%s\"",
                         name);
         return SECFailure;
     }
 
     trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
     if (!trust) {
@@ -1043,25 +1043,20 @@ PrintSyntax(char *progName)
     FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
         progName);
     FPS "\t%s -F -n nickname [-d certdir] [-P dbprefix]\n",
         progName);
     FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
         "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
-#ifndef NSS_DISABLE_ECC
     FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
         progName);
-#else
-    FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n",
-        progName);
-#endif /* NSS_DISABLE_ECC */
     FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
     FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
         progName);
     FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
     FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
     FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
     FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
         progName);
@@ -1243,36 +1238,28 @@ luG(enum usage_level ul, const char *com
     int is_my_command = (command && 0 == strcmp(command, "G"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Generate a new key pair\n",
         "-G");
     if (ul == usage_selected && !is_my_command)
         return;
     FPS "%-20s Name of token in which to generate key (default is internal)\n",
         "   -h token-name");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
         "   -k key-type");
     FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
-#else
-    FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
-        "   -k key-type");
-    FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
-        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
-#endif /* NSS_DISABLE_ECC */
     FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
         "   -y exp");
     FPS "%-20s Specify the password file\n",
         "   -f password-file");
     FPS "%-20s Specify the noise file to be used\n",
         "   -z noisefile");
     FPS "%-20s read PQG value from pqgfile (dsa only)\n",
         "   -q pqgfile");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Elliptic curve name (ec only)\n",
         "   -q curve-name");
     FPS "%-20s One of nistp256, nistp384, nistp521, curve25519.\n", "");
     FPS "%-20s If a custom token is present, the following curves are also supported:\n", "");
     FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
     FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
     FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
     FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
@@ -1284,17 +1271,16 @@ luG(enum usage_level ul, const char *com
     FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
     FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
     FPS "%-20s c2tnb191v2, c2tnb191v3,  \n", "");
     FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
     FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
     FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
     FPS "%-20s sect131r1, sect131r2\n", "");
-#endif
     FPS "%-20s Key database directory (default is ~/.netscape)\n",
         "   -d keydir");
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
     FPS "%-20s\n"
         "%-20s PKCS #11 key Attributes.\n",
         "   --keyAttrFlags attrflags", "");
     FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
@@ -1374,19 +1360,17 @@ luK(enum usage_level ul, const char *com
     FPS "%-15s List all private keys\n",
         "-K");
     if (ul == usage_selected && !is_my_command)
         return;
     FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
         "   -h token-name ");
 
     FPS "%-20s Key type (\"all\" (default), \"dsa\","
-#ifndef NSS_DISABLE_ECC
                                                     " \"ec\","
-#endif
                                                     " \"rsa\")\n",
         "   -k key-type");
     FPS "%-20s The nickname of the key or associated certificate\n",
         "   -n name");
     FPS "%-20s Specify the password file\n",
         "   -f password-file");
     FPS "%-20s Key database directory (default is ~/.netscape)\n",
         "   -d keydir");
@@ -1519,36 +1503,30 @@ luR(enum usage_level ul, const char *com
     FPS "%-15s Generate a certificate request (stdout)\n",
         "-R");
     if (ul == usage_selected && !is_my_command)
         return;
     FPS "%-20s Specify the subject name (using RFC1485)\n",
         "   -s subject");
     FPS "%-20s Output the cert request to this file\n",
         "   -o output-req");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
-#else
-    FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
-#endif /* NSS_DISABLE_ECC */
         "   -k key-type-or-id");
     FPS "%-20s or nickname of the cert key to use \n",
         "");
     FPS "%-20s Name of token in which to generate key (default is internal)\n",
         "   -h token-name");
     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
         "   -q pqgfile");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Elliptic curve name (ec only)\n",
         "   -q curve-name");
     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
         "");
-#endif /* NSS_DISABLE_ECC */
     FPS "%-20s Specify the password file\n",
         "   -f pwfile");
     FPS "%-20s Key database directory (default is ~/.netscape)\n",
         "   -d keydir");
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
         "   -p phone");
@@ -1704,34 +1682,28 @@ luS(enum usage_level ul, const char *com
     FPS "%-20s Specify the nickname of the cert\n",
         "   -n key-name");
     FPS "%-20s Specify the subject name (using RFC1485)\n",
         "   -s subject");
     FPS "%-20s The nickname of the issuer cert\n",
         "   -c issuer-name");
     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
         "   -t trustargs");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
-#else
-    FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
-#endif /* NSS_DISABLE_ECC */
         "   -k key-type-or-id");
     FPS "%-20s Name of token in which to generate key (default is internal)\n",
         "   -h token-name");
     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
         "   -q pqgfile");
-#ifndef NSS_DISABLE_ECC
     FPS "%-20s Elliptic curve name (ec only)\n",
         "   -q curve-name");
     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
         "");
-#endif /* NSS_DISABLE_ECC */
     FPS "%-20s Self sign\n",
         "   -x");
     FPS "%-20s Cert serial number\n",
         "   -m serial-number");
     FPS "%-20s Time Warp\n",
         "   -w warp-months");
     FPS "%-20s Months valid (default is 3)\n",
         "   -v months-valid");
@@ -2620,22 +2592,20 @@ certutil_main(int argc, char **argv, PRB
     if (certutil.options[opt_KeySize].activated) {
         keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
         if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
             PR_fprintf(PR_STDERR,
                        "%s -g:  Keysize must be between %d and %d.\n",
                        progName, MIN_KEY_BITS, MAX_KEY_BITS);
             return 255;
         }
-#ifndef NSS_DISABLE_ECC
         if (keytype == ecKey) {
             PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
             return 255;
         }
-#endif /* NSS_DISABLE_ECC */
     }
 
     /*  -h specify token name  */
     if (certutil.options[opt_TokenName].activated) {
         if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
             slotname = NULL;
         else
             slotname = certutil.options[opt_TokenName].arg;
@@ -2654,20 +2624,18 @@ certutil_main(int argc, char **argv, PRB
 
     /*  -k key type  */
     if (certutil.options[opt_KeyType].activated) {
         char *arg = certutil.options[opt_KeyType].arg;
         if (PL_strcmp(arg, "rsa") == 0) {
             keytype = rsaKey;
         } else if (PL_strcmp(arg, "dsa") == 0) {
             keytype = dsaKey;
-#ifndef NSS_DISABLE_ECC
         } else if (PL_strcmp(arg, "ec") == 0) {
             keytype = ecKey;
-#endif /* NSS_DISABLE_ECC */
         } else if (PL_strcmp(arg, "all") == 0) {
             keytype = nullKey;
         } else {
             /* use an existing private/public key pair */
             keysource = arg;
         }
     } else if (certutil.commands[cmd_ListKeys].activated) {
         keytype = nullKey;
@@ -2710,26 +2678,20 @@ certutil_main(int argc, char **argv, PRB
             srcCertPrefix = certutil.options[opt_SourcePrefix].arg;
         } else {
             Usage(progName);
         }
     }
 
     /*  -q PQG file or curve name */
     if (certutil.options[opt_PQGFile].activated) {
-#ifndef NSS_DISABLE_ECC
         if ((keytype != dsaKey) && (keytype != ecKey)) {
             PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys"
                                   " (-k dsa) or a named curve for EC keys (-k ec)\n)",
                        progName);
-#else  /* } */
-        if (keytype != dsaKey) {
-            PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
-                       progName);
-#endif /* NSS_DISABLE_ECC */
             return 255;
         }
     }
 
     /*  -s subject name  */
     if (certutil.options[opt_Subject].activated) {
         subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
         if (!subject) {
--- a/security/nss/cmd/certutil/keystuff.c
+++ b/security/nss/cmd/certutil/keystuff.c
@@ -375,17 +375,16 @@ CERTUTIL_FileForRNG(const char *noise)
             PK11_RandomUpdate(buf, count);
         }
     } while (count > 0);
 
     PR_Close(fd);
     return SECSuccess;
 }
 
-#ifndef NSS_DISABLE_ECC
 typedef struct curveNameTagPairStr {
     char *curveName;
     SECOidTag curveOidTag;
 } CurveNameTagPair;
 
 static CurveNameTagPair nameTagPair[] =
     {
       { "sect163k1", SEC_OID_SECG_EC_SECT163K1 },
@@ -490,28 +489,27 @@ getECParams(const char *curve)
     if ((curveOidTag == SEC_OID_UNKNOWN) ||
         (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
         fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
         return NULL;
     }
 
     ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
 
-    /* 
+    /*
      * ecparams->data needs to contain the ASN encoding of an object ID (OID)
-     * representing the named curve. The actual OID is in 
+     * representing the named curve. The actual OID is in
      * oidData->oid.data so we simply prepend 0x06 and OID length
      */
     ecparams->data[0] = SEC_ASN1_OBJECT_ID;
     ecparams->data[1] = oidData->oid.len;
     memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
 
     return ecparams;
 }
-#endif /* NSS_DISABLE_ECC */
 
 SECKEYPrivateKey *
 CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
                             int publicExponent, const char *noise,
                             SECKEYPublicKey **pubkeyp, const char *pqgFile,
                             PK11AttrFlags attrFlags, CK_FLAGS opFlagsOn,
                             CK_FLAGS opFlagsOff, secuPWData *pwdata)
 {
@@ -559,24 +557,22 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
                 if (dsaparams == NULL)
                     return NULL;
                 params = dsaparams;
             } else {
                 /* cast away const, and don't set dsaparams */
                 params = (void *)&default_pqg_params;
             }
             break;
-#ifndef NSS_DISABLE_ECC
         case ecKey:
             mechanism = CKM_EC_KEY_PAIR_GEN;
             /* For EC keys, PQGFile determines EC parameters */
             if ((params = (void *)getECParams(pqgFile)) == NULL)
                 return NULL;
             break;
-#endif /* NSS_DISABLE_ECC */
         default:
             return NULL;
     }
 
     fprintf(stderr, "\n\n");
     fprintf(stderr, "Generating key.  This may take a few moments...\n\n");
 
     privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism, params, pubkeyp,
@@ -584,18 +580,16 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
                                                                         opFlagsOff,
                                               pwdata /*wincx*/);
     /* free up the params */
     switch (keytype) {
         case dsaKey:
             if (dsaparams)
                 CERTUTIL_DestroyParamsPQG(dsaparams);
             break;
-#ifndef NSS_DISABLE_ECC
         case ecKey:
             SECITEM_FreeItem((SECItem *)params, PR_TRUE);
             break;
-#endif
         default: /* nothing to free */
             break;
     }
     return privKey;
 }
--- a/security/nss/cmd/fipstest/fipstest.c
+++ b/security/nss/cmd/fipstest/fipstest.c
@@ -30,23 +30,21 @@
 #undef CK_NEED_ARG_LIST
 #undef __PASTE
 #define SSL3_RANDOM_LENGTH 32
 
 #if 0
 #include "../../lib/freebl/mpi/mpi.h"
 #endif
 
-#ifndef NSS_DISABLE_ECC
 extern SECStatus
 EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
 extern SECStatus
 EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
               const ECParams *srcParams);
-#endif
 
 #define ENCRYPT 1
 #define DECRYPT 0
 #define BYTE unsigned char
 #define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001
 #define RSA_MAX_TEST_MODULUS_BITS 4096
 #define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS / 8
 #define RSA_MAX_TEST_EXPONENT_BYTES 8
@@ -2089,17 +2087,16 @@ get_next_line(FILE *req, char *key, char
         } else {
             writeto[w++] = c;
         }
     }
     writeto[w] = '\0';
     return (c == EOF) ? -1 : ignore;
 }
 
-#ifndef NSS_DISABLE_ECC
 typedef struct curveNameTagPairStr {
     char *curveName;
     SECOidTag curveOidTag;
 } CurveNameTagPair;
 
 #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1
 /* #define DEFAULT_CURVE_OID_TAG  SEC_OID_SECG_EC_SECP160R1 */
 
@@ -2953,17 +2950,16 @@ ecdsa_sigver_test(char *reqfn)
         }
     }
 loser:
     if (ecpub.ecParams.arena != NULL) {
         PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
     }
     fclose(ecdsareq);
 }
-#endif /* NSS_DISABLE_ECC */
 
 PRBool
 isblankline(char *b)
 {
     while (isspace(*b))
         b++;
     if ((*b == '\n') || (*b == 0)) {
         return PR_TRUE;
@@ -6089,17 +6085,16 @@ main(int argc, char **argv)
             dsa_pqgver_test(argv[3]);
         } else if (strcmp(argv[2], "siggen") == 0) {
             /* Signature Generation Test */
             dsa_siggen_test(argv[3]);
         } else if (strcmp(argv[2], "sigver") == 0) {
             /* Signature Verification Test */
             dsa_sigver_test(argv[3]);
         }
-#ifndef NSS_DISABLE_ECC
         /*************/
         /*   ECDSA   */
         /*************/
     } else if (strcmp(argv[1], "ecdsa") == 0) {
         /* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */
         if (strcmp(argv[2], "keypair") == 0) {
             /* Key Pair Generation Test */
             ecdsa_keypair_test(argv[3]);
@@ -6108,17 +6103,16 @@ main(int argc, char **argv)
             ecdsa_pkv_test(argv[3]);
         } else if (strcmp(argv[2], "siggen") == 0) {
             /* Signature Generation Test */
             ecdsa_siggen_test(argv[3]);
         } else if (strcmp(argv[2], "sigver") == 0) {
             /* Signature Verification Test */
             ecdsa_sigver_test(argv[3]);
         }
-#endif /* NSS_DISABLE_ECC */
         /*************/
         /*   RNG     */
         /*************/
     } else if (strcmp(argv[1], "rng") == 0) {
         /* argv[2]=vst|mct argv[3]=<test name>.req */
         if (strcmp(argv[2], "vst") == 0) {
             /* Variable Seed Test */
             rng_vst(argv[3]);
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -479,58 +479,16 @@ SECU_ConfigDirectory(const char *base)
         if (buf[strlen(buf) - 1] == '/')
             buf[strlen(buf) - 1] = 0;
     }
 
     initted = PR_TRUE;
     return buf;
 }
 
-/*Turn off SSL for now */
-/* This gets called by SSL when server wants our cert & key */
-int
-SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
-                       struct CERTDistNamesStr *caNames,
-                       struct CERTCertificateStr **pRetCert,
-                       struct SECKEYPrivateKeyStr **pRetKey)
-{
-    SECKEYPrivateKey *key;
-    CERTCertificate *cert;
-    int errsave;
-
-    if (arg == NULL) {
-        fprintf(stderr, "no key/cert name specified for client auth\n");
-        return -1;
-    }
-    cert = PK11_FindCertFromNickname(arg, NULL);
-    errsave = PORT_GetError();
-    if (!cert) {
-        if (errsave == SEC_ERROR_BAD_PASSWORD)
-            fprintf(stderr, "Bad password\n");
-        else if (errsave > 0)
-            fprintf(stderr, "Unable to read cert (error %d)\n", errsave);
-        else if (errsave == SEC_ERROR_BAD_DATABASE)
-            fprintf(stderr, "Unable to get cert from database (%d)\n", errsave);
-        else
-            fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave);
-        return -1;
-    }
-
-    key = PK11_FindKeyByAnyCert(arg, NULL);
-    if (!key) {
-        fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError());
-        return -1;
-    }
-
-    *pRetCert = cert;
-    *pRetKey = key;
-
-    return 0;
-}
-
 SECStatus
 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii,
                      PRBool warnOnPrivateKeyInAsciiFile)
 {
     SECStatus rv;
     if (ascii) {
         /* First convert ascii to binary */
         SECItem filedata;
@@ -1404,17 +1362,16 @@ secu_PrintAttribute(FILE *out, SEC_PKCS7
                         SECU_PrintTimeChoice(out, value, om, level + 1);
                         break;
                 }
             }
         }
     }
 }
 
-#ifndef NSS_DISABLE_ECC
 static void
 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
 {
     SECItem curveOID = { siBuffer, NULL, 0 };
 
     SECU_Indent(out, level);
     fprintf(out, "%s:\n", m);
     SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level + 1);
@@ -1423,17 +1380,16 @@ secu_PrintECPublicKey(FILE *out, SECKEYP
      */
     if ((pk->u.ec.DEREncodedParams.len > 2) &&
         (pk->u.ec.DEREncodedParams.data[0] == 0x06)) {
         curveOID.len = pk->u.ec.DEREncodedParams.data[1];
         curveOID.data = pk->u.ec.DEREncodedParams.data + 2;
         SECU_PrintObjectID(out, &curveOID, "Curve", level + 1);
     }
 }
-#endif /* NSS_DISABLE_ECC */
 
 void
 SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
 {
     SECU_Indent(out, level);
     fprintf(out, "%s:\n", m);
     SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level + 1);
     SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level + 1);
@@ -1471,21 +1427,19 @@ secu_PrintSubjectPublicKeyInfo(FILE *out
             case rsaKey:
                 SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level + 1);
                 break;
 
             case dsaKey:
                 SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level + 1);
                 break;
 
-#ifndef NSS_DISABLE_ECC
             case ecKey:
                 secu_PrintECPublicKey(out, pk, "EC Public Key", level + 1);
                 break;
-#endif
 
             case dhKey:
             case fortezzaKey:
             case keaKey:
                 SECU_Indent(out, level);
                 fprintf(out, "unable to format this SPKI algorithm type\n");
                 goto loser;
             default:
@@ -3628,54 +3582,16 @@ SECU_DerSignDataCRL(PLArenaPool *arena, 
         goto loser;
     }
 
 loser:
     PORT_Free(it.data);
     return rv;
 }
 
-#if 0
-
-/* we need access to the private function cert_FindExtension for this code to work */
-
-CERTAuthKeyID *
-SECU_FindCRLAuthKeyIDExten (PLArenaPool *arena, CERTSignedCrl *scrl)
-{
-    SECItem encodedExtenValue;
-    SECStatus rv;
-    CERTAuthKeyID *ret;
-    CERTCrl* crl;
-
-    if (!scrl) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return NULL;
-    }
-
-    crl = &scrl->crl;
-
-    encodedExtenValue.data = NULL;
-    encodedExtenValue.len = 0;
-
-    rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
-                            &encodedExtenValue);
-    if ( rv != SECSuccess ) {
-        return (NULL);
-    }
-
-    ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
-
-    PORT_Free(encodedExtenValue.data);
-    encodedExtenValue.data = NULL;
-
-    return(ret);
-}
-
-#endif
-
 /*
  * Find the issuer of a Crl.  Use the authorityKeyID if it exists.
  */
 CERTCertificate *
 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem *subject,
                    CERTAuthKeyID *authorityKeyID, PRTime validTime)
 {
     CERTCertificate *issuerCert = NULL;
@@ -3739,17 +3655,17 @@ SECU_EncodeAndAddExtensionValue(PLArenaP
 }
 
 CERTCertificate *
 SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle,
                                   char *name, PRBool ascii,
                                   void *pwarg)
 {
     CERTCertificate *the_cert;
-    the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
+    the_cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwarg);
     if (the_cert) {
         return the_cert;
     }
     the_cert = PK11_FindCertFromNickname(name, pwarg);
     if (!the_cert) {
         /* Don't have a cert with name "name" in the DB. Try to
          * open a file with such name and get the cert from there.*/
         SECStatus rv;
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -160,19 +160,17 @@ PrintUsageHeader(const char *progName)
 {
     fprintf(stderr,
             "Usage: %s -n rsa_nickname -p port [-BDENRZbjlmrsuvx] [-w password]\n"
             "         [-t threads] [-i pid_file] [-c ciphers] [-Y] [-d dbdir] [-g numblocks]\n"
             "         [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
             "         [-V [min-version]:[max-version]] [-a sni_name]\n"
             "         [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
             "         [-C SSLCacheEntries] [-S dsa_nickname] -Q [-I groups]"
-#ifndef NSS_DISABLE_ECC
             " [-e ec_nickname]"
-#endif /* NSS_DISABLE_ECC */
             "\n"
             "         -U [0|1] -H [0|1|2] -W [0|1]\n"
             "\n",
             progName);
 }
 
 static void
 PrintParameterUsage()
@@ -2338,25 +2336,23 @@ main(int argc, char **argv)
             case 'c':
                 cipherString = PORT_Strdup(optstate->value);
                 break;
 
             case 'd':
                 dir = optstate->value;
                 break;
 
-#ifndef NSS_DISABLE_ECC
             case 'e':
                 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX) {
                     Usage(progName);
                     break;
                 }
                 certNicknameArray[certNicknameIndex++] = PORT_Strdup(optstate->value);
                 break;
-#endif /* NSS_DISABLE_ECC */
 
             case 'f':
                 pwdata.source = PW_FROMFILE;
                 pwdata.data = pwfile = PORT_Strdup(optstate->value);
                 break;
 
             case 'g':
                 testBulk = PR_TRUE;
@@ -2676,19 +2672,17 @@ main(int argc, char **argv)
             exit(10);
         }
         privKey[i] = PK11_FindKeyByAnyCert(cert[i], &pwdata);
         if (privKey[i] == NULL) {
             fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n",
                     certNicknameArray[i]);
             exit(11);
         }
-#ifdef NSS_DISABLE_ECC
         if (privKey[i]->keyType != ecKey)
-#endif
             setupCertStatus(certStatusArena, ocspStaplingMode, cert[i], i, &pwdata);
     }
 
     if (configureWeakDHE > 0) {
         fprintf(stderr, "selfserv: Creating dynamic weak DH parameters\n");
         rv = SSL_EnableWeakDHEPrimeGroup(NULL, PR_TRUE);
         if (rv != SECSuccess) {
             goto cleanup;
--- a/security/nss/coreconf/config.mk
+++ b/security/nss/coreconf/config.mk
@@ -141,20 +141,16 @@ endif
 #######################################################################
 
 -include $(MKDEPENDENCIES)
 
 #######################################################################
 # [16.0] Global environ ment defines
 #######################################################################
 
-ifdef NSS_DISABLE_ECC
-DEFINES += -DNSS_DISABLE_ECC
-endif
-
 ifdef NSS_ALLOW_UNSUPPORTED_CRITICAL
 DEFINES += -DNSS_ALLOW_UNSUPPORTED_CRITICAL
 endif
 
 ifdef BUILD_LIBPKIX_TESTS
 DEFINES += -DBUILD_LIBPKIX_TESTS
 endif
 
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/fuzz/mpi_expmod_target.cc
+++ b/security/nss/fuzz/mpi_expmod_target.cc
@@ -14,19 +14,22 @@ extern "C" int LLVMFuzzerTestOneInput(co
   if (size < 3) {
     return 0;
   }
   INIT_FOUR_NUMBERS
 
   auto modulus = get_modulus(data, size, ctx);
   // Compare with OpenSSL exp mod
   m1 = &std::get<1>(modulus);
-  print_bn("A", A);
-  print_bn("B", B);
-  print_bn("m", std::get<0>(modulus));
+  // The exponent b (B) can get really big. Make it smaller if necessary.
+  if (MP_USED(&b) > 100) {
+    size_t shift = (MP_USED(&b) - 100) * MP_DIGIT_BIT;
+    mp_div_2d(&b, shift, &b, nullptr);
+    BN_rshift(B, B, shift);
+  }
   check_equal(A, &a, max_size);
   check_equal(B, &b, max_size);
   check_equal(std::get<0>(modulus), m1, 3 * max_size);
   assert(mp_exptmod(&a, &b, m1, &c) == MP_OKAY);
   (void)BN_mod_exp(C, A, B, std::get<0>(modulus), ctx);
   check_equal(C, &c, 2 * max_size);
 
   CLEANUP_AND_RETURN
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/freebl_gtest/blake2b_unittest.cc
@@ -0,0 +1,277 @@
+/*
+ * blake2b_unittest.cc - unittests for blake2b hash function
+ *
+ * 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 "blapi.h"
+#include "nspr.h"
+#include "nss.h"
+#include "secerr.h"
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+#define GTEST_HAS_RTTI 0
+#include "gtest/gtest.h"
+
+#include "kat/blake2b_kat.h"
+
+template <class T>
+struct ScopedDelete {
+  void operator()(T* ptr) {
+    if (ptr) {
+      BLAKE2B_DestroyContext(ptr, PR_TRUE);
+    }
+  }
+};
+
+typedef std::unique_ptr<BLAKE2BContext, ScopedDelete<BLAKE2BContext>>
+    ScopedBLAKE2BContext;
+
+class Blake2BTests : public ::testing::Test {};
+
+class Blake2BKAT
+    : public ::testing::TestWithParam<std::pair<int, std::vector<uint8_t>>> {};
+
+class Blake2BKATUnkeyed : public Blake2BKAT {};
+class Blake2BKATKeyed : public Blake2BKAT {};
+
+TEST_P(Blake2BKATUnkeyed, Unkeyed) {
+  std::vector<uint8_t> values(BLAKE2B512_LENGTH);
+  SECStatus rv =
+      BLAKE2B_HashBuf(values.data(), kat_data.data(), std::get<0>(GetParam()));
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(values, std::get<1>(GetParam()));
+}
+
+TEST_P(Blake2BKATKeyed, Keyed) {
+  std::vector<uint8_t> values(BLAKE2B512_LENGTH);
+  SECStatus rv = BLAKE2B_MAC_HashBuf(values.data(), kat_data.data(),
+                                     std::get<0>(GetParam()), key.data(),
+                                     BLAKE2B_KEY_SIZE);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(values, std::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(UnkeyedKAT, Blake2BKATUnkeyed,
+                        ::testing::ValuesIn(TestcasesUnkeyed));
+INSTANTIATE_TEST_CASE_P(KeyedKAT, Blake2BKATKeyed,
+                        ::testing::ValuesIn(TestcasesKeyed));
+
+TEST_F(Blake2BTests, ContextTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  SECStatus rv = BLAKE2B_Begin(ctx.get());
+  ASSERT_EQ(SECSuccess, rv);
+
+  size_t src_length = 252;
+  const size_t quarter = 63;
+
+  for (int i = 0; i < 4 && src_length > 0; i++) {
+    rv = BLAKE2B_Update(ctx.get(), kat_data.data() + i * quarter,
+                        PR_MIN(quarter, src_length));
+    ASSERT_EQ(SECSuccess, rv);
+
+    size_t len = BLAKE2B_FlattenSize(ctx.get());
+    std::vector<unsigned char> ctxbytes(len);
+    rv = BLAKE2B_Flatten(ctx.get(), ctxbytes.data());
+    ASSERT_EQ(SECSuccess, rv);
+    ScopedBLAKE2BContext ctx_cpy(BLAKE2B_Resurrect(ctxbytes.data(), NULL));
+    ASSERT_TRUE(ctx_cpy) << "BLAKE2B_Resurrect failed!";
+    ASSERT_EQ(SECSuccess, PORT_Memcmp(ctx.get(), ctx_cpy.get(), len));
+    src_length -= quarter;
+  }
+  ASSERT_EQ(0U, src_length);
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  rv = BLAKE2B_End(ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(std::get<1>(TestcasesUnkeyed[252]), digest)
+      << "BLAKE2B_End failed!";
+}
+
+TEST_F(Blake2BTests, ContextTest2) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  SECStatus rv = BLAKE2B_Begin(ctx.get());
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
+  ASSERT_EQ(SECSuccess, rv);
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
+  ASSERT_EQ(SECSuccess, rv);
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  rv = BLAKE2B_End(ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(std::get<1>(TestcasesUnkeyed[255]), digest)
+      << "BLAKE2B_End failed!";
+}
+
+TEST_F(Blake2BTests, CloneTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ScopedBLAKE2BContext cloned_ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+  ASSERT_TRUE(cloned_ctx) << "BLAKE2B_NewContext failed!";
+
+  SECStatus rv = BLAKE2B_Begin(ctx.get());
+  ASSERT_EQ(SECSuccess, rv);
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 255);
+  ASSERT_EQ(SECSuccess, rv);
+  BLAKE2B_Clone(cloned_ctx.get(), ctx.get());
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  rv = BLAKE2B_End(cloned_ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(std::get<1>(TestcasesUnkeyed[255]), digest)
+      << "BLAKE2B_End failed!";
+}
+
+TEST_F(Blake2BTests, NullTest) {
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  SECStatus rv = BLAKE2B_HashBuf(digest.data(), nullptr, 0);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(std::get<1>(TestcasesUnkeyed[0]), digest);
+
+  digest = std::vector<uint8_t>(BLAKE2B512_LENGTH);
+  rv = BLAKE2B_MAC_HashBuf(digest.data(), nullptr, 0, key.data(),
+                           BLAKE2B_KEY_SIZE);
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(std::get<1>(TestcasesKeyed[0]), digest);
+}
+
+TEST_F(Blake2BTests, HashTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  SECStatus rv = BLAKE2B_Hash(digest.data(), "abc");
+  std::vector<uint8_t> expected = {
+      0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d, 0x6a, 0x27, 0x97,
+      0xb6, 0x9f, 0x12, 0xf6, 0xe9, 0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a,
+      0xc4, 0xb7, 0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1, 0x7d,
+      0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d, 0xc2, 0x52, 0xd5, 0xde,
+      0x45, 0x33, 0xcc, 0x95, 0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92,
+      0x5a, 0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23};
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(expected, digest);
+}
+
+TEST_F(Blake2BTests, LongHashTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  SECStatus rv = BLAKE2B_Hash(
+      digest.data(),
+      "qwertzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qw"
+      "ertzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qwer"
+      "tzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qwertz"
+      "uiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789");
+  std::vector<uint8_t> expected = {
+      0x1f, 0x9e, 0xe6, 0x5a, 0xa0, 0x36, 0x05, 0xfc, 0x41, 0x0e, 0x2f,
+      0x55, 0x96, 0xfd, 0xb5, 0x9d, 0x85, 0x95, 0x5e, 0x24, 0x37, 0xe7,
+      0x0d, 0xe4, 0xa0, 0x22, 0x4a, 0xe1, 0x59, 0x1f, 0x97, 0x03, 0x57,
+      0x54, 0xf0, 0xca, 0x92, 0x75, 0x2f, 0x9e, 0x86, 0xeb, 0x82, 0x4f,
+      0x9c, 0xf4, 0x02, 0x17, 0x7f, 0x76, 0x56, 0x26, 0x46, 0xf4, 0x07,
+      0xfd, 0x1f, 0x78, 0xdb, 0x7b, 0x0d, 0x24, 0x43, 0xf0};
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(expected, digest);
+}
+
+TEST_F(Blake2BTests, TruncatedHashTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  SECStatus rv = BLAKE2B_Begin(ctx.get());
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
+  ASSERT_EQ(SECSuccess, rv);
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
+  ASSERT_EQ(SECSuccess, rv);
+
+  size_t max_digest_len = BLAKE2B512_LENGTH - 5;
+  std::vector<uint8_t> digest(max_digest_len);
+  unsigned int digest_len;
+  rv = BLAKE2B_End(ctx.get(), digest.data(), &digest_len, max_digest_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(digest.size(), digest_len);
+  ASSERT_EQ(0, memcmp(std::get<1>(TestcasesUnkeyed[255]).data(), digest.data(),
+                      max_digest_len))
+      << "BLAKE2B_End failed!";
+}
+
+TEST_F(Blake2BTests, TruncatedHashTest2) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  SECStatus rv = BLAKE2B_Begin(ctx.get());
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
+  ASSERT_EQ(SECSuccess, rv);
+  rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
+  ASSERT_EQ(SECSuccess, rv);
+
+  size_t max_digest_len = BLAKE2B512_LENGTH - 60;
+  std::vector<uint8_t> digest(max_digest_len);
+  unsigned int digest_len;
+  rv = BLAKE2B_End(ctx.get(), digest.data(), &digest_len, max_digest_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(digest.size(), digest_len);
+}
+
+TEST_F(Blake2BTests, OverlongKeyTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  std::vector<uint8_t> key = {
+      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31,
+      0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+      0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33,
+      0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+      0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35};
+  std::vector<uint8_t> data = {0x61, 0x62, 0x63};
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  SECStatus rv =
+      BLAKE2B_MAC_HashBuf(digest.data(), data.data(), 3, key.data(), 65);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+}
+
+TEST_F(Blake2BTests, EmptyKeyTest) {
+  ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
+  ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
+
+  uint8_t key[1];  // A vector.data() would give us a nullptr.
+  std::vector<uint8_t> data = {0x61, 0x62, 0x63};
+
+  std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
+  SECStatus rv = BLAKE2B_MAC_HashBuf(digest.data(), data.data(), 3, key, 0);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
+    return 1;
+  }
+
+  int rv = RUN_ALL_TESTS();
+
+  if (NSS_Shutdown() != SECSuccess) {
+    return 1;
+  }
+
+  return rv;
+}
--- a/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
+++ b/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
@@ -3,91 +3,103 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 {
   'includes': [
     '../../coreconf/config.gypi',
     '../common/gtest.gypi',
   ],
   'targets': [
     {
-      'target_name': 'freebl_gtest',
-      'type': 'executable',
-      'sources': [
-        'mpi_unittest.cc',
-        'dh_unittest.cc',
-        'ecl_unittest.cc',
-        'ghash_unittest.cc',
-        '<(DEPTH)/gtests/common/gtests.cc'
-      ],
+      # Dependencies for tests.
+      'target_name': 'freebl_gtest_deps',
+      'type': 'none',
       'dependencies': [
-        '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
         '<(DEPTH)/lib/nss/nss.gyp:nss_static',
         '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
         '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
         '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
         '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
         '<(DEPTH)/lib/base/base.gyp:nssb',
         '<(DEPTH)/lib/dev/dev.gyp:nssdev',
         '<(DEPTH)/lib/pki/pki.gyp:nsspki',
         '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
       ],
     },
     {
+      'target_name': 'freebl_gtest',
+      'type': 'executable',
+      'sources': [
+        'mpi_unittest.cc',
+        'dh_unittest.cc',
+        'ecl_unittest.cc',
+        'ghash_unittest.cc',
+        '<(DEPTH)/gtests/common/gtests.cc'
+      ],
+      'dependencies': [
+        'freebl_gtest_deps',
+        '<(DEPTH)/exports.gyp:nss_exports',
+      ],
+    },
+    {
       'target_name': 'prng_gtest',
       'type': 'executable',
       'sources': [
         'prng_kat_unittest.cc',
       ],
       'dependencies': [
+        'freebl_gtest_deps',
         '<(DEPTH)/exports.gyp:nss_exports',
-        '<(DEPTH)/lib/util/util.gyp:nssutil3',
-        '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
-        '<(DEPTH)/lib/nss/nss.gyp:nss_static',
-        '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
-        '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
-        '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
-        '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
-        '<(DEPTH)/lib/base/base.gyp:nssb',
-        '<(DEPTH)/lib/dev/dev.gyp:nssdev',
-        '<(DEPTH)/lib/pki/pki.gyp:nsspki',
-        '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
-        '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
       ],
-      'conditions': [
-        [ 'OS=="win"', {
-          'libraries': [
-            'advapi32.lib',
-          ],
-        }],
+    },
+    {
+      'target_name': 'blake2b_gtest',
+      'type': 'executable',
+      'sources': [
+        'blake2b_unittest.cc',
       ],
-      'defines': [
-        'NSS_USE_STATIC_LIBS'
+      'dependencies': [
+        'freebl_gtest_deps',
+        '<(DEPTH)/exports.gyp:nss_exports',
       ],
     },
   ],
   'target_defaults': {
     'include_dirs': [
+      '<(DEPTH)/lib/freebl/ecl',
       '<(DEPTH)/lib/freebl/mpi',
       '<(DEPTH)/lib/freebl/',
+      '<(DEPTH)/lib/ssl/',
+      '<(DEPTH)/lib/util/',
+      '<(DEPTH)/lib/certdb/',
+      '<(DEPTH)/lib/cryptohi/',
+      '<(DEPTH)/lib/pk11wrap/',
+    ],
+    'defines': [
+      'NSS_USE_STATIC_LIBS',
     ],
     # For test builds we have to set MPI defines.
     'conditions': [
       [ 'ct_verif==1', {
         'defines': [
           'CT_VERIF',
         ],
       }],
       [ 'target_arch=="ia32"', {
         'defines': [
           'MP_USE_UINT_DIGIT',
           'MP_ASSEMBLY_MULTIPLY',
           'MP_ASSEMBLY_SQUARE',
           'MP_ASSEMBLY_DIV_2DX1D',
         ],
       }],
+      [ 'OS=="win"', {
+        'libraries': [
+          'advapi32.lib',
+        ],
+      }],
     ],
   },
   'variables': {
     'module': 'nss'
   }
 }
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/freebl_gtest/kat/blake2b_kat.h
@@ -0,0 +1,4646 @@
+/* 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/. */
+
+/* https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2b-kat.txt */
+
+#include <vector>
+#include <stdint.h>
+
+const std::vector<uint8_t> key = {
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
+
+const std::vector<uint8_t> kat_data = {
+    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,
+    15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+    30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
+    45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
+    60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,
+    75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+    90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104,
+    105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+    135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+    150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+    165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+    195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+    210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+    225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+    255};
+
+std::vector<std::pair<int, std::vector<uint8_t>>> TestcasesUnkeyed = {
+    std::make_pair(
+        0,
+        std::vector<uint8_t>(
+            {0x78, 0x6a, 0x02, 0xf7, 0x42, 0x01, 0x59, 0x03, 0xc6, 0xc6, 0xfd,
+             0x85, 0x25, 0x52, 0xd2, 0x72, 0x91, 0x2f, 0x47, 0x40, 0xe1, 0x58,
+             0x47, 0x61, 0x8a, 0x86, 0xe2, 0x17, 0xf7, 0x1f, 0x54, 0x19, 0xd2,
+             0x5e, 0x10, 0x31, 0xaf, 0xee, 0x58, 0x53, 0x13, 0x89, 0x64, 0x44,
+             0x93, 0x4e, 0xb0, 0x4b, 0x90, 0x3a, 0x68, 0x5b, 0x14, 0x48, 0xb7,
+             0x55, 0xd5, 0x6f, 0x70, 0x1a, 0xfe, 0x9b, 0xe2, 0xce})),
+    std::make_pair(
+        1,
+        std::vector<uint8_t>(
+            {0x2f, 0xa3, 0xf6, 0x86, 0xdf, 0x87, 0x69, 0x95, 0x16, 0x7e, 0x7c,
+             0x2e, 0x5d, 0x74, 0xc4, 0xc7, 0xb6, 0xe4, 0x8f, 0x80, 0x68, 0xfe,
+             0x0e, 0x44, 0x20, 0x83, 0x44, 0xd4, 0x80, 0xf7, 0x90, 0x4c, 0x36,
+             0x96, 0x3e, 0x44, 0x11, 0x5f, 0xe3, 0xeb, 0x2a, 0x3a, 0xc8, 0x69,
+             0x4c, 0x28, 0xbc, 0xb4, 0xf5, 0xa0, 0xf3, 0x27, 0x6f, 0x2e, 0x79,
+             0x48, 0x7d, 0x82, 0x19, 0x05, 0x7a, 0x50, 0x6e, 0x4b})),
+    std::make_pair(
+        2,
+        std::vector<uint8_t>(
+            {0x1c, 0x08, 0x79, 0x8d, 0xc6, 0x41, 0xab, 0xa9, 0xde, 0xe4, 0x35,
+             0xe2, 0x25, 0x19, 0xa4, 0x72, 0x9a, 0x09, 0xb2, 0xbf, 0xe0, 0xff,
+             0x00, 0xef, 0x2d, 0xcd, 0x8e, 0xd6, 0xf8, 0xa0, 0x7d, 0x15, 0xea,
+             0xf4, 0xae, 0xe5, 0x2b, 0xbf, 0x18, 0xab, 0x56, 0x08, 0xa6, 0x19,
+             0x0f, 0x70, 0xb9, 0x04, 0x86, 0xc8, 0xa7, 0xd4, 0x87, 0x37, 0x10,
+             0xb1, 0x11, 0x5d, 0x3d, 0xeb, 0xbb, 0x43, 0x27, 0xb5})),
+    std::make_pair(
+        3,
+        std::vector<uint8_t>(
+            {0x40, 0xa3, 0x74, 0x72, 0x73, 0x02, 0xd9, 0xa4, 0x76, 0x9c, 0x17,
+             0xb5, 0xf4, 0x09, 0xff, 0x32, 0xf5, 0x8a, 0xa2, 0x4f, 0xf1, 0x22,
+             0xd7, 0x60, 0x3e, 0x4f, 0xda, 0x15, 0x09, 0xe9, 0x19, 0xd4, 0x10,
+             0x7a, 0x52, 0xc5, 0x75, 0x70, 0xa6, 0xd9, 0x4e, 0x50, 0x96, 0x7a,
+             0xea, 0x57, 0x3b, 0x11, 0xf8, 0x6f, 0x47, 0x3f, 0x53, 0x75, 0x65,
+             0xc6, 0x6f, 0x70, 0x39, 0x83, 0x0a, 0x85, 0xd1, 0x86})),
+    std::make_pair(
+        4,
+        std::vector<uint8_t>(
+            {0x77, 0xdd, 0xf4, 0xb1, 0x44, 0x25, 0xeb, 0x3d, 0x05, 0x3c, 0x1e,
+             0x84, 0xe3, 0x46, 0x9d, 0x92, 0xc4, 0xcd, 0x91, 0x0e, 0xd2, 0x0f,
+             0x92, 0x03, 0x5e, 0x0c, 0x99, 0xd8, 0xa7, 0xa8, 0x6c, 0xec, 0xaf,
+             0x69, 0xf9, 0x66, 0x3c, 0x20, 0xa7, 0xaa, 0x23, 0x0b, 0xc8, 0x2f,
+             0x60, 0xd2, 0x2f, 0xb4, 0xa0, 0x0b, 0x09, 0xd3, 0xeb, 0x8f, 0xc6,
+             0x5e, 0xf5, 0x47, 0xfe, 0x63, 0xc8, 0xd3, 0xdd, 0xce})),
+    std::make_pair(
+        5,
+        std::vector<uint8_t>(
+            {0xcb, 0xaa, 0x0b, 0xa7, 0xd4, 0x82, 0xb1, 0xf3, 0x01, 0x10, 0x9a,
+             0xe4, 0x10, 0x51, 0x99, 0x1a, 0x32, 0x89, 0xbc, 0x11, 0x98, 0x00,
+             0x5a, 0xf2, 0x26, 0xc5, 0xe4, 0xf1, 0x03, 0xb6, 0x65, 0x79, 0xf4,
+             0x61, 0x36, 0x10, 0x44, 0xc8, 0xba, 0x34, 0x39, 0xff, 0x12, 0xc5,
+             0x15, 0xfb, 0x29, 0xc5, 0x21, 0x61, 0xb7, 0xeb, 0x9c, 0x28, 0x37,
+             0xb7, 0x6a, 0x5d, 0xc3, 0x3f, 0x7c, 0xb2, 0xe2, 0xe8})),
+    std::make_pair(
+        6,
+        std::vector<uint8_t>(
+            {0xf9, 0x5d, 0x45, 0xcf, 0x69, 0xaf, 0x5c, 0x20, 0x23, 0xbd, 0xb5,
+             0x05, 0x82, 0x1e, 0x62, 0xe8, 0x5d, 0x7c, 0xae, 0xdf, 0x7b, 0xed,
+             0xa1, 0x2c, 0x02, 0x48, 0x77, 0x5b, 0x0c, 0x88, 0x20, 0x5e, 0xeb,
+             0x35, 0xaf, 0x3a, 0x90, 0x81, 0x6f, 0x66, 0x08, 0xce, 0x7d, 0xd4,
+             0x4e, 0xc2, 0x8d, 0xb1, 0x14, 0x06, 0x14, 0xe1, 0xdd, 0xeb, 0xf3,
+             0xaa, 0x9c, 0xd1, 0x84, 0x3e, 0x0f, 0xad, 0x2c, 0x36})),
+    std::make_pair(
+        7,
+        std::vector<uint8_t>(
+            {0x8f, 0x94, 0x5b, 0xa7, 0x00, 0xf2, 0x53, 0x0e, 0x5c, 0x2a, 0x7d,
+             0xf7, 0xd5, 0xdc, 0xe0, 0xf8, 0x3f, 0x9e, 0xfc, 0x78, 0xc0, 0x73,
+             0xfe, 0x71, 0xae, 0x1f, 0x88, 0x20, 0x4a, 0x4f, 0xd1, 0xcf, 0x70,
+             0xa0, 0x73, 0xf5, 0xd1, 0xf9, 0x42, 0xed, 0x62, 0x3a, 0xa1, 0x6e,
+             0x90, 0xa8, 0x71, 0x24, 0x6c, 0x90, 0xc4, 0x5b, 0x62, 0x1b, 0x34,
+             0x01, 0xa5, 0xdd, 0xbd, 0x9d, 0xf6, 0x26, 0x41, 0x65})),
+    std::make_pair(
+        8,
+        std::vector<uint8_t>(
+            {0xe9, 0x98, 0xe0, 0xdc, 0x03, 0xec, 0x30, 0xeb, 0x99, 0xbb, 0x6b,
+             0xfa, 0xaf, 0x66, 0x18, 0xac, 0xc6, 0x20, 0x32, 0x0d, 0x72, 0x20,
+             0xb3, 0xaf, 0x2b, 0x23, 0xd1, 0x12, 0xd8, 0xe9, 0xcb, 0x12, 0x62,
+             0xf3, 0xc0, 0xd6, 0x0d, 0x18, 0x3b, 0x1e, 0xe7, 0xf0, 0x96, 0xd1,
+             0x2d, 0xae, 0x42, 0xc9, 0x58, 0x41, 0x86, 0x00, 0x21, 0x4d, 0x04,
+             0xf5, 0xed, 0x6f, 0x5e, 0x71, 0x8b, 0xe3, 0x55, 0x66})),
+    std::make_pair(
+        9,
+        std::vector<uint8_t>(
+            {0x6a, 0x9a, 0x09, 0x0c, 0x61, 0xb3, 0x41, 0x0a, 0xed, 0xe7, 0xec,
+             0x91, 0x38, 0x14, 0x6c, 0xeb, 0x2c, 0x69, 0x66, 0x2f, 0x46, 0x0c,
+             0x3d, 0xa5, 0x3c, 0x65, 0x15, 0xc1, 0xeb, 0x31, 0xf4, 0x1c, 0xa3,
+             0xd2, 0x80, 0xe5, 0x67, 0x88, 0x2f, 0x95, 0xcf, 0x66, 0x4a, 0x94,
+             0x14, 0x7d, 0x78, 0xf4, 0x2c, 0xfc, 0x71, 0x4a, 0x40, 0xd2, 0x2e,
+             0xf1, 0x94, 0x70, 0xe0, 0x53, 0x49, 0x35, 0x08, 0xa2})),
+    std::make_pair(
+        10,
+        std::vector<uint8_t>(
+            {0x29, 0x10, 0x25, 0x11, 0xd7, 0x49, 0xdb, 0x3c, 0xc9, 0xb4, 0xe3,
+             0x35, 0xfa, 0x1f, 0x5e, 0x8f, 0xac, 0xa8, 0x42, 0x1d, 0x55, 0x8f,
+             0x6a, 0x3f, 0x33, 0x21, 0xd5, 0x0d, 0x04, 0x4a, 0x24, 0x8b, 0xa5,
+             0x95, 0xcf, 0xc3, 0xef, 0xd3, 0xd2, 0xad, 0xc9, 0x73, 0x34, 0xda,
+             0x73, 0x24, 0x13, 0xf5, 0xcb, 0xf4, 0x75, 0x1c, 0x36, 0x2b, 0xa1,
+             0xd5, 0x38, 0x62, 0xac, 0x1e, 0x8d, 0xab, 0xee, 0xe8})),
+    std::make_pair(
+        11,
+        std::vector<uint8_t>(
+            {0xc9, 0x7a, 0x47, 0x79, 0xd4, 0x7e, 0x6f, 0x77, 0x72, 0x9b, 0x59,
+             0x17, 0xd0, 0x13, 0x8a, 0xbb, 0x35, 0x98, 0x0a, 0xb6, 0x41, 0xbd,
+             0x73, 0xa8, 0x85, 0x9e, 0xb1, 0xac, 0x98, 0xc0, 0x53, 0x62, 0xed,
+             0x7d, 0x60, 0x8f, 0x2e, 0x95, 0x87, 0xd6, 0xba, 0x9e, 0x27, 0x1d,
+             0x34, 0x31, 0x25, 0xd4, 0x0d, 0x93, 0x3a, 0x8e, 0xd0, 0x4e, 0xc1,
+             0xfe, 0x75, 0xec, 0x40, 0x7c, 0x7a, 0x53, 0xc3, 0x4e})),
+    std::make_pair(
+        12,
+        std::vector<uint8_t>(
+            {0x10, 0xf0, 0xdc, 0x91, 0xb9, 0xf8, 0x45, 0xfb, 0x95, 0xfa, 0xd6,
+             0x86, 0x0e, 0x6c, 0xe1, 0xad, 0xfa, 0x00, 0x2c, 0x7f, 0xc3, 0x27,
+             0x11, 0x6d, 0x44, 0xd0, 0x47, 0xcd, 0x7d, 0x58, 0x70, 0xd7, 0x72,
+             0xbb, 0x12, 0xb5, 0xfa, 0xc0, 0x0e, 0x02, 0xb0, 0x8a, 0xc2, 0xa0,
+             0x17, 0x4d, 0x04, 0x46, 0xc3, 0x6a, 0xb3, 0x5f, 0x14, 0xca, 0x31,
+             0x89, 0x4c, 0xd6, 0x1c, 0x78, 0xc8, 0x49, 0xb4, 0x8a})),
+    std::make_pair(
+        13,
+        std::vector<uint8_t>(
+            {0xde, 0xa9, 0x10, 0x1c, 0xac, 0x62, 0xb8, 0xf6, 0xa3, 0xc6, 0x50,
+             0xf9, 0x0e, 0xea, 0x5b, 0xfa, 0xe2, 0x65, 0x3a, 0x4e, 0xaf, 0xd6,
+             0x3a, 0x6d, 0x1f, 0x0f, 0x13, 0x2d, 0xb9, 0xe4, 0xf2, 0xb1, 0xb6,
+             0x62, 0x43, 0x2e, 0xc8, 0x5b, 0x17, 0xbc, 0xac, 0x41, 0xe7, 0x75,
+             0x63, 0x78, 0x81, 0xf6, 0xaa, 0xb3, 0x8d, 0xd6, 0x6d, 0xcb, 0xd0,
+             0x80, 0xf0, 0x99, 0x0a, 0x7a, 0x6e, 0x98, 0x54, 0xfe})),
+    std::make_pair(
+        14,
+        std::vector<uint8_t>(
+            {0x44, 0x1f, 0xfa, 0xa0, 0x8c, 0xd7, 0x9d, 0xff, 0x4a, 0xfc, 0x9b,
+             0x9e, 0x5b, 0x56, 0x20, 0xee, 0xc0, 0x86, 0x73, 0x0c, 0x25, 0xf6,
+             0x61, 0xb1, 0xd6, 0xfb, 0xfb, 0xd1, 0xce, 0xc3, 0x14, 0x8d, 0xd7,
+             0x22, 0x58, 0xc6, 0x56, 0x41, 0xf2, 0xfc, 0xa5, 0xeb, 0x15, 0x5f,
+             0xad, 0xbc, 0xab, 0xb1, 0x3c, 0x6e, 0x21, 0xdc, 0x11, 0xfa, 0xf7,
+             0x2c, 0x2a, 0x28, 0x1b, 0x7d, 0x56, 0x14, 0x5f, 0x19})),
+    std::make_pair(
+        15,
+        std::vector<uint8_t>(
+            {0x44, 0x4b, 0x24, 0x0f, 0xe3, 0xed, 0x86, 0xd0, 0xe2, 0xef, 0x4c,
+             0xe7, 0xd8, 0x51, 0xed, 0xde, 0x22, 0x15, 0x55, 0x82, 0xaa, 0x09,
+             0x14, 0x79, 0x7b, 0x72, 0x6c, 0xd0, 0x58, 0xb6, 0xf4, 0x59, 0x32,
+             0xe0, 0xe1, 0x29, 0x51, 0x68, 0x76, 0x52, 0x7b, 0x1d, 0xd8, 0x8f,
+             0xc6, 0x6d, 0x71, 0x19, 0xf4, 0xab, 0x3b, 0xed, 0x93, 0xa6, 0x1a,
+             0x0e, 0x2d, 0x2d, 0x2a, 0xea, 0xc3, 0x36, 0xd9, 0x58})),
+    std::make_pair(
+        16,
+        std::vector<uint8_t>(
+            {0xbf, 0xba, 0xbb, 0xef, 0x45, 0x55, 0x4c, 0xcf, 0xa0, 0xdc, 0x83,
+             0x75, 0x2a, 0x19, 0xcc, 0x35, 0xd5, 0x92, 0x09, 0x56, 0xb3, 0x01,
+             0xd5, 0x58, 0xd7, 0x72, 0x28, 0x2b, 0xc8, 0x67, 0x00, 0x91, 0x68,
+             0xe9, 0xe9, 0x86, 0x06, 0xbb, 0x5b, 0xa7, 0x3a, 0x38, 0x5d, 0xe5,
+             0x74, 0x92, 0x28, 0xc9, 0x25, 0xa8, 0x50, 0x19, 0xb7, 0x1f, 0x72,
+             0xfe, 0x29, 0xb3, 0xcd, 0x37, 0xca, 0x52, 0xef, 0xe6})),
+    std::make_pair(
+        17,
+        std::vector<uint8_t>(
+            {0x9c, 0x4d, 0x0c, 0x3e, 0x1c, 0xdb, 0xbf, 0x48, 0x5b, 0xec, 0x86,
+             0xf4, 0x1c, 0xec, 0x7c, 0x98, 0x37, 0x3f, 0x0e, 0x09, 0xf3, 0x92,
+             0x84, 0x9a, 0xaa, 0x22, 0x9e, 0xbf, 0xbf, 0x39, 0x7b, 0x22, 0x08,
+             0x55, 0x29, 0xcb, 0x7e, 0xf3, 0x9f, 0x9c, 0x7c, 0x22, 0x22, 0xa5,
+             0x14, 0x18, 0x2b, 0x1e, 0xff, 0xaa, 0x17, 0x8c, 0xc3, 0x68, 0x7b,
+             0x1b, 0x2b, 0x6c, 0xbc, 0xb6, 0xfd, 0xeb, 0x96, 0xf8})),
+    std::make_pair(
+        18,
+        std::vector<uint8_t>(
+            {0x47, 0x71, 0x76, 0xb3, 0xbf, 0xcb, 0xad, 0xd7, 0x65, 0x7c, 0x23,
+             0xc2, 0x46, 0x25, 0xe4, 0xd0, 0xd6, 0x74, 0xd1, 0x86, 0x8f, 0x00,
+             0x60, 0x06, 0x39, 0x8a, 0xf9, 0x7a, 0xa4, 0x18, 0x77, 0xc8, 0xe7,
+             0x0d, 0x3d, 0x14, 0xc3, 0xbb, 0xc9, 0xbb, 0xcd, 0xce, 0xa8, 0x01,
+             0xbd, 0x0e, 0x15, 0x99, 0xaf, 0x1f, 0x3e, 0xec, 0x67, 0x40, 0x51,
+             0x70, 0xf4, 0xe2, 0x6c, 0x96, 0x4a, 0x57, 0xa8, 0xb7})),
+    std::make_pair(
+        19,
+        std::vector<uint8_t>(
+            {0xa7, 0x8c, 0x49, 0x0e, 0xda, 0x31, 0x73, 0xbb, 0x3f, 0x10, 0xde,
+             0xe5, 0x2f, 0x11, 0x0f, 0xb1, 0xc0, 0x8e, 0x03, 0x02, 0x23, 0x0b,
+             0x85, 0xdd, 0xd7, 0xc1, 0x12, 0x57, 0xd9, 0x2d, 0xe1, 0x48, 0x78,
+             0x5e, 0xf0, 0x0c, 0x03, 0x9c, 0x0b, 0xb8, 0xeb, 0x98, 0x08, 0xa3,
+             0x5b, 0x2d, 0x8c, 0x08, 0x0f, 0x57, 0x28, 0x59, 0x71, 0x4c, 0x9d,
+             0x40, 0x69, 0xc5, 0xbc, 0xaf, 0x09, 0x0e, 0x89, 0x8e})),
+    std::make_pair(
+        20,
+        std::vector<uint8_t>(
+            {0x58, 0xd0, 0x23, 0x39, 0x7b, 0xeb, 0x5b, 0x41, 0x45, 0xcb, 0x22,
+             0x55, 0xb0, 0x7d, 0x74, 0x29, 0x0b, 0x36, 0xd9, 0xfd, 0x1e, 0x59,
+             0x4a, 0xfb, 0xd8, 0xee, 0xa4, 0x7c, 0x20, 0x5b, 0x2e, 0xfb, 0xfe,
+             0x6f, 0x46, 0x19, 0x0f, 0xaf, 0x95, 0xaf, 0x50, 0x4a, 0xb0, 0x72,
+             0xe3, 0x6f, 0x6c, 0x85, 0xd7, 0x67, 0xa3, 0x21, 0xbf, 0xd7, 0xf2,
+             0x26, 0x87, 0xa4, 0xab, 0xbf, 0x49, 0x4a, 0x68, 0x9c})),
+    std::make_pair(
+        21,
+        std::vector<uint8_t>(
+            {0x40, 0x01, 0xec, 0x74, 0xd5, 0xa4, 0x6f, 0xd2, 0x9c, 0x2c, 0x3c,
+             0xdb, 0xe5, 0xd1, 0xb9, 0xf2, 0x0e, 0x51, 0xa9, 0x41, 0xbe, 0x98,
+             0xd2, 0xa4, 0xe1, 0xe2, 0xfb, 0xf8, 0x66, 0xa6, 0x72, 0x12, 0x1d,
+             0xb6, 0xf8, 0x1a, 0x51, 0x4c, 0xfd, 0x10, 0xe7, 0x35, 0x8d, 0x57,
+             0x1b, 0xdb, 0xa4, 0x8e, 0x4c, 0xe7, 0x08, 0xb9, 0xd1, 0x24, 0x89,
+             0x4b, 0xc0, 0xb5, 0xed, 0x55, 0x49, 0x35, 0xf7, 0x3a})),
+    std::make_pair(
+        22,
+        std::vector<uint8_t>(
+            {0xcc, 0xd1, 0xb2, 0x2d, 0xab, 0x65, 0x11, 0x22, 0x5d, 0x24, 0x01,
+             0xea, 0x2d, 0x86, 0x25, 0xd2, 0x06, 0xa1, 0x24, 0x73, 0xcc, 0x73,
+             0x2b, 0x61, 0x5e, 0x56, 0x40, 0xce, 0xff, 0xf0, 0xa4, 0xad, 0xf9,
+             0x71, 0xb0, 0xe8, 0x27, 0xa6, 0x19, 0xe0, 0xa8, 0x0f, 0x5d, 0xb9,
+             0xcc, 0xd0, 0x96, 0x23, 0x29, 0x01, 0x0d, 0x07, 0xe3, 0x4a, 0x20,
+             0x64, 0xe7, 0x31, 0xc5, 0x20, 0x81, 0x7b, 0x21, 0x83})),
+    std::make_pair(
+        23,
+        std::vector<uint8_t>(
+            {0xb4, 0xa0, 0xa9, 0xe3, 0x57, 0x4e, 0xdb, 0x9e, 0x1e, 0x72, 0xaa,
+             0x31, 0xe3, 0x9c, 0xc5, 0xf3, 0x0d, 0xbf, 0x94, 0x3f, 0x8c, 0xab,
+             0xc4, 0x08, 0x44, 0x96, 0x54, 0xa3, 0x91, 0x31, 0xe6, 0x6d, 0x71,
+             0x8a, 0x18, 0x81, 0x91, 0x43, 0xe3, 0xea, 0x96, 0xb4, 0xa1, 0x89,
+             0x59, 0x88, 0xa1, 0xc0, 0x05, 0x6c, 0xf2, 0xb6, 0xe0, 0x4f, 0x9a,
+             0xc1, 0x9d, 0x65, 0x73, 0x83, 0xc2, 0x91, 0x0c, 0x44})),
+    std::make_pair(
+        24,
+        std::vector<uint8_t>(
+            {0x44, 0x7b, 0xec, 0xab, 0x16, 0x63, 0x06, 0x08, 0xd3, 0x9f, 0x4f,
+             0x05, 0x8b, 0x16, 0xf7, 0xaf, 0x95, 0xb8, 0x5a, 0x76, 0xaa, 0x0f,
+             0xa7, 0xce, 0xa2, 0xb8, 0x07, 0x55, 0xfb, 0x76, 0xe9, 0xc8, 0x04,
+             0xf2, 0xca, 0x78, 0xf0, 0x26, 0x43, 0xc9, 0x15, 0xfb, 0xf2, 0xfc,
+             0xe5, 0xe1, 0x9d, 0xe8, 0x60, 0x00, 0xde, 0x03, 0xb1, 0x88, 0x61,
+             0x81, 0x5a, 0x83, 0x12, 0x60, 0x71, 0xf8, 0xa3, 0x7b})),
+    std::make_pair(
+        25,
+        std::vector<uint8_t>(
+            {0x54, 0xe6, 0xda, 0xb9, 0x97, 0x73, 0x80, 0xa5, 0x66, 0x58, 0x22,
+             0xdb, 0x93, 0x37, 0x4e, 0xda, 0x52, 0x8d, 0x9b, 0xeb, 0x62, 0x6f,
+             0x9b, 0x94, 0x02, 0x70, 0x71, 0xcb, 0x26, 0x67, 0x5e, 0x11, 0x2b,
+             0x4a, 0x7f, 0xec, 0x94, 0x1e, 0xe6, 0x0a, 0x81, 0xe4, 0xd2, 0xea,
+             0x3f, 0xf7, 0xbc, 0x52, 0xcf, 0xc4, 0x5d, 0xfb, 0xfe, 0x73, 0x5a,
+             0x1c, 0x64, 0x6b, 0x2c, 0xf6, 0xd6, 0xa4, 0x9b, 0x62})),
+    std::make_pair(
+        26,
+        std::vector<uint8_t>(
+            {0x3e, 0xa6, 0x26, 0x25, 0x94, 0x9e, 0x36, 0x46, 0x70, 0x4d, 0x7e,
+             0x3c, 0x90, 0x6f, 0x82, 0xf6, 0xc0, 0x28, 0xf5, 0x40, 0xf5, 0xf7,
+             0x2a, 0x79, 0x4b, 0x0c, 0x57, 0xbf, 0x97, 0xb7, 0x64, 0x9b, 0xfe,
+             0xb9, 0x0b, 0x01, 0xd3, 0xca, 0x3e, 0x82, 0x9d, 0xe2, 0x1b, 0x38,
+             0x26, 0xe6, 0xf8, 0x70, 0x14, 0xd3, 0xc7, 0x73, 0x50, 0xcb, 0x5a,
+             0x15, 0xff, 0x5d, 0x46, 0x8a, 0x81, 0xbe, 0xc1, 0x60})),
+    std::make_pair(
+        27,
+        std::vector<uint8_t>(
+            {0x21, 0x3c, 0xfe, 0x14, 0x5c, 0x54, 0xa3, 0x36, 0x91, 0x56, 0x99,
+             0x80, 0xe5, 0x93, 0x8c, 0x88, 0x83, 0xa4, 0x6d, 0x84, 0xd1, 0x49,
+             0xc8, 0xff, 0x1a, 0x67, 0xcd, 0x28, 0x7b, 0x4d, 0x49, 0xc6, 0xda,
+             0x69, 0xd3, 0xa0, 0x35, 0x44, 0x3d, 0xb0, 0x85, 0x98, 0x3d, 0x0e,
+             0xfe, 0x63, 0x70, 0x6b, 0xd5, 0xb6, 0xf1, 0x5a, 0x7d, 0xa4, 0x59,
+             0xe8, 0xd5, 0x0a, 0x19, 0x09, 0x3d, 0xb5, 0x5e, 0x80})),
+    std::make_pair(
+        28,
+        std::vector<uint8_t>(
+            {0x57, 0x16, 0xc4, 0xa3, 0x8f, 0x38, 0xdb, 0x10, 0x4e, 0x49, 0x4a,
+             0x0a, 0x27, 0xcb, 0xe8, 0x9a, 0x26, 0xa6, 0xbb, 0x6f, 0x49, 0x9e,
+             0xc0, 0x1c, 0x8c, 0x01, 0xaa, 0x7c, 0xb8, 0x84, 0x97, 0xe7, 0x51,
+             0x48, 0xcd, 0x6e, 0xee, 0x12, 0xa7, 0x16, 0x8b, 0x6f, 0x78, 0xab,
+             0x74, 0xe4, 0xbe, 0x74, 0x92, 0x51, 0xa1, 0xa7, 0x4c, 0x38, 0xc8,
+             0x6d, 0x61, 0x29, 0x17, 0x7e, 0x28, 0x89, 0xe0, 0xb6})),
+    std::make_pair(
+        29,
+        std::vector<uint8_t>(
+            {0x03, 0x04, 0x60, 0xa9, 0x8b, 0xdf, 0x9f, 0xf1, 0x7c, 0xd9, 0x64,
+             0x04, 0xf2, 0x8f, 0xc3, 0x04, 0xf2, 0xb7, 0xc0, 0x4e, 0xaa, 0xde,
+             0x53, 0x67, 0x7f, 0xd2, 0x8f, 0x78, 0x8c, 0xa2, 0x21, 0x86, 0xb8,
+             0xbc, 0x80, 0xdd, 0x21, 0xd1, 0x7f, 0x85, 0x49, 0xc7, 0x11, 0xaf,
+             0xf0, 0xe5, 0x14, 0xe1, 0x9d, 0x4e, 0x15, 0xf5, 0x99, 0x02, 0x52,
+             0xa0, 0x3e, 0x08, 0x2f, 0x28, 0xdc, 0x20, 0x52, 0xf6})),
+    std::make_pair(
+        30,
+        std::vector<uint8_t>(
+            {0x19, 0xe7, 0xf1, 0xcc, 0xee, 0x88, 0xa1, 0x06, 0x72, 0x33, 0x3e,
+             0x39, 0x0c, 0xf2, 0x20, 0x13, 0xa8, 0xc7, 0x34, 0xc6, 0xcb, 0x9e,
+             0xab, 0x41, 0xf1, 0x7c, 0x3c, 0x80, 0x32, 0xa2, 0xe4, 0xac, 0xa0,
+             0x56, 0x9e, 0xa3, 0x6f, 0x08, 0x60, 0xc7, 0xa1, 0xaf, 0x28, 0xfa,
+             0x47, 0x68, 0x40, 0xd6, 0x60, 0x11, 0x16, 0x88, 0x59, 0x33, 0x4a,
+             0x9e, 0x4e, 0xf9, 0xcc, 0x2e, 0x61, 0xa0, 0xe2, 0x9e})),
+    std::make_pair(
+        31,
+        std::vector<uint8_t>(
+            {0x29, 0xf8, 0xb8, 0xc7, 0x8c, 0x80, 0xf2, 0xfc, 0xb4, 0xbd, 0xf7,
+             0x82, 0x5e, 0xd9, 0x0a, 0x70, 0xd6, 0x25, 0xff, 0x78, 0x5d, 0x26,
+             0x26, 0x77, 0xe2, 0x50, 0xc0, 0x4f, 0x37, 0x20, 0xc8, 0x88, 0xd0,
+             0x3f, 0x80, 0x45, 0xe4, 0xed, 0xf3, 0xf5, 0x28, 0x5b, 0xd3, 0x9d,
+             0x92, 0x8a, 0x10, 0xa7, 0xd0, 0xa5, 0xdf, 0x00, 0xb8, 0x48, 0x4a,
+             0xc2, 0x86, 0x81, 0x42, 0xa1, 0xe8, 0xbe, 0xa3, 0x51})),
+    std::make_pair(
+        32,
+        std::vector<uint8_t>(
+            {0x5c, 0x52, 0x92, 0x0a, 0x72, 0x63, 0xe3, 0x9d, 0x57, 0x92, 0x0c,
+             0xa0, 0xcb, 0x75, 0x2a, 0xc6, 0xd7, 0x9a, 0x04, 0xfe, 0xf8, 0xa7,
+             0xa2, 0x16, 0xa1, 0xec, 0xb7, 0x11, 0x5c, 0xe0, 0x6d, 0x89, 0xfd,
+             0x7d, 0x73, 0x5b, 0xd6, 0xf4, 0x27, 0x25, 0x55, 0xdb, 0xa2, 0x2c,
+             0x2d, 0x1c, 0x96, 0xe6, 0x35, 0x23, 0x22, 0xc6, 0x2c, 0x56, 0x30,
+             0xfd, 0xe0, 0xf4, 0x77, 0x7a, 0x76, 0xc3, 0xde, 0x2c})),
+    std::make_pair(
+        33,
+        std::vector<uint8_t>(
+            {0x83, 0xb0, 0x98, 0xf2, 0x62, 0x25, 0x1b, 0xf6, 0x60, 0x06, 0x4a,
+             0x9d, 0x35, 0x11, 0xce, 0x76, 0x87, 0xa0, 0x9e, 0x6d, 0xfb, 0xb8,
+             0x78, 0x29, 0x9c, 0x30, 0xe9, 0x3d, 0xfb, 0x43, 0xa9, 0x31, 0x4d,
+             0xb9, 0xa6, 0x00, 0x33, 0x7d, 0xb2, 0x6e, 0xbe, 0xed, 0xaf, 0x22,
+             0x56, 0xa9, 0x6d, 0xab, 0xe9, 0xb2, 0x9e, 0x75, 0x73, 0xad, 0x11,
+             0xc3, 0x52, 0x3d, 0x87, 0x4d, 0xde, 0x5b, 0xe7, 0xed})),
+    std::make_pair(
+        34,
+        std::vector<uint8_t>(
+            {0x94, 0x47, 0xd9, 0x8a, 0xa5, 0xc9, 0x33, 0x13, 0x52, 0xf4, 0x3d,
+             0x3e, 0x56, 0xd0, 0xa9, 0xa9, 0xf9, 0x58, 0x18, 0x65, 0x99, 0x8e,
+             0x28, 0x85, 0xcc, 0x56, 0xdd, 0x0a, 0x0b, 0xd5, 0xa7, 0xb5, 0x05,
+             0x95, 0xbd, 0x10, 0xf7, 0x52, 0x9b, 0xcd, 0x31, 0xf3, 0x7d, 0xc1,
+             0x6a, 0x14, 0x65, 0xd5, 0x94, 0x07, 0x96, 0x67, 0xda, 0x2a, 0x3f,
+             0xcb, 0x70, 0x40, 0x14, 0x98, 0x83, 0x7c, 0xed, 0xeb})),
+    std::make_pair(
+        35,
+        std::vector<uint8_t>(
+            {0x86, 0x77, 0x32, 0xf2, 0xfe, 0xeb, 0x23, 0x89, 0x30, 0x97, 0x56,
+             0x1a, 0xc7, 0x10, 0xa4, 0xbf, 0xf4, 0x53, 0xbe, 0x9c, 0xfb, 0xed,
+             0xba, 0x8b, 0xa3, 0x24, 0xf9, 0xd3, 0x12, 0xa8, 0x2d, 0x73, 0x2e,
+             0x1b, 0x83, 0xb8, 0x29, 0xfd, 0xcd, 0x17, 0x7b, 0x88, 0x2c, 0xa0,
+             0xc1, 0xbf, 0x54, 0x4b, 0x22, 0x3b, 0xe5, 0x29, 0x92, 0x4a, 0x24,
+             0x6a, 0x63, 0xcf, 0x05, 0x9b, 0xfd, 0xc5, 0x0a, 0x1b})),
+    std::make_pair(
+        36,
+        std::vector<uint8_t>(
+            {0xf1, 0x5a, 0xb2, 0x6d, 0x4c, 0xdf, 0xcf, 0x56, 0xe1, 0x96, 0xbb,
+             0x6b, 0xa1, 0x70, 0xa8, 0xfc, 0xcc, 0x41, 0x4d, 0xe9, 0x28, 0x5a,
+             0xfd, 0x98, 0xa3, 0xd3, 0xcf, 0x2f, 0xb8, 0x8f, 0xcb, 0xc0, 0xf1,
+             0x98, 0x32, 0xac, 0x43, 0x3a, 0x5b, 0x2c, 0xc2, 0x39, 0x2a, 0x4c,
+             0xe3, 0x43, 0x32, 0x98, 0x7d, 0x8d, 0x2c, 0x2b, 0xef, 0x6c, 0x34,
+             0x66, 0x13, 0x8d, 0xb0, 0xc6, 0xe4, 0x2f, 0xa4, 0x7b})),
+    std::make_pair(
+        37,
+        std::vector<uint8_t>(
+            {0x28, 0x13, 0x51, 0x6d, 0x68, 0xed, 0x4a, 0x08, 0xb3, 0x9d, 0x64,
+             0x8a, 0xa6, 0xaa, 0xcd, 0x81, 0xe9, 0xd6, 0x55, 0xec, 0xd5, 0xf0,
+             0xc1, 0x35, 0x56, 0xc6, 0x0f, 0xdf, 0x0d, 0x33, 0x3e, 0xa3, 0x84,
+             0x64, 0xb3, 0x6c, 0x02, 0xba, 0xcc, 0xd7, 0x46, 0xe9, 0x57, 0x5e,
+             0x96, 0xc6, 0x30, 0x14, 0xf0, 0x74, 0xae, 0x34, 0xa0, 0xa2, 0x5b,
+             0x32, 0x0f, 0x0f, 0xbe, 0xdd, 0x6a, 0xcf, 0x76, 0x65})),
+    std::make_pair(
+        38,
+        std::vector<uint8_t>(
+            {0xd3, 0x25, 0x9a, 0xfc, 0xa8, 0xa4, 0x89, 0x62, 0xfa, 0x89, 0x2e,
+             0x14, 0x5a, 0xcf, 0x54, 0x7f, 0x26, 0x92, 0x3a, 0xe8, 0xd4, 0x92,
+             0x4c, 0x8a, 0x53, 0x15, 0x81, 0x52, 0x6b, 0x04, 0xb4, 0x4c, 0x7a,
+             0xf8, 0x3c, 0x64, 0x3e, 0xf5, 0xa0, 0xbc, 0x28, 0x2d, 0x36, 0xf3,
+             0xfb, 0x04, 0xc8, 0x4e, 0x28, 0xb3, 0x51, 0xf4, 0x0c, 0x74, 0xb6,
+             0x9d, 0xc7, 0x84, 0x0b, 0xc7, 0x17, 0xb6, 0xf1, 0x5f})),
+    std::make_pair(
+        39,
+        std::vector<uint8_t>(
+            {0xf1, 0x4b, 0x06, 0x1a, 0xe3, 0x59, 0xfa, 0x31, 0xb9, 0x89, 0xe3,
+             0x03, 0x32, 0xbf, 0xe8, 0xde, 0x8c, 0xc8, 0xcd, 0xb5, 0x68, 0xe1,
+             0x4b, 0xe2, 0x14, 0xa2, 0x22, 0x3b, 0x84, 0xca, 0xab, 0x74, 0x19,
+             0x54, 0x9e, 0xcf, 0xcc, 0x96, 0xce, 0x2a, 0xce, 0xc1, 0x19, 0x48,
+             0x5d, 0x87, 0xd1, 0x57, 0xd3, 0xa8, 0x73, 0x4f, 0xc4, 0x26, 0x59,
+             0x7d, 0x64, 0xf3, 0x65, 0x70, 0xce, 0xaf, 0x22, 0x4d})),
+    std::make_pair(
+        40,
+        std::vector<uint8_t>(
+            {0x55, 0xe7, 0x0b, 0x01, 0xd1, 0xfb, 0xf8, 0xb2, 0x3b, 0x57, 0xfb,
+             0x62, 0xe2, 0x6c, 0x2c, 0xe5, 0x4f, 0x13, 0xf8, 0xfa, 0x24, 0x64,
+             0xe6, 0xeb, 0x98, 0xd1, 0x6a, 0x61, 0x17, 0x02, 0x6d, 0x8b, 0x90,
+             0x81, 0x90, 0x12, 0x49, 0x6d, 0x40, 0x71, 0xeb, 0xe2, 0xe5, 0x95,
+             0x57, 0xec, 0xe3, 0x51, 0x9a, 0x7a, 0xa4, 0x58, 0x02, 0xf9, 0x61,
+             0x53, 0x74, 0x87, 0x73, 0x32, 0xb7, 0x34, 0x90, 0xb3})),
+    std::make_pair(
+        41,
+        std::vector<uint8_t>(
+            {0x25, 0x26, 0x1e, 0xb2, 0x96, 0x97, 0x1d, 0x6e, 0x4a, 0x71, 0xb2,
+             0x92, 0x8e, 0x64, 0x83, 0x9c, 0x67, 0xd4, 0x22, 0x87, 0x2b, 0xf9,
+             0xf3, 0xc3, 0x19, 0x93, 0x61, 0x52, 0x22, 0xde, 0x9f, 0x8f, 0x0b,
+             0x2c, 0x4b, 0xe8, 0x54, 0x85, 0x59, 0xb4, 0xb3, 0x54, 0xe7, 0x36,
+             0x41, 0x6e, 0x32, 0x18, 0xd4, 0xe8, 0xa1, 0xe2, 0x19, 0xa4, 0xa6,
+             0xd4, 0x3e, 0x1a, 0x9a, 0x52, 0x1d, 0x0e, 0x75, 0xfc})),
+    std::make_pair(
+        42,
+        std::vector<uint8_t>(
+            {0x08, 0x30, 0x7f, 0x34, 0x7c, 0x41, 0x29, 0x4e, 0x34, 0xbb, 0x54,
+             0xcb, 0x42, 0xb1, 0x52, 0x2d, 0x22, 0xf8, 0x24, 0xf7, 0xb6, 0xe5,
+             0xdb, 0x50, 0xfd, 0xa0, 0x96, 0x79, 0x8e, 0x18, 0x1a, 0x8f, 0x02,
+             0x6f, 0xa2, 0x7b, 0x4a, 0xe4, 0x5d, 0x52, 0xa6, 0x2c, 0xaf, 0x9d,
+             0x51, 0x98, 0xe2, 0x4a, 0x49, 0x13, 0xc6, 0x67, 0x17, 0x75, 0xb2,
+             0xd7, 0x23, 0xc1, 0x23, 0x9b, 0xfb, 0xf0, 0x16, 0xd7})),
+    std::make_pair(
+        43,
+        std::vector<uint8_t>(
+            {0x1e, 0x5c, 0x62, 0xe7, 0xe9, 0xbf, 0xa1, 0xb1, 0x18, 0x74, 0x7a,
+             0x2d, 0xe0, 0x8b, 0x3c, 0xa1, 0x01, 0x12, 0xaf, 0x96, 0xa4, 0x6e,
+             0x4b, 0x22, 0xc3, 0xfc, 0x06, 0xf9, 0xbf, 0xee, 0x4e, 0xb5, 0xc4,
+             0x9e, 0x05, 0x7a, 0x4a, 0x48, 0x86, 0x23, 0x43, 0x24, 0x57, 0x25,
+             0x76, 0xbb, 0x9b, 0x5e, 0xcf, 0xde, 0x0d, 0x99, 0xb0, 0xde, 0x4f,
+             0x98, 0xec, 0x16, 0xe4, 0xd1, 0xb8, 0x5f, 0xa9, 0x47})),
+    std::make_pair(
+        44,
+        std::vector<uint8_t>(
+            {0xc7, 0x4a, 0x77, 0x39, 0x5f, 0xb8, 0xbc, 0x12, 0x64, 0x47, 0x45,
+             0x48, 0x38, 0xe5, 0x61, 0xe9, 0x62, 0x85, 0x3d, 0xc7, 0xeb, 0x49,
+             0xa1, 0xe3, 0xcb, 0x67, 0xc3, 0xd0, 0x85, 0x1f, 0x3e, 0x39, 0x51,
+             0x7b, 0xe8, 0xc3, 0x50, 0xac, 0x91, 0x09, 0x03, 0xd4, 0x9c, 0xd2,
+             0xbf, 0xdf, 0x54, 0x5c, 0x99, 0x31, 0x6d, 0x03, 0x46, 0x17, 0x0b,
+             0x73, 0x9f, 0x0a, 0xdd, 0x5d, 0x53, 0x3c, 0x2c, 0xfc})),
+    std::make_pair(
+        45,
+        std::vector<uint8_t>(
+            {0x0d, 0xd5, 0x7b, 0x42, 0x3c, 0xc0, 0x1e, 0xb2, 0x86, 0x13, 0x91,
+             0xeb, 0x88, 0x6a, 0x0d, 0x17, 0x07, 0x9b, 0x93, 0x3f, 0xc7, 0x6e,
+             0xb3, 0xfc, 0x08, 0xa1, 0x9f, 0x8a, 0x74, 0x95, 0x2c, 0xb6, 0x8f,
+             0x6b, 0xcd, 0xc6, 0x44, 0xf7, 0x73, 0x70, 0x96, 0x6e, 0x4d, 0x13,
+             0xe8, 0x05, 0x60, 0xbc, 0xf0, 0x82, 0xef, 0x04, 0x79, 0xd4, 0x8f,
+             0xbb, 0xab, 0x4d, 0xf0, 0x3b, 0x53, 0xa4, 0xe1, 0x78})),
+    std::make_pair(
+        46,
+        std::vector<uint8_t>(
+            {0x4d, 0x8d, 0xc3, 0x92, 0x3e, 0xdc, 0xcd, 0xfc, 0xe7, 0x00, 0x72,
+             0x39, 0x8b, 0x8a, 0x3d, 0xa5, 0xc3, 0x1f, 0xcb, 0x3e, 0xe3, 0xb6,
+             0x45, 0xc8, 0x5f, 0x71, 0x7c, 0xba, 0xeb, 0x4b, 0x67, 0x3a, 0x19,
+             0x39, 0x44, 0x25, 0xa5, 0x85, 0xbf, 0xb4, 0x64, 0xd9, 0x2f, 0x15,
+             0x97, 0xd0, 0xb7, 0x54, 0xd1, 0x63, 0xf9, 0x7c, 0xed, 0x34, 0x3b,
+             0x25, 0xdb, 0x5a, 0x70, 0xef, 0x48, 0xeb, 0xb3, 0x4f})),
+    std::make_pair(
+        47,
+        std::vector<uint8_t>(
+            {0xf0, 0xa5, 0x05, 0x53, 0xe4, 0xdf, 0xb0, 0xc4, 0xe3, 0xe3, 0xd3,
+             0xba, 0x82, 0x03, 0x48, 0x57, 0xe3, 0xb1, 0xe5, 0x09, 0x18, 0xf5,
+             0xb8, 0xa7, 0xd6, 0x98, 0xe1, 0x0d, 0x24, 0x2b, 0x0f, 0xb5, 0x44,
+             0xaf, 0x6c, 0x92, 0xd0, 0xc3, 0xaa, 0xf9, 0x93, 0x22, 0x20, 0x41,
+             0x61, 0x17, 0xb4, 0xe7, 0x8e, 0xcb, 0x8a, 0x8f, 0x43, 0x0e, 0x13,
+             0xb8, 0x2a, 0x59, 0x15, 0x29, 0x0a, 0x58, 0x19, 0xc5})),
+    std::make_pair(
+        48,
+        std::vector<uint8_t>(
+            {0xb1, 0x55, 0x43, 0xf3, 0xf7, 0x36, 0x08, 0x66, 0x27, 0xcc, 0x53,
+             0x65, 0xe7, 0xe8, 0x98, 0x8c, 0x2e, 0xf1, 0x55, 0xc0, 0xfd, 0x4f,
+             0x42, 0x89, 0x61, 0xb0, 0x0d, 0x15, 0x26, 0xf0, 0x4d, 0x6d, 0x6a,
+             0x65, 0x8b, 0x4b, 0x8e, 0xd3, 0x2c, 0x5d, 0x86, 0x21, 0xe7, 0xf4,
+             0xf8, 0xe8, 0xa9, 0x33, 0xd9, 0xec, 0xc9, 0xdd, 0x1b, 0x83, 0x33,
+             0xcb, 0xe2, 0x8c, 0xfc, 0x37, 0xd9, 0x71, 0x9e, 0x1c})),
+    std::make_pair(
+        49,
+        std::vector<uint8_t>(
+            {0x7b, 0x4f, 0xa1, 0x58, 0xe4, 0x15, 0xfe, 0xf0, 0x23, 0x24, 0x72,
+             0x64, 0xcb, 0xbe, 0x15, 0xd1, 0x6d, 0x91, 0xa4, 0x44, 0x24, 0xa8,
+             0xdb, 0x70, 0x7e, 0xb1, 0xe2, 0x03, 0x3c, 0x30, 0xe9, 0xe1, 0xe7,
+             0xc8, 0xc0, 0x86, 0x45, 0x95, 0xd2, 0xcb, 0x8c, 0x58, 0x0e, 0xb4,
+             0x7e, 0x9d, 0x16, 0xab, 0xbd, 0x7e, 0x44, 0xe8, 0x24, 0xf7, 0xce,
+             0xdb, 0x7d, 0xef, 0x57, 0x13, 0x0e, 0x52, 0xcf, 0xe9})),
+    std::make_pair(
+        50,
+        std::vector<uint8_t>(
+            {0x60, 0x42, 0x4f, 0xf2, 0x32, 0x34, 0xc3, 0x4d, 0xc9, 0x68, 0x7a,
+             0xd5, 0x02, 0x86, 0x93, 0x72, 0xcc, 0x31, 0xa5, 0x93, 0x80, 0x18,
+             0x6b, 0xc2, 0x36, 0x1c, 0x83, 0x5d, 0x97, 0x2f, 0x49, 0x66, 0x6e,
+             0xb1, 0xac, 0x69, 0x62, 0x9d, 0xe6, 0x46, 0xf0, 0x3f, 0x9b, 0x4d,
+             0xb9, 0xe2, 0xac, 0xe0, 0x93, 0xfb, 0xfd, 0xf8, 0xf2, 0x0a, 0xb5,
+             0xf9, 0x85, 0x41, 0x97, 0x8b, 0xe8, 0xef, 0x54, 0x9f})),
+    std::make_pair(
+        51,
+        std::vector<uint8_t>(
+            {0x74, 0x06, 0x01, 0x8c, 0xe7, 0x04, 0xd8, 0x4f, 0x5e, 0xb9, 0xc7,
+             0x9f, 0xea, 0x97, 0xda, 0x34, 0x56, 0x99, 0x46, 0x8a, 0x35, 0x0e,
+             0xe0, 0xb2, 0xd0, 0xf3, 0xa4, 0xbf, 0x20, 0x70, 0x30, 0x4e, 0xa8,
+             0x62, 0xd7, 0x2a, 0x51, 0xc5, 0x7d, 0x30, 0x64, 0x94, 0x72, 0x86,
+             0xf5, 0x31, 0xe0, 0xea, 0xf7, 0x56, 0x37, 0x02, 0x26, 0x2e, 0x6c,
+             0x72, 0x4a, 0xbf, 0x5e, 0xd8, 0xc8, 0x39, 0x8d, 0x17})),
+    std::make_pair(
+        52,
+        std::vector<uint8_t>(
+            {0x14, 0xef, 0x5c, 0x6d, 0x64, 0x7b, 0x3b, 0xd1, 0xe6, 0xe3, 0x20,
+             0x06, 0xc2, 0x31, 0x19, 0x98, 0x10, 0xde, 0x5c, 0x4d, 0xc8, 0x8e,
+             0x70, 0x24, 0x02, 0x73, 0xb0, 0xea, 0x18, 0xe6, 0x51, 0xa3, 0xeb,
+             0x4f, 0x5c, 0xa3, 0x11, 0x4b, 0x8a, 0x56, 0x71, 0x69, 0x69, 0xc7,
+             0xcd, 0xa2, 0x7e, 0x0c, 0x8d, 0xb8, 0x32, 0xad, 0x5e, 0x89, 0xa2,
+             0xdc, 0x6c, 0xb0, 0xad, 0xbe, 0x7d, 0x93, 0xab, 0xd1})),
+    std::make_pair(
+        53,
+        std::vector<uint8_t>(
+            {0x38, 0xcf, 0x6c, 0x24, 0xe3, 0xe0, 0x8b, 0xcf, 0x1f, 0x6c, 0xf3,
+             0xd1, 0xb1, 0xf6, 0x5b, 0x90, 0x52, 0x39, 0xa3, 0x11, 0x80, 0x33,
+             0x24, 0x9e, 0x44, 0x81, 0x13, 0xec, 0x63, 0x2e, 0xa6, 0xdc, 0x34,
+             0x6f, 0xee, 0xb2, 0x57, 0x1c, 0x38, 0xbd, 0x9a, 0x73, 0x98, 0xb2,
+             0x22, 0x12, 0x80, 0x32, 0x80, 0x02, 0xb2, 0x3e, 0x1a, 0x45, 0xad,
+             0xaf, 0xfe, 0x66, 0xd9, 0x3f, 0x65, 0x64, 0xea, 0xa2})),
+    std::make_pair(
+        54,
+        std::vector<uint8_t>(
+            {0x6c, 0xd7, 0x20, 0x8a, 0x4b, 0xc7, 0xe7, 0xe5, 0x62, 0x01, 0xbb,
+             0xba, 0x02, 0xa0, 0xf4, 0x89, 0xcd, 0x38, 0x4a, 0xbe, 0x40, 0xaf,
+             0xd4, 0x22, 0x2f, 0x15, 0x8b, 0x3d, 0x98, 0x6e, 0xe7, 0x2a, 0x54,
+             0xc5, 0x0f, 0xb6, 0x4f, 0xd4, 0xed, 0x25, 0x30, 0xed, 0xa2, 0xc8,
+             0xaf, 0x29, 0x28, 0xa0, 0xda, 0x6d, 0x4f, 0x83, 0x0a, 0xe1, 0xc9,
+             0xdb, 0x46, 0x9d, 0xfd, 0x97, 0x0f, 0x12, 0xa5, 0x6f})),
+    std::make_pair(
+        55,
+        std::vector<uint8_t>(
+            {0x65, 0x98, 0x58, 0xf0, 0xb5, 0xc9, 0xed, 0xab, 0x5b, 0x94, 0xfd,
+             0x73, 0x2f, 0x6e, 0x6b, 0x17, 0xc5, 0x1c, 0xc0, 0x96, 0x10, 0x4f,
+             0x09, 0xbe, 0xb3, 0xaf, 0xc3, 0xaa, 0x46, 0x7c, 0x2e, 0xcf, 0x88,
+             0x5c, 0x4c, 0x65, 0x41, 0xef, 0xfa, 0x90, 0x23, 0xd3, 0xb5, 0x73,
+             0x8a, 0xe5, 0xa1, 0x4d, 0x86, 0x7e, 0x15, 0xdb, 0x06, 0xfe, 0x1f,
+             0x9d, 0x11, 0x27, 0xb7, 0x7e, 0x1a, 0xab, 0xb5, 0x16})),
+    std::make_pair(
+        56,
+        std::vector<uint8_t>(
+            {0x26, 0xcc, 0xa0, 0x12, 0x6f, 0x5d, 0x1a, 0x81, 0x3c, 0x62, 0xe5,
+             0xc7, 0x10, 0x01, 0xc0, 0x46, 0xf9, 0xc9, 0x20, 0x95, 0x70, 0x45,
+             0x50, 0xbe, 0x58, 0x73, 0xa4, 0x95, 0xa9, 0x99, 0xad, 0x01, 0x0a,
+             0x4f, 0x79, 0x49, 0x1f, 0x24, 0xf2, 0x86, 0x50, 0x0a, 0xdc, 0xe1,
+             0xa1, 0x37, 0xbc, 0x20, 0x84, 0xe4, 0x94, 0x9f, 0x5b, 0x72, 0x94,
+             0xce, 0xfe, 0x51, 0xec, 0xaf, 0xf8, 0xe9, 0x5c, 0xba})),
+    std::make_pair(
+        57,
+        std::vector<uint8_t>(
+            {0x41, 0x47, 0xc1, 0xf5, 0x51, 0x72, 0x78, 0x8c, 0x55, 0x67, 0xc5,
+             0x61, 0xfe, 0xef, 0x87, 0x6f, 0x62, 0x1f, 0xff, 0x1c, 0xe8, 0x77,
+             0x86, 0xb8, 0x46, 0x76, 0x37, 0xe7, 0x0d, 0xfb, 0xcd, 0x0d, 0xbd,
+             0xb6, 0x41, 0x5c, 0xb6, 0x00, 0x95, 0x4a, 0xb9, 0xc0, 0x4c, 0x0e,
+             0x45, 0x7e, 0x62, 0x5b, 0x40, 0x72, 0x22, 0xc0, 0xfe, 0x1a, 0xe2,
+             0x1b, 0x21, 0x43, 0x68, 0x8a, 0xda, 0x94, 0xdc, 0x58})),
+    std::make_pair(
+        58,
+        std::vector<uint8_t>(
+            {0x5b, 0x1b, 0xf1, 0x54, 0xc6, 0x2a, 0x8a, 0xf6, 0xe9, 0x3d, 0x35,
+             0xf1, 0x8f, 0x7f, 0x90, 0xab, 0xb1, 0x6a, 0x6e, 0xf0, 0xe8, 0xd1,
+             0xae, 0xcd, 0x11, 0x8b, 0xf7, 0x01, 0x67, 0xba, 0xb2, 0xaf, 0x08,
+             0x93, 0x5c, 0x6f, 0xdc, 0x06, 0x63, 0xce, 0x74, 0x48, 0x2d, 0x17,
+             0xa8, 0xe5, 0x4b, 0x54, 0x6d, 0x1c, 0x29, 0x66, 0x31, 0xc6, 0x5f,
+             0x3b, 0x52, 0x2a, 0x51, 0x58, 0x39, 0xd4, 0x3d, 0x71})),
+    std::make_pair(
+        59,
+        std::vector<uint8_t>(
+            {0x9f, 0x60, 0x04, 0x19, 0xa4, 0xe8, 0xf4, 0xfb, 0x83, 0x4c, 0x24,
+             0xb0, 0xf7, 0xfc, 0x13, 0xbf, 0x4e, 0x27, 0x9d, 0x98, 0xe8, 0xa3,
+             0xc7, 0x65, 0xee, 0x93, 0x49, 0x17, 0x40, 0x3e, 0x3a, 0x66, 0x09,
+             0x71, 0x82, 0xea, 0x21, 0x45, 0x3c, 0xb6, 0x3e, 0xbb, 0xe8, 0xb7,
+             0x3a, 0x9c, 0x21, 0x67, 0x59, 0x64, 0x46, 0x43, 0x8c, 0x57, 0x62,
+             0x7f, 0x33, 0x0b, 0xad, 0xd4, 0xf5, 0x69, 0xf7, 0xd6})),
+    std::make_pair(
+        60,
+        std::vector<uint8_t>(
+            {0x45, 0x7e, 0xf6, 0x46, 0x6a, 0x89, 0x24, 0xfd, 0x80, 0x11, 0xa3,
+             0x44, 0x71, 0xa5, 0xa1, 0xac, 0x8c, 0xcd, 0x9b, 0xd0, 0xd0, 0x7a,
+             0x97, 0x41, 0x4a, 0xc9, 0x43, 0x02, 0x1c, 0xe4, 0xb9, 0xe4, 0xb9,
+             0xc8, 0xdb, 0x0a, 0x28, 0xf0, 0x16, 0xed, 0x43, 0xb1, 0x54, 0x24,
+             0x81, 0x99, 0x00, 0x22, 0x14, 0x7b, 0x31, 0x3e, 0x19, 0x46, 0x71,
+             0x13, 0x1e, 0x70, 0x8d, 0xd4, 0x3a, 0x3e, 0xd7, 0xdc})),
+    std::make_pair(
+        61,
+        std::vector<uint8_t>(
+            {0x99, 0x97, 0xb2, 0x19, 0x4d, 0x9a, 0xf6, 0xdf, 0xcb, 0x91, 0x43,
+             0xf4, 0x1c, 0x0e, 0xd8, 0x3d, 0x3a, 0x3f, 0x43, 0x88, 0x36, 0x11,
+             0x03, 0xd3, 0x8c, 0x2a, 0x49, 0xb2, 0x80, 0xa5, 0x81, 0x21, 0x27,
+             0x15, 0xfd, 0x90, 0x8d, 0x41, 0xc6, 0x51, 0xf5, 0xc7, 0x15, 0xca,
+             0x38, 0xc0, 0xce, 0x28, 0x30, 0xa3, 0x7e, 0x00, 0xe5, 0x08, 0xce,
+             0xd1, 0xbc, 0xdc, 0x32, 0x0e, 0x5e, 0x4d, 0x1e, 0x2e})),
+    std::make_pair(
+        62,
+        std::vector<uint8_t>(
+            {0x5c, 0x6b, 0xbf, 0x16, 0xba, 0xa1, 0x80, 0xf9, 0x86, 0xbd, 0x40,
+             0xa1, 0x28, 0x7e, 0xd4, 0xc5, 0x49, 0x77, 0x0e, 0x72, 0x84, 0x85,
+             0x8f, 0xc4, 0x7b, 0xc2, 0x1a, 0xb9, 0x5e, 0xbb, 0xf3, 0x37, 0x4b,
+             0x4e, 0xe3, 0xfd, 0x9f, 0x2a, 0xf6, 0x0f, 0x33, 0x95, 0x22, 0x1b,
+             0x2a, 0xcc, 0x76, 0xf2, 0xd3, 0x4c, 0x13, 0x29, 0x54, 0x04, 0x9f,
+             0x8a, 0x3a, 0x99, 0x6f, 0x1e, 0x32, 0xec, 0x84, 0xe5})),
+    std::make_pair(
+        63,
+        std::vector<uint8_t>(
+            {0xd1, 0x0b, 0xf9, 0xa1, 0x5b, 0x1c, 0x9f, 0xc8, 0xd4, 0x1f, 0x89,
+             0xbb, 0x14, 0x0b, 0xf0, 0xbe, 0x08, 0xd2, 0xf3, 0x66, 0x61, 0x76,
+             0xd1, 0x3b, 0xaa, 0xc4, 0xd3, 0x81, 0x35, 0x8a, 0xd0, 0x74, 0xc9,
+             0xd4, 0x74, 0x8c, 0x30, 0x05, 0x20, 0xeb, 0x02, 0x6d, 0xae, 0xae,
+             0xa7, 0xc5, 0xb1, 0x58, 0x89, 0x2f, 0xde, 0x4e, 0x8e, 0xc1, 0x7d,
+             0xc9, 0x98, 0xdc, 0xd5, 0x07, 0xdf, 0x26, 0xeb, 0x63})),
+    std::make_pair(
+        64,
+        std::vector<uint8_t>(
+            {0x2f, 0xc6, 0xe6, 0x9f, 0xa2, 0x6a, 0x89, 0xa5, 0xed, 0x26, 0x90,
+             0x92, 0xcb, 0x9b, 0x2a, 0x44, 0x9a, 0x44, 0x09, 0xa7, 0xa4, 0x40,
+             0x11, 0xee, 0xca, 0xd1, 0x3d, 0x7c, 0x4b, 0x04, 0x56, 0x60, 0x2d,
+             0x40, 0x2f, 0xa5, 0x84, 0x4f, 0x1a, 0x7a, 0x75, 0x81, 0x36, 0xce,
+             0x3d, 0x5d, 0x8d, 0x0e, 0x8b, 0x86, 0x92, 0x1f, 0xff, 0xf4, 0xf6,
+             0x92, 0xdd, 0x95, 0xbd, 0xc8, 0xe5, 0xff, 0x00, 0x52})),
+    std::make_pair(
+        65,
+        std::vector<uint8_t>(
+            {0xfc, 0xbe, 0x8b, 0xe7, 0xdc, 0xb4, 0x9a, 0x32, 0xdb, 0xdf, 0x23,
+             0x94, 0x59, 0xe2, 0x63, 0x08, 0xb8, 0x4d, 0xff, 0x1e, 0xa4, 0x80,
+             0xdf, 0x8d, 0x10, 0x4e, 0xef, 0xf3, 0x4b, 0x46, 0xfa, 0xe9, 0x86,
+             0x27, 0xb4, 0x50, 0xc2, 0x26, 0x7d, 0x48, 0xc0, 0x94, 0x6a, 0x69,
+             0x7c, 0x5b, 0x59, 0x53, 0x14, 0x52, 0xac, 0x04, 0x84, 0xf1, 0xc8,
+             0x4e, 0x3a, 0x33, 0xd0, 0xc3, 0x39, 0xbb, 0x2e, 0x28})),
+    std::make_pair(
+        66,
+        std::vector<uint8_t>(
+            {0xa1, 0x90, 0x93, 0xa6, 0xe3, 0xbc, 0xf5, 0x95, 0x2f, 0x85, 0x0f,
+             0x20, 0x30, 0xf6, 0x9b, 0x96, 0x06, 0xf1, 0x47, 0xf9, 0x0b, 0x8b,
+             0xae, 0xe3, 0x36, 0x2d, 0xa7, 0x1d, 0x9f, 0x35, 0xb4, 0x4e, 0xf9,
+             0xd8, 0xf0, 0xa7, 0x71, 0x2b, 0xa1, 0x87, 0x7f, 0xdd, 0xcd, 0x2d,
+             0x8e, 0xa8, 0xf1, 0xe5, 0xa7, 0x73, 0xd0, 0xb7, 0x45, 0xd4, 0x72,
+             0x56, 0x05, 0x98, 0x3a, 0x2d, 0xe9, 0x01, 0xf8, 0x03})),
+    std::make_pair(
+        67,
+        std::vector<uint8_t>(
+            {0x3c, 0x20, 0x06, 0x42, 0x3f, 0x73, 0xe2, 0x68, 0xfa, 0x59, 0xd2,
+             0x92, 0x03, 0x77, 0xeb, 0x29, 0xa4, 0xf9, 0xa8, 0xb4, 0x62, 0xbe,
+             0x15, 0x98, 0x3e, 0xe3, 0xb8, 0x5a, 0xe8, 0xa7, 0x8e, 0x99, 0x26,
+             0x33, 0x58, 0x1a, 0x90, 0x99, 0x89, 0x3b, 0x63, 0xdb, 0x30, 0x24,
+             0x1c, 0x34, 0xf6, 0x43, 0x02, 0x7d, 0xc8, 0x78, 0x27, 0x9a, 0xf5,
+             0x85, 0x0d, 0x7e, 0x2d, 0x4a, 0x26, 0x53, 0x07, 0x3a})),
+    std::make_pair(
+        68,
+        std::vector<uint8_t>(
+            {0xd0, 0xf2, 0xf2, 0xe3, 0x78, 0x76, 0x53, 0xf7, 0x7c, 0xce, 0x2f,
+             0xa2, 0x48, 0x35, 0x78, 0x5b, 0xbd, 0x0c, 0x43, 0x3f, 0xc7, 0x79,
+             0x46, 0x5a, 0x11, 0x51, 0x49, 0x90, 0x5a, 0x9d, 0xd1, 0xcb, 0x82,
+             0x7a, 0x62, 0x85, 0x06, 0xd4, 0x57, 0xfc, 0xf1, 0x24, 0xa0, 0xc2,
+             0xae, 0xf9, 0xce, 0x2d, 0x2a, 0x0a, 0x0f, 0x63, 0x54, 0x55, 0x70,
+             0xd8, 0x66, 0x7f, 0xf9, 0xe2, 0xeb, 0xa0, 0x73, 0x34})),
+    std::make_pair(
+        69,
+        std::vector<uint8_t>(
+            {0x78, 0xa9, 0xfc, 0x04, 0x8e, 0x25, 0xc6, 0xdc, 0xb5, 0xde, 0x45,
+             0x66, 0x7d, 0xe8, 0xff, 0xdd, 0x3a, 0x93, 0x71, 0x11, 0x41, 0xd5,
+             0x94, 0xe9, 0xfa, 0x62, 0xa9, 0x59, 0x47, 0x5d, 0xa6, 0x07, 0x5e,
+             0xa8, 0xf0, 0x91, 0x6e, 0x84, 0xe4, 0x5a, 0xd9, 0x11, 0xb7, 0x54,
+             0x67, 0x07, 0x7e, 0xe5, 0x2d, 0x2c, 0x9a, 0xeb, 0xf4, 0xd5, 0x8f,
+             0x20, 0xce, 0x4a, 0x3a, 0x00, 0x45, 0x8b, 0x05, 0xd4})),
+    std::make_pair(
+        70,
+        std::vector<uint8_t>(
+            {0x45, 0x81, 0x3f, 0x44, 0x17, 0x69, 0xab, 0x6e, 0xd3, 0x7d, 0x34,
+             0x9f, 0xf6, 0xe7, 0x22, 0x67, 0xd7, 0x6a, 0xe6, 0xbb, 0x3e, 0x3c,
+             0x61, 0x2e, 0xc0, 0x5c, 0x6e, 0x02, 0xa1, 0x2a, 0xf5, 0xa3, 0x7c,
+             0x91, 0x8b, 0x52, 0xbf, 0x74, 0x26, 0x7c, 0x3f, 0x6a, 0x3f, 0x18,
+             0x3a, 0x80, 0x64, 0xff, 0x84, 0xc0, 0x7b, 0x19, 0x3d, 0x08, 0x06,
+             0x67, 0x89, 0xa0, 0x1a, 0xcc, 0xdb, 0x6f, 0x93, 0x40})),
+    std::make_pair(
+        71,
+        std::vector<uint8_t>(
+            {0x95, 0x6d, 0xa1, 0xc6, 0x8d, 0x83, 0xa7, 0xb8, 0x81, 0xe0, 0x1b,
+             0x9a, 0x96, 0x6c, 0x3c, 0x0b, 0xf2, 0x7f, 0x68, 0x60, 0x6a, 0x8b,
+             0x71, 0xd4, 0x57, 0xbd, 0x01, 0x6d, 0x4c, 0x41, 0xdd, 0x8a, 0x38,
+             0x0c, 0x70, 0x9a, 0x29, 0x6c, 0xb4, 0xc6, 0x54, 0x47, 0x92, 0x92,
+             0x0f, 0xd7, 0x88, 0x83, 0x57, 0x71, 0xa0, 0x7d, 0x4a, 0x16, 0xfb,
+             0x52, 0xed, 0x48, 0x05, 0x03, 0x31, 0xdc, 0x4c, 0x8b})),
+    std::make_pair(
+        72,
+        std::vector<uint8_t>(
+            {0xdf, 0x18, 0x6c, 0x2d, 0xc0, 0x9c, 0xaa, 0x48, 0xe1, 0x4e, 0x94,
+             0x2f, 0x75, 0xde, 0x5a, 0xc1, 0xb7, 0xa2, 0x1e, 0x4f, 0x9f, 0x07,
+             0x2a, 0x5b, 0x37, 0x1e, 0x09, 0xe0, 0x73, 0x45, 0xb0, 0x74, 0x0c,
+             0x76, 0x17, 0x7b, 0x01, 0x27, 0x88, 0x08, 0xfe, 0xc0, 0x25, 0xed,
+             0xed, 0x98, 0x22, 0xc1, 0x22, 0xaf, 0xd1, 0xc6, 0x3e, 0x6f, 0x0c,
+             0xe2, 0xe3, 0x26, 0x31, 0x04, 0x10, 0x63, 0x14, 0x5c})),
+    std::make_pair(
+        73,
+        std::vector<uint8_t>(
+            {0x87, 0x47, 0x56, 0x40, 0x96, 0x6a, 0x9f, 0xdc, 0xd6, 0xd3, 0xa3,
+             0xb5, 0xa2, 0xcc, 0xa5, 0xc0, 0x8f, 0x0d, 0x88, 0x2b, 0x10, 0x24,
+             0x3c, 0x0e, 0xc1, 0xbf, 0x3c, 0x6b, 0x1c, 0x37, 0xf2, 0xcd, 0x32,
+             0x12, 0xf1, 0x9a, 0x05, 0x78, 0x64, 0x47, 0x7d, 0x5e, 0xaf, 0x8f,
+             0xae, 0xd7, 0x3f, 0x29, 0x37, 0xc7, 0x68, 0xa0, 0xaf, 0x41, 0x5e,
+             0x84, 0xbb, 0xce, 0x6b, 0xd7, 0xde, 0x23, 0xb6, 0x60})),
+    std::make_pair(
+        74,
+        std::vector<uint8_t>(
+            {0xc3, 0xb5, 0x73, 0xbb, 0xe1, 0x09, 0x49, 0xa0, 0xfb, 0xd4, 0xff,
+             0x88, 0x4c, 0x44, 0x6f, 0x22, 0x29, 0xb7, 0x69, 0x02, 0xf9, 0xdf,
+             0xdb, 0xb8, 0xa0, 0x35, 0x3d, 0xa5, 0xc8, 0x3c, 0xa1, 0x4e, 0x81,
+             0x51, 0xbb, 0xaa, 0xc8, 0x2f, 0xd1, 0x57, 0x6a, 0x00, 0x9a, 0xdc,
+             0x6f, 0x19, 0x35, 0xcf, 0x26, 0xed, 0xd4, 0xf1, 0xfb, 0x8d, 0xa4,
+             0x83, 0xe6, 0xc5, 0xcd, 0x9d, 0x89, 0x23, 0xad, 0xc3})),
+    std::make_pair(
+        75,
+        std::vector<uint8_t>(
+            {0xb0, 0x9d, 0x8d, 0x0b, 0xba, 0x8a, 0x72, 0x86, 0xe4, 0x35, 0x68,
+