Merge mozilla-central to inbound. a=merge CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 10 May 2018 12:52:31 +0300
changeset 417709 27d3c10daf7e13028054a40514c476733f413ea6
parent 417708 b25f32e267b85bf2501a3ca97bb05faa8348e627 (current diff)
parent 417640 b52b2eb81d1e52d259d55d948281c7f6ddf1270c (diff)
child 417710 193e46b398bf45521768bf11fffddbb854320eeb
push id33977
push userncsoregi@mozilla.com
push dateThu, 10 May 2018 16:43:24 +0000
treeherdermozilla-central@17db33b6a124 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. a=merge CLOSED TREE
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
taskcluster/ci/test/test-platforms.yml
taskcluster/taskgraph/transforms/tests.py
testing/marionette/harness/marionette_harness/www/beforeunload.html
testing/web-platform/meta/MANIFEST.json
toolkit/components/places/nsIBrowserHistory.idl
xpcom/ds/nsGkAtomList.h
--- a/.arcconfig
+++ b/.arcconfig
@@ -1,4 +1,5 @@
 {
   "phabricator.uri" : "https://phabricator.services.mozilla.com/",
-  "repository.callsign": "MOZILLACENTRAL"
+  "repository.callsign": "MOZILLACENTRAL",
+  "history.immutable": false
 }
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -697,18 +697,17 @@ TextAttrsMgr::AutoGeneratedTextAttr::
 // TextDecorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::TextDecorValue::
   TextDecorValue(nsIFrame* aFrame)
 {
   const nsStyleTextReset* textReset = aFrame->StyleTextReset();
   mStyle = textReset->mTextDecorationStyle;
-  mColor = aFrame->StyleColor()->
-    CalcComplexColor(textReset->mTextDecorationColor);
+  mColor = textReset->mTextDecorationColor.CalcColor(aFrame);
   mLine = textReset->mTextDecorationLine &
     (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE |
      NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
 }
 
 TextAttrsMgr::TextDecorTextAttr::
   TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
   TTextAttr<TextDecorValue>(!aFrame)
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1301,21 +1301,16 @@ pref("pdfjs.disabled", false);
 // Used by pdf.js to know the first time firefox is run with it installed so it
 // can become the default pdf viewer.
 pref("pdfjs.firstRun", true);
 // The values of preferredAction and alwaysAskBeforeHandling before pdf.js
 // became the default.
 pref("pdfjs.previousHandler.preferredAction", 0);
 pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
 
-// The maximum amount of decoded image data we'll willingly keep around (we
-// might keep around more than this, but we'll try to get down to this value).
-// (This is intentionally on the high side; see bug 746055.)
-pref("image.mem.max_decoded_image_kb", 256000);
-
 // Is the sidebar positioned ahead of the content browser
 pref("sidebar.position_start", true);
 
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
 // Show degraded UI for http pages with password fields.
 pref("security.insecure_password.ui.enabled", true);
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -355,17 +355,19 @@ class BasePopup {
     // Panels inherit the applied theme (light, dark, etc) and there is a high
     // likelihood that most extension authors will not have tested with a dark theme.
     // If they have not set a background-color, we force it to white to ensure visibility
     // of the extension content. Passing `null` should be treated the same as no argument,
     // which is why we can't use default parameters here.
     if (!background) {
       background = "#fff";
     }
-    this.panel.style.setProperty("--arrowpanel-background", background);
+    if (this.panel.id != "widget-overflow") {
+      this.panel.style.setProperty("--arrowpanel-background", background);
+    }
     if (background == "#fff") {
       // Set a usable default color that work with the default background-color.
       this.panel.style.setProperty("--arrowpanel-border-color", "hsla(210,4%,10%,.15)");
     }
     this.background = background;
   }
 }
 
--- a/browser/components/extensions/test/browser/browser_ext_popup_background.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_background.js
@@ -5,17 +5,30 @@
 
 async function testPanel(browser, standAlone, initial_background) {
   let panel = getPanelForNode(browser);
   let arrowContent = document.getAnonymousElementByAttribute(panel, "class", "panel-arrowcontent");
   let arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
 
   let checkArrow = (background = null) => {
     if (background == null || !standAlone) {
-      ok(!arrow.style.hasOwnProperty("fill"), "Arrow fill should be the default one");
+      if (standAlone) {
+        is(getComputedStyle(arrow).fill,
+           "rgb(255, 255, 255)", "Arrow fill should be set to #fff when no background is supplied and popup is standAlone");
+      } else {
+        let default_background =
+          getComputedStyle(document.documentElement).getPropertyValue("--arrowpanel-background");
+        // Need to apply the color to a node and get the computed value
+        // to resolve CSS named colors such as -moz-field.
+        let span = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+        span.style.color = default_background;
+        let default_background_computed = getComputedStyle(span).color;
+
+        is(getComputedStyle(arrow).fill, default_background_computed, "Arrow fill should be the default one");
+      }
       return;
     }
 
     is(getComputedStyle(arrowContent).backgroundColor, background, "Arrow content should have correct background");
     is(getComputedStyle(arrow).fill, background, "Arrow should have correct background");
   };
 
   function getBackground(browser) {
--- a/browser/components/preferences/blocklists.js
+++ b/browser/components/preferences/blocklists.js
@@ -7,31 +7,27 @@ const BASE_LIST_ID = "base";
 const CONTENT_LIST_ID = "content";
 const TRACK_SUFFIX = "-track-digest256";
 const TRACKING_TABLE_PREF = "urlclassifier.trackingTable";
 const LISTS_PREF_BRANCH = "browser.safebrowsing.provider.mozilla.lists.";
 
 var gBlocklistManager = {
   _type: "",
   _blockLists: [],
-  _bundle: null,
   _tree: null,
 
   _view: {
     _rowCount: 0,
     get rowCount() {
       return this._rowCount;
     },
     getCellText(row, column) {
       if (column.id == "listCol") {
         let list = gBlocklistManager._blockLists[row];
-        let desc = list.description ? list.description : "";
-        let text = gBlocklistManager._bundle.getFormattedString("mozNameTemplate",
-                                                                [list.name, desc]);
-        return text;
+        return list.name;
       }
       return "";
     },
 
     isSeparator(index) { return false; },
     isSorted() { return false; },
     isContainer(index) { return false; },
     setTree(tree) {},
@@ -57,17 +53,16 @@ var gBlocklistManager = {
     if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
       window.close();
     } else if (event.keyCode == KeyEvent.DOM_VK_RETURN) {
       gBlocklistManager.onApplyChanges();
     }
   },
 
   onLoad() {
-    this._bundle = document.getElementById("bundlePreferences");
     let params = window.arguments[0];
     this.init(params);
   },
 
   init(params) {
     if (this._type) {
       // reusing an open dialog, clear the old observer
       this.uninit();
@@ -114,53 +109,50 @@ var gBlocklistManager = {
       if (listmanager) {
         listmanager.forceUpdates(trackingTable);
       }
     }
 
     window.close();
   },
 
-  _loadBlockLists() {
+  async _loadBlockLists() {
     this._blockLists = [];
 
     // Load blocklists into a table.
     let branch = Services.prefs.getBranch(LISTS_PREF_BRANCH);
     let itemArray = branch.getChildList("");
     for (let itemName of itemArray) {
       try {
-        this._createOrUpdateBlockList(itemName);
+        let list = await this._createBlockList(itemName);
+        this._blockLists.push(list);
       } catch (e) {
         // Ignore bogus or missing list name.
         continue;
       }
     }
 
     this._updateTree();
   },
 
-  _createOrUpdateBlockList(itemName) {
+  async _createBlockList(id) {
     let branch = Services.prefs.getBranch(LISTS_PREF_BRANCH);
-    let key = branch.getCharPref(itemName);
-    let value = this._bundle.getString(key);
+    let l10nKey = branch.getCharPref(id);
+    let [listName, description] = await document.l10n.formatValues([
+      [`blocklist-item-${l10nKey}-name`],
+      [`blocklist-item-${l10nKey}-desc`],
+    ]);
+    let name = await document.l10n.formatValue(
+      "blocklist-item-list-template", {listName, description});
 
-    let suffix = itemName.slice(itemName.lastIndexOf("."));
-    let id = itemName.replace(suffix, "");
-    let list = this._blockLists.find(el => el.id === id);
-    if (!list) {
-      list = { id };
-      this._blockLists.push(list);
-    }
-    list.selected = this._getActiveList() === id;
-
-    // Get the property name from the suffix (e.g. ".name" -> "name").
-    let prop = suffix.slice(1);
-    list[prop] = value;
-
-    return list;
+    return {
+      id,
+      name,
+      selected: this._getActiveList() === id,
+    };
   },
 
   _updateTree() {
     this._tree = document.getElementById("blocklistsTree");
     this._view._rowCount = this._blockLists.length;
     this._tree.view = this._view;
   },
 
--- a/browser/components/preferences/blocklists.xul
+++ b/browser/components/preferences/blocklists.xul
@@ -19,19 +19,16 @@
 
   <link rel="localization" href="branding/brand.ftl"/>
   <link rel="localization" href="browser/preferences/blocklists.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://global/content/treeUtils.js"/>
   <script src="chrome://browser/content/preferences/blocklists.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-
   <keyset>
     <key data-l10n-id="blocklist-close-key" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="contentPane largeDialogContainer" flex="1">
     <description id="blocklistsText" data-l10n-id="blocklist-desc" control="url"/>
     <separator class="thin"/>
     <tree id="blocklistsTree" flex="1" style="height: 18em;"
--- a/browser/components/preferences/fonts.js
+++ b/browser/components/preferences/fonts.js
@@ -85,32 +85,34 @@ var gFontsDialog = {
     return preference.value == 1;
   },
 
   writeUseDocumentFonts() {
     var useDocumentFonts = document.getElementById("useDocumentFonts");
     return useDocumentFonts.checked ? 1 : 0;
   },
 
-  onBeforeAccept() {
-    // It would be good if we could avoid touching languages the pref pages won't use, but
-    // unfortunately the language group APIs (deducing language groups from language codes)
-    // are C++ - only. So we just check all the things the user touched:
-    // Don't care about anything up to 24px, or if this value is the same as set previously:
-    let preferences = Preferences.getAll().filter(pref => {
-      return pref.id.includes("font.minimum-size") && pref.value > 24 && pref.value != pref.valueFromPreferences;
-    });
-    if (!preferences.length) {
-      return true;
+  async confirmMinSizeChange() {
+    let menulist = document.getElementById("minSize");
+    let preference = menulist.getAttribute("preference");
+    let defaultValue = Preferences.get(preference).valueFromPreferences;
+    let oldValue = Preferences.get(preference).value;
+    let newValue = menulist.value;
+
+    if (newValue <= 24 || newValue == defaultValue) {
+      return;
     }
 
-    let strings = document.getElementById("bundlePreferences");
-    let title = strings.getString("veryLargeMinimumFontTitle");
-    let confirmLabel = strings.getString("acceptVeryLargeMinimumFont");
-    let warningMessage = strings.getString("veryLargeMinimumFontWarning");
+    let [title, warningMessage, confirmLabel] = await document.l10n.formatValues([
+      ["fonts-very-large-warning-title"],
+      ["fonts-very-large-warning-message"],
+      ["fonts-very-large-warning-accept"],
+    ]);
     let {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
     let flags = Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL |
                 Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING |
                 Services.prompt.BUTTON_POS_1_DEFAULT;
     let buttonChosen = Services.prompt.confirmEx(window, title, warningMessage, flags, confirmLabel, null, "", "", {});
-    return buttonChosen == 0;
+    if (buttonChosen != 0) {
+      menulist.value = oldValue;
+    }
   },
 };
--- a/browser/components/preferences/fonts.xul
+++ b/browser/components/preferences/fonts.xul
@@ -11,32 +11,30 @@
 <dialog id="FontsDialog" type="child" class="prefwindow"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         data-l10n-id="fonts-window"
         data-l10n-attrs="title"
         buttons="accept,cancel,help"
         persist="lastSelected screenX screenY"
         role="dialog"
         helpTopic="prefs-fonts-and-colors"
-        ondialoghelp="openPrefsHelp()"
-        onbeforeaccept="return gFontsDialog.onBeforeAccept();">
+        ondialoghelp="openPrefsHelp()">
 
   <link rel="localization" href="browser/preferences/fonts.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
 
   <keyset>
     <key data-l10n-id="fonts-window-close" modifiers="accel" oncommand="Preferences.close(event)"/>
   </keyset>
 
   <vbox id="FontsDialogPane" class="prefpane largeDialogContainer">
 
-    <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
     <script type="application/javascript" src="chrome://mozapps/content/preferences/fontbuilder.js"/>
     <script type="application/javascript" src="chrome://browser/content/preferences/fonts.js"/>
 
     <!-- Fonts for: [ Language ] -->
     <groupbox>
       <caption>
         <hbox align="center">
           <label data-l10n-id="fonts-langgroup-header" control="selectLangs"/>
@@ -209,17 +207,17 @@
       </grid>
       <separator class="thin"/>
       <hbox flex="1">
         <spacer flex="1"/>
         <hbox align="center" pack="end">
           <label data-l10n-id="fonts-minsize" control="minSize"/>
           <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
           <hbox>
-            <menulist id="minSize">
+            <menulist id="minSize" oncommand="gFontsDialog.confirmMinSizeChange();">
               <menupopup>
                 <menuitem value="0" data-l10n-id="fonts-minsize-none"/>
                 <menuitem value="9" label="9"/>
                 <menuitem value="10" label="10"/>
                 <menuitem value="11" label="11"/>
                 <menuitem value="12" label="12"/>
                 <menuitem value="13" label="13"/>
                 <menuitem value="14" label="14"/>
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -35,23 +35,24 @@
       xmlns:html="http://www.w3.org/1999/xhtml"
       disablefastfind="true"
       data-l10n-id="pref-page"
       data-l10n-attrs="title">
 
   <link rel="localization" href="branding/brand.ftl"/>
   <link rel="localization" href="browser/branding/sync-brand.ftl"/>
   <link rel="localization" href="browser/preferences/preferences.ftl"/>
+  <!-- Used by fontbuilder.js -->
+  <link rel="localization" href="browser/preferences/fonts.ftl"/>
 
   <!-- Links below are only used for search-l10n-ids into subdialogs -->
   <link rel="localization" href="browser/preferences/blocklists.ftl"/>
   <link rel="localization" href="browser/preferences/clearSiteData.ftl"/>
   <link rel="localization" href="browser/preferences/colors.ftl"/>
   <link rel="localization" href="browser/preferences/connection.ftl"/>
-  <link rel="localization" href="browser/preferences/fonts.ftl"/>
   <link rel="localization" href="browser/preferences/languages.ftl"/>
   <link rel="localization" href="browser/preferences/permissions.ftl"/>
   <link rel="localization" href="browser/preferences/selectBookmark.ftl"/>
   <link rel="localization" href="browser/preferences/siteDataSettings.ftl"/>
 
   <script type="text/javascript" src="chrome://global/content/l10n.js"></script>
 
   <html:link rel="shortcut icon"
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -317,18 +317,16 @@ var gPrivacyPane = {
       gPrivacyPane.showCameraExceptions);
     setEventListener("microphoneSettingsButton", "command",
       gPrivacyPane.showMicrophoneExceptions);
     setEventListener("popupPolicyButton", "command",
       gPrivacyPane.showPopupExceptions);
     setEventListener("notificationsDoNotDisturb", "command",
       gPrivacyPane.toggleDoNotDisturbNotifications);
 
-    let bundlePrefs = document.getElementById("bundlePreferences");
-
     if (AlertsServiceDND) {
       let notificationsDoNotDisturbBox =
         document.getElementById("notificationsDoNotDisturbBox");
       notificationsDoNotDisturbBox.removeAttribute("hidden");
       let checkbox = document.getElementById("notificationsDoNotDisturb");
       document.l10n.setAttributes(checkbox, "permissions-notification-pause");
       if (AlertsServiceDND.manualDoNotDisturb) {
         let notificationsDoNotDisturb =
@@ -387,20 +385,16 @@ var gPrivacyPane = {
     let signonBundle = document.getElementById("signonBundle");
     let pkiBundle = document.getElementById("pkiBundle");
     appendSearchKeywords("showPasswords", [
       signonBundle.getString("loginsDescriptionAll2"),
     ]);
     appendSearchKeywords("viewSecurityDevicesButton", [
       pkiBundle.getString("enable_fips"),
     ]);
-    appendSearchKeywords("siteDataSettings", [
-      bundlePrefs.getString("siteDataSettings3.description"),
-      bundlePrefs.getString("removeAllSiteData.label"),
-    ]);
 
     if (!PrivateBrowsingUtils.enabled) {
       document.getElementById("privateBrowsingAutoStart").hidden = true;
       document.querySelector("menuitem[value='dontremember']").hidden = true;
     }
 
     // Notify observers that the UI is now ready
     Services.obs.notifyObservers(window, "privacy-pane-loaded");
@@ -881,27 +875,28 @@ var gPrivacyPane = {
     let clearButton = document.getElementById("clearSiteDataButton");
     let settingsButton = document.getElementById("siteDataSettings");
     clearButton.disabled = !shouldShow;
     settingsButton.disabled = !shouldShow;
   },
 
   showSiteDataLoading() {
     let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
-    let prefStrBundle = document.getElementById("bundlePreferences");
-    totalSiteDataSizeLabel.textContent = prefStrBundle.getString("loadingSiteDataSize1");
+    document.l10n.setAttributes(totalSiteDataSizeLabel, "sitedata-total-size-calculating");
   },
 
   updateTotalDataSizeLabel(siteDataUsage) {
     SiteDataManager.getCacheSize().then(function(cacheUsage) {
-      let prefStrBundle = document.getElementById("bundlePreferences");
       let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
       let totalUsage = siteDataUsage + cacheUsage;
-      let size = DownloadUtils.convertByteUnits(totalUsage);
-      totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize2", size);
+      let [value, unit] = DownloadUtils.convertByteUnits(totalUsage);
+      document.l10n.setAttributes(totalSiteDataSizeLabel, "sitedata-total-size", {
+        value,
+        unit
+      });
     });
   },
 
   clearSiteData() {
     gSubDialog.open("chrome://browser/content/preferences/clearSiteData.xul");
   },
 
   // GEOLOCATION
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -235,16 +235,18 @@
         <button id="siteDataSettings"
                 class="accessory-button"
                 data-l10n-id="sitedata-settings"
                 search-l10n-ids="
                   site-data-settings-window.title,
                   site-data-column-host.label,
                   site-data-column-cookies.label,
                   site-data-column-storage.label,
+                  site-data-settings-description,
+                  site-data-remove-all.label,
                 "/>
       </hbox>
       <hbox>
         <button id="cookieExceptions"
                 class="accessory-button"
                 data-l10n-id="sitedata-cookies-exceptions"
                 preference="pref.privacy.disable_button.cookie_exceptions"
                 search-l10n-ids="
--- a/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
+++ b/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
@@ -14,29 +14,32 @@ var sitePermissionsDialog;
 
 function checkPermissionItem(origin, state) {
   let doc = sitePermissionsDialog.document;
 
   let label = doc.getElementsByTagName("label")[0];
   Assert.equal(label.value, origin);
 
   let menulist = doc.getElementsByTagName("menulist")[0];
-  Assert.equal(menulist.label, state);
+  let selectedIndex = menulist.selectedIndex;
+  let selectedItem = menulist.querySelectorAll("menuitem")[selectedIndex];
+  Assert.equal(selectedItem.value, state);
 }
 
 async function openPermissionsDialog() {
   let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
 
   await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     let doc = content.document;
     let settingsButton = doc.getElementById("notificationSettingsButton");
     settingsButton.click();
   });
 
   sitePermissionsDialog = await dialogOpened;
+  await sitePermissionsDialog.document.mozSubdialogReady;
 }
 
 add_task(async function openSitePermissionsDialog() {
   await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
   await openPermissionsDialog();
 });
 
 add_task(async function addPermission() {
@@ -47,28 +50,28 @@ add_task(async function addPermission() 
   Assert.equal(richlistbox.itemCount, 0,
                "Number of permission items is 0 initially");
 
   // Add notification permission for a website.
   SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
 
   // Observe the added permission changes in the dialog UI.
   Assert.equal(richlistbox.itemCount, 1);
-  checkPermissionItem(URL, "Allow");
+  checkPermissionItem(URL, Services.perms.ALLOW_ACTION);
 
   SitePermissions.remove(URL, "desktop-notification");
 });
 
 add_task(async function observePermissionChange() {
   SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
 
   // Change the permission.
   SitePermissions.set(URI, "desktop-notification", SitePermissions.BLOCK);
 
-  checkPermissionItem(URL, "Block");
+  checkPermissionItem(URL, Services.perms.DENY_ACTION);
 
   SitePermissions.remove(URL, "desktop-notification");
 });
 
 add_task(async function observePermissionDelete() {
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
--- a/browser/components/preferences/in-content/tests/siteData/browser_siteData.js
+++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData.js
@@ -54,50 +54,50 @@ add_task(async function() {
 
 // Test buttons are disabled and loading message shown while updating sites
 add_task(async function() {
   let updatedPromise = promiseSiteDataManagerSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   await updatedPromise;
   let cacheSize = await SiteDataManager.getCacheSize();
 
-  let actual = null;
-  let expected = null;
   let doc = gBrowser.selectedBrowser.contentDocument;
   let clearBtn = doc.getElementById("clearSiteDataButton");
   let settingsButton = doc.getElementById("siteDataSettings");
-  let prefStrBundle = doc.getElementById("bundlePreferences");
   let totalSiteDataSizeLabel = doc.getElementById("totalSiteDataSize");
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
   await SiteDataManager.getTotalUsage()
                        .then(usage => {
-                         actual = totalSiteDataSizeLabel.textContent;
-                         expected = prefStrBundle.getFormattedString(
-                           "totalSiteDataSize2", DownloadUtils.convertByteUnits(usage + cacheSize));
-                          is(actual, expected, "Should show the right total site data size");
+                         let [value, unit] = DownloadUtils.convertByteUnits(usage + cacheSize);
+                         Assert.deepEqual(doc.l10n.getAttributes(totalSiteDataSizeLabel), {
+                           id: "sitedata-total-size",
+                           args: {value, unit}
+                         }, "Should show the right total site data size");
                        });
 
   Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
   is(clearBtn.disabled, true, "Should disable clear button while updating sites");
   is(settingsButton.disabled, true, "Should disable settings button while updating sites");
-  actual = totalSiteDataSizeLabel.textContent;
-  expected = prefStrBundle.getString("loadingSiteDataSize1");
-  is(actual, expected, "Should show the loading message while updating");
+  Assert.deepEqual(doc.l10n.getAttributes(totalSiteDataSizeLabel), {
+    id: "sitedata-total-size-calculating",
+    args: null
+  }, "Should show the loading message while updating");
 
   Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
   cacheSize = await SiteDataManager.getCacheSize();
   await SiteDataManager.getTotalUsage()
                        .then(usage => {
-                         actual = totalSiteDataSizeLabel.textContent;
-                         expected = prefStrBundle.getFormattedString(
-                           "totalSiteDataSize2", DownloadUtils.convertByteUnits(usage + cacheSize));
-                          is(actual, expected, "Should show the right total site data size");
+                         let [value, unit] = DownloadUtils.convertByteUnits(usage + cacheSize);
+                         Assert.deepEqual(doc.l10n.getAttributes(totalSiteDataSizeLabel), {
+                           id: "sitedata-total-size",
+                           args: {value, unit}
+                         }, "Should show the right total site data size");
                        });
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 // Test clearing service wroker through the settings panel
 add_task(async function() {
   // Register a test service worker
--- a/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js
+++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js
@@ -86,20 +86,21 @@ add_task(async function() {
 
   let columns = siteItems[0].querySelectorAll(".item-box > label");
 
   let expected = "account.xyz.com";
   is(columns[0].value, expected, "Should group and list sites by host");
 
   is(columns[1].value, "5", "Should group cookies across scheme, port and origin attributes");
 
-  let prefStrBundle = frameDoc.getElementById("bundlePreferences");
-  expected = prefStrBundle.getFormattedString("siteUsagePersistent",
-    DownloadUtils.convertByteUnits(quotaUsage * mockSiteDataManager.fakeSites.length));
-  is(columns[2].value, expected, "Should sum up usages across scheme, port, origin attributes and persistent status");
+  let [value, unit] = DownloadUtils.convertByteUnits(quotaUsage * mockSiteDataManager.fakeSites.length);
+  Assert.deepEqual(frameDoc.l10n.getAttributes(columns[2]), {
+    id: "site-usage-persistent",
+    args: { value, unit }
+  }, "Should sum up usages across scheme, port, origin attributes and persistent status");
 
   await mockSiteDataManager.unregister();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 // Test sorting
 add_task(async function() {
   mockSiteDataManager.register(SiteDataManager, [
--- a/browser/components/preferences/languages.js
+++ b/browser/components/preferences/languages.js
@@ -46,21 +46,20 @@ var gLanguagesDialog = {
 
   _loadAvailableLanguages() {
     // This is a parser for: resource://gre/res/language.properties
     // The file is formatted like so:
     // ab[-cd].accept=true|false
     //  ab = language
     //  cd = region
     var bundleAccepted    = document.getElementById("bundleAccepted");
-    var bundlePreferences = document.getElementById("bundlePreferences");
 
-    function LanguageInfo(aName, aABCD, aIsVisible) {
-      this.name = aName;
-      this.abcd = aABCD;
+    function LocaleInfo(aLocaleName, aLocaleCode, aIsVisible) {
+      this.name = aLocaleName;
+      this.code = aLocaleCode;
       this.isVisible = aIsVisible;
     }
 
     // 1) Read the available languages out of language.properties
     var strings = bundleAccepted.strings;
 
     let localeCodes = [];
     let localeValues = [];
@@ -77,68 +76,87 @@ var gLanguagesDialog = {
     }
 
     let localeNames = Services.intl.getLocaleDisplayNames(undefined, localeCodes);
 
     for (let i in localeCodes) {
       let isVisible = localeValues[i] == "true" &&
         (!(localeCodes[i] in this._acceptLanguages) || !this._acceptLanguages[localeCodes[i]]);
 
-      let name = bundlePreferences.getFormattedString("languageCodeFormat",
-        [localeNames[i], localeCodes[i]]);
-      let li = new LanguageInfo(name, localeCodes[i], isVisible);
+      let li = new LocaleInfo(localeNames[i], localeCodes[i], isVisible);
       this._availableLanguagesList.push(li);
     }
 
     this._buildAvailableLanguageList();
   },
 
-  _buildAvailableLanguageList() {
+  async _buildAvailableLanguageList() {
     var availableLanguagesPopup = document.getElementById("availableLanguagesPopup");
     while (availableLanguagesPopup.hasChildNodes())
       availableLanguagesPopup.firstChild.remove();
 
-    // Sort the list of languages by name
-    this._availableLanguagesList.sort(function(a, b) {
-                                        return a.name.localeCompare(b.name);
-                                      });
+    let frag = document.createDocumentFragment();
 
     // Load the UI with the data
     for (var i = 0; i < this._availableLanguagesList.length; ++i) {
-      var abCD = this._availableLanguagesList[i].abcd;
-      if (this._availableLanguagesList[i].isVisible &&
-          (!(abCD in this._acceptLanguages) || !this._acceptLanguages[abCD])) {
+      let locale = this._availableLanguagesList[i];
+      let localeCode = locale.code;
+      if (locale.isVisible &&
+          (!(localeCode in this._acceptLanguages) || !this._acceptLanguages[localeCode])) {
         var menuitem = document.createElement("menuitem");
-        menuitem.id = this._availableLanguagesList[i].abcd;
-        availableLanguagesPopup.appendChild(menuitem);
-        menuitem.setAttribute("label", this._availableLanguagesList[i].name);
+        menuitem.id = localeCode;
+        document.l10n.setAttributes(menuitem, "languages-code-format", {
+          locale: locale.name,
+          code: localeCode,
+        });
+        frag.appendChild(menuitem);
       }
     }
+
+    await document.l10n.translateFragment(frag);
+
+    // Sort the list of languages by name
+    let comp = new Services.intl.Collator(undefined, {
+      usage: "sort"
+    });
+
+    let items = Array.from(frag.children);
+
+    items.sort((a, b) => {
+      return comp.compare(a.getAttribute("label"), b.getAttribute("label"));
+    });
+
+    // Re-append items in the correct order:
+    items.forEach(item => frag.appendChild(item));
+
+    availableLanguagesPopup.appendChild(frag);
+
     this._availableLanguages.setAttribute("label", this._availableLanguages.getAttribute("placeholder"));
   },
 
   readAcceptLanguages() {
     while (this._activeLanguages.hasChildNodes())
       this._activeLanguages.firstChild.remove();
 
     var selectedIndex = 0;
     var preference = Preferences.get("intl.accept_languages");
     if (preference.value == "")
       return undefined;
     var languages = preference.value.toLowerCase().split(/\s*,\s*/);
     for (var i = 0; i < languages.length; ++i) {
-      var name = this._getLanguageName(languages[i]);
-      if (!name)
-        name = "[" + languages[i] + "]";
       var listitem = document.createElement("listitem");
       listitem.id = languages[i];
       if (languages[i] == this._selectedItemID)
         selectedIndex = i;
       this._activeLanguages.appendChild(listitem);
-      listitem.setAttribute("label", name);
+      var localeName = this._getLocaleName(languages[i]);
+      document.l10n.setAttributes(listitem, "languages-code-format", {
+        locale: localeName,
+        code: languages[i],
+      });
 
       // Hash this language as an "Active" language so we don't
       // show it in the list that can be added.
       this._acceptLanguages[languages[i]] = true;
     }
 
     if (this._activeLanguages.childNodes.length > 0) {
       this._activeLanguages.ensureIndexIsVisible(selectedIndex);
@@ -212,21 +230,21 @@ var gLanguagesDialog = {
 
     // Update the preference and force a UI rebuild
     var preference = Preferences.get("intl.accept_languages");
     preference.value = string;
 
     this._buildAvailableLanguageList();
   },
 
-  _getLanguageName(aABCD) {
+  _getLocaleName(localeCode) {
     if (!this._availableLanguagesList.length)
       this._loadAvailableLanguages();
     for (var i = 0; i < this._availableLanguagesList.length; ++i) {
-      if (aABCD == this._availableLanguagesList[i].abcd)
+      if (localeCode == this._availableLanguagesList[i].code)
         return this._availableLanguagesList[i].name;
     }
     return "";
   },
 
   moveUp() {
     var selectedItem = this._activeLanguages.selectedItems[0];
     var previousItem = selectedItem.previousSibling;
--- a/browser/components/preferences/languages.xul
+++ b/browser/components/preferences/languages.xul
@@ -28,17 +28,16 @@
 
   <keyset>
     <key data-l10n-id="languages-close-key" modifiers="accel" oncommand="Preferences.close(event)"/>
   </keyset>
 
   <vbox id="LanguagesDialogPane" class="prefpane largeDialogContainer">
 
     <stringbundleset id="languageSet">
-      <stringbundle id="bundlePreferences"  src="chrome://browser/locale/preferences/preferences.properties"/>
       <stringbundle id="bundleAccepted"     src="resource://gre/res/language.properties"/>
     </stringbundleset>
 
     <description data-l10n-id="languages-description"/>
     <checkbox id="spoofEnglish"
               data-l10n-id="languages-customize-spoof-english"
               preference="privacy.spoof_english"
               onsyncfrompreference="return gLanguagesDialog.readSpoofEnglish();"
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -125,17 +125,17 @@ var gPermissionManager = {
         principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
         // If we have ended up with an unknown scheme, the following will throw.
         principal.origin;
       }
     } catch (ex) {
       document.l10n.formatValues([
         ["permissions-invalid-uri-title"],
         ["permissions-invalid-uri-label"]
-      ]).then(([message, title]) => {
+      ]).then(([title, message]) => {
         Services.prompt.alert(window, title, message);
       });
       return;
     }
 
     var capabilityString = this._getCapabilityString(aCapability);
 
     // check whether the permission already exists, if not, add it
--- a/browser/components/preferences/siteDataRemoveSelected.js
+++ b/browser/components/preferences/siteDataRemoveSelected.js
@@ -3,21 +3,16 @@
  * 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";
 
 let gSiteDataRemoveSelected = {
 
   init() {
-    let bundlePreferences = document.getElementById("bundlePreferences");
-    let acceptBtn = document.getElementById("SiteDataRemoveSelectedDialog")
-                            .getButton("accept");
-    acceptBtn.label = bundlePreferences.getString("acceptRemove");
-
     let hosts = window.arguments[0].hosts;
     hosts.sort();
     let list = document.getElementById("removalList");
     let fragment = document.createDocumentFragment();
     for (let host of hosts) {
       let listItem = document.createElement("listitem");
       listItem.setAttribute("label", host);
       fragment.appendChild(listItem);
--- a/browser/components/preferences/siteDataRemoveSelected.xul
+++ b/browser/components/preferences/siteDataRemoveSelected.xul
@@ -6,31 +6,28 @@
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/preferences/siteDataSettings.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/in-content/siteDataSettings.css" type="text/css"?>
 
 <dialog id="SiteDataRemoveSelectedDialog"
         windowtype="Browser:SiteDataRemoveSelected"
         width="500"
-        data-l10n-id="site-data-removing-window"
-        data-l10n-attrs="title"
+        data-l10n-id="site-data-removing-dialog"
+        data-l10n-attrs="title, buttonlabelaccept"
         onload="gSiteDataRemoveSelected.init();"
         ondialogaccept="gSiteDataRemoveSelected.ondialogaccept(); return true;"
         ondialogcancel="gSiteDataRemoveSelected.ondialogcancel(); return true;"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <link rel="localization" href="browser/preferences/siteDataSettings.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://browser/content/preferences/siteDataRemoveSelected.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-
   <vbox id="contentContainer">
     <hbox flex="1">
       <vbox>
         <image class="question-icon"/>
       </vbox>
       <vbox flex="1">
         <!-- Only show this label on OS X because of no dialog title -->
         <label id="removing-label"
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -19,57 +19,63 @@ let gSiteDataSettings = {
   // - baseDomain: base domain of the site
   // - cookies: array of cookies of that site
   // - usage: disk usage which site uses
   // - userAction: "remove" or "update-permission"; the action user wants to take.
   _sites: null,
 
   _list: null,
   _searchBox: null,
-  _prefStrBundle: null,
 
   _createSiteListItem(site) {
     let item = document.createElement("richlistitem");
     item.setAttribute("host", site.host);
     let container = document.createElement("hbox");
 
     // Creates a new column item with the specified relative width.
-    function addColumnItem(value, flexWidth) {
+    function addColumnItem(l10n, flexWidth) {
       let box = document.createElement("hbox");
       box.className = "item-box";
       box.setAttribute("flex", flexWidth);
       let label = document.createElement("label");
       label.setAttribute("crop", "end");
-      if (value) {
-        box.setAttribute("tooltiptext", value);
-        label.setAttribute("value", value);
+      if (l10n) {
+        if (l10n.raw) {
+          box.setAttribute("tooltiptext", l10n.raw);
+          label.setAttribute("value", l10n.raw);
+        } else {
+          document.l10n.setAttributes(label, l10n.id, l10n.args);
+        }
       }
       box.appendChild(label);
       container.appendChild(box);
     }
 
     // Add "Host" column.
-    addColumnItem(site.host, "4");
+    addColumnItem({raw: site.host}, "4");
 
     // Add "Cookies" column.
-    addColumnItem(site.cookies.length, "1");
+    addColumnItem({raw: site.cookies.length}, "1");
 
     // Add "Storage" column
     if (site.usage > 0 || site.persisted) {
-      let size = DownloadUtils.convertByteUnits(site.usage);
-      let strName = site.persisted ? "siteUsagePersistent" : "siteUsage";
-      addColumnItem(this._prefStrBundle.getFormattedString(strName, size), "2");
+      let [value, unit] = DownloadUtils.convertByteUnits(site.usage);
+      let strName = site.persisted ? "site-usage-persistent" : "site-usage-pattern";
+      addColumnItem({
+        id: strName,
+        args: { value, unit }
+      }, "2");
     } else {
       // Pass null to avoid showing "0KB" when there is no site data stored.
       addColumnItem(null, "2");
     }
 
     // Add "Last Used" column.
     addColumnItem(site.lastAccessed > 0 ?
-      this._formatter.format(site.lastAccessed) : null, "2");
+      {raw: this._formatter.format(site.lastAccessed)} : null, "2");
 
     item.appendChild(container);
     return item;
   },
 
   init() {
     function setEventListener(id, eventType, callback) {
       document.getElementById(id)
@@ -77,29 +83,24 @@ let gSiteDataSettings = {
     }
 
     this._formatter = new Services.intl.DateTimeFormat(undefined, {
       dateStyle: "short", timeStyle: "short",
     });
 
     this._list = document.getElementById("sitesList");
     this._searchBox = document.getElementById("searchBox");
-    this._prefStrBundle = document.getElementById("bundlePreferences");
     SiteDataManager.getSites().then(sites => {
       this._sites = sites;
       let sortCol = document.querySelector("treecol[data-isCurrentSortCol=true]");
       this._sortSites(this._sites, sortCol);
       this._buildSitesList(this._sites);
       Services.obs.notifyObservers(null, "sitedata-settings-init");
     });
 
-    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
-    let settingsDescription = document.getElementById("settingsDescription");
-    settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings3.description", [brandShortName]);
-
     setEventListener("sitesList", "select", this.onSelect);
     setEventListener("hostCol", "click", this.onClickTreeCol);
     setEventListener("usageCol", "click", this.onClickTreeCol);
     setEventListener("lastAccessedCol", "click", this.onClickTreeCol);
     setEventListener("cookiesCol", "click", this.onClickTreeCol);
     setEventListener("cancel", "command", this.close);
     setEventListener("save", "command", this.saveChanges);
     setEventListener("searchBox", "command", this.onCommandSearch);
@@ -109,24 +110,18 @@ let gSiteDataSettings = {
 
   _updateButtonsState() {
     let items = this._list.getElementsByTagName("richlistitem");
     let removeSelectedBtn = document.getElementById("removeSelected");
     let removeAllBtn = document.getElementById("removeAll");
     removeSelectedBtn.disabled = this._list.selectedItems.length == 0;
     removeAllBtn.disabled = items.length == 0;
 
-    let removeAllBtnLabelStringID = "removeAllSiteData.label";
-    let removeAllBtnAccesskeyStringID = "removeAllSiteData.accesskey";
-    if (this._searchBox.value) {
-      removeAllBtnLabelStringID = "removeAllSiteDataShown.label";
-      removeAllBtnAccesskeyStringID = "removeAllSiteDataShown.accesskey";
-    }
-    removeAllBtn.setAttribute("label", this._prefStrBundle.getString(removeAllBtnLabelStringID));
-    removeAllBtn.setAttribute("accesskey", this._prefStrBundle.getString(removeAllBtnAccesskeyStringID));
+    let l10nId = this._searchBox.value ? "site-data-remove-shown" : "site-data-remove-all";
+    document.l10n.setAttributes(removeAllBtn, l10nId);
   },
 
   /**
    * @param sites {Array}
    * @param col {XULElement} the <treecol> being sorted on
    */
   _sortSites(sites, col) {
     let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol");
--- a/browser/components/preferences/siteDataSettings.xul
+++ b/browser/components/preferences/siteDataSettings.xul
@@ -14,27 +14,24 @@
         data-l10n-attrs="title"
         class="windowDialog"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         style="width: 45em;"
         onload="gSiteDataSettings.init();"
         onkeypress="gSiteDataSettings.onKeyPress(event);"
         persist="screenX screenY width height">
 
+  <link rel="localization" href="branding/brand.ftl"/>
   <link rel="localization" href="browser/preferences/siteDataSettings.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://browser/content/preferences/siteDataSettings.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-  <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
-
   <vbox flex="1">
-    <description id="settingsDescription"></description>
+    <description id="settingsDescription" data-l10n-id="site-data-settings-description"/>
     <separator class="thin"/>
 
     <hbox id="searchBoxContainer">
       <textbox id="searchBox" type="search" flex="1"
         data-l10n-id="site-data-search-textbox"/>
     </hbox>
     <separator class="thin"/>
 
--- a/browser/components/preferences/sitePermissions.js
+++ b/browser/components/preferences/sitePermissions.js
@@ -28,34 +28,33 @@ const sitePermissionsL10n = {
   "microphone": {
     window: "permissions-site-microphone-window",
     description: "permissions-site-microphone-desc",
     disableLabel: "permissions-site-microphone-disable-label",
     disableDescription: "permissions-site-microphone-disable-desc",
   },
 };
 
-function Permission(principal, type, capability, capabilityString) {
+function Permission(principal, type, capability, l10nId) {
   this.principal = principal;
   this.origin = principal.origin;
   this.type = type;
   this.capability = capability;
-  this.capabilityString = capabilityString;
+  this.l10nId = l10nId;
 }
 
 const PERMISSION_STATES = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.PROMPT];
 
 var gSitePermissionsManager = {
   _type: "",
   _isObserving: false,
   _permissions: new Map(),
   _permissionsToChange: new Map(),
   _permissionsToDelete: new Map(),
   _list: null,
-  _bundle: null,
   _removeButton: null,
   _removeAllButton: null,
   _searchBox: null,
   _checkbox: null,
   _currentDefaultPermissionsState: null,
   _defaultPermissionStatePrefName: null,
 
   onLoad() {
@@ -64,17 +63,16 @@ var gSitePermissionsManager = {
   },
 
   async init(params) {
     if (!this._isObserving) {
       Services.obs.addObserver(this, "perm-changed");
       this._isObserving = true;
     }
 
-    this._bundle = document.getElementById("bundlePreferences");
     this._type = params.permissionType;
     this._list = document.getElementById("permissionsBox");
     this._removeButton = document.getElementById("removePermission");
     this._removeAllButton = document.getElementById("removeAllPermissions");
     this._searchBox = document.getElementById("searchBox");
     this._checkbox = document.getElementById("permissionsDisableCheckbox");
 
     let permissionsDisableDescription = document.getElementById("permissionsDisableDescription");
@@ -105,17 +103,17 @@ var gSitePermissionsManager = {
       permissionsDisableDescription.setAttribute("hidden", true);
     } else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
       this._checkbox.checked = true;
     } else {
       this._checkbox.checked = false;
     }
 
     this._loadPermissions();
-    this.buildPermissionsList();
+    await this.buildPermissionsList();
 
     this._searchBox.focus();
   },
 
   uninit() {
     if (this._isObserving) {
       Services.obs.removeObserver(this, "perm-changed");
       this._isObserving = false;
@@ -133,17 +131,17 @@ var gSitePermissionsManager = {
       return;
 
     if (data == "added") {
       this._addPermissionToList(permission);
       this.buildPermissionsList();
     } else if (data == "changed") {
       let p = this._permissions.get(permission.principal.origin);
       p.capability = permission.capability;
-      p.capabilityString = this._getCapabilityString(permission.capability);
+      p.l10nId = this._getCapabilityString(permission.capability);
       this._handleCapabilityChange(p);
       this.buildPermissionsList();
     } else if (data == "deleted") {
       this._removePermissionFromList(permission.principal.origin);
     }
   },
 
   _handleCapabilityChange(perm) {
@@ -152,35 +150,36 @@ var gSitePermissionsManager = {
     menulist.selectedItem =
       menulist.getElementsByAttribute("value", perm.capability)[0];
   },
 
   _getCapabilityString(capability) {
     let stringKey = null;
     switch (capability) {
     case Services.perms.ALLOW_ACTION:
-      stringKey = "can";
+      stringKey = "permissions-capabilities-allow";
       break;
     case Services.perms.DENY_ACTION:
-      stringKey = "cannot";
+      stringKey = "permissions-capabilities-block";
       break;
     case Services.perms.PROMPT_ACTION:
-      stringKey = "prompt";
+      stringKey = "permissions-capabilities-prompt";
       break;
+    default:
+        throw new Error(`Unknown capability: ${capability}`);
     }
-    return this._bundle.getString(stringKey);
+    return stringKey;
   },
 
   _addPermissionToList(perm) {
     // Ignore unrelated permission types and permissions with unknown states.
     if (perm.type !== this._type || !PERMISSION_STATES.includes(perm.capability))
       return;
-    let capabilityString = this._getCapabilityString(perm.capability);
-    let p = new Permission(perm.principal, perm.type, perm.capability,
-                           capabilityString);
+    let l10nId = this._getCapabilityString(perm.capability);
+    let p = new Permission(perm.principal, perm.type, perm.capability, l10nId);
     this._permissions.set(p.origin, p);
   },
 
   _removePermissionFromList(origin) {
     this._permissions.delete(origin);
     let permissionlistitem = document.getElementsByAttribute("origin", origin)[0];
     if (permissionlistitem) {
       permissionlistitem.remove();
@@ -223,30 +222,30 @@ var gSitePermissionsManager = {
       // PROMPT permission set for an origin.
       if (state == SitePermissions.UNKNOWN &&
           permission.capability == SitePermissions.PROMPT) {
         state = SitePermissions.PROMPT;
       } else if (state == SitePermissions.UNKNOWN) {
         continue;
       }
       let m = document.createElement("menuitem");
-      m.setAttribute("label", this._getCapabilityString(state));
+      document.l10n.setAttributes(m, this._getCapabilityString(state));
       m.setAttribute("value", state);
       menupopup.appendChild(m);
     }
     menulist.value = permission.capability;
 
     menulist.addEventListener("select", () => {
       this.onPermissionChange(permission, Number(menulist.selectedItem.value));
     });
 
     row.appendChild(hbox);
     row.appendChild(menulist);
     richlistitem.appendChild(row);
-    this._list.appendChild(richlistitem);
+    return richlistitem;
   },
 
   onWindowKeyPress(event) {
     if (event.keyCode == KeyEvent.DOM_VK_ESCAPE)
       window.close();
   },
 
   onPermissionKeyPress(event) {
@@ -295,17 +294,17 @@ var gSitePermissionsManager = {
     this._setRemoveButtonState();
   },
 
   onPermissionChange(perm, capability) {
     let p = this._permissions.get(perm.origin);
     if (p.capability == capability)
       return;
     p.capability = capability;
-    p.capabilityString = this._getCapabilityString(capability);
+    p.l10nId = this._getCapabilityString(capability);
     this._permissionsToChange.set(p.origin, p);
 
     // enable "remove all" button as needed
     this._setRemoveButtonState();
   },
 
   onApplyChanges() {
     // Stop observing permission changes since we are about
@@ -327,75 +326,88 @@ var gSitePermissionsManager = {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.BLOCK);
     } else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.UNKNOWN);
     }
 
     window.close();
   },
 
-  buildPermissionsList(sortCol) {
+  async buildPermissionsList(sortCol) {
     // Clear old entries.
     let oldItems = this._list.querySelectorAll("richlistitem");
     for (let item of oldItems) {
       item.remove();
     }
+    let frag = document.createDocumentFragment();
 
-    // Sort permissions.
-    let sortedPermissions = this._sortPermissions(sortCol);
+    let permissions = Array.from(this._permissions.values());
 
     let keyword = this._searchBox.value.toLowerCase().trim();
-    for (let permission of sortedPermissions) {
+    for (let permission of permissions) {
       if (keyword && !permission.origin.includes(keyword)) {
         continue;
       }
 
-      this._createPermissionListItem(permission);
+      let richlistitem = this._createPermissionListItem(permission);
+      frag.appendChild(richlistitem);
     }
 
+    // Sort permissions.
+    this._sortPermissions(this._list, frag, sortCol);
+
+    this._list.appendChild(frag);
+
     this._setRemoveButtonState();
   },
 
-  _sortPermissions(column) {
-    let permissions = Array.from(this._permissions.values());
+  _sortPermissions(list, frag, column) {
     let sortDirection;
 
     if (!column) {
       column = document.querySelector("treecol[data-isCurrentSortCol=true]");
       sortDirection = column.getAttribute("data-last-sortDirection") || "ascending";
     } else {
       sortDirection = column.getAttribute("data-last-sortDirection");
       sortDirection = sortDirection === "ascending" ? "descending" : "ascending";
     }
 
     let sortFunc = null;
     switch (column.id) {
       case "siteCol":
         sortFunc = (a, b) => {
-          return a.origin.localeCompare(b.origin);
+          return comp.compare(a.getAttribute("origin"), b.getAttribute("origin"));
         };
         break;
 
       case "statusCol":
         sortFunc = (a, b) => {
-          return a.capabilityString.localeCompare(b.capabilityString);
+          return parseInt(a.querySelector("menulist").value) >
+            parseInt(b.querySelector("menulist").value);
         };
         break;
     }
 
+    let comp = new Services.intl.Collator(undefined, {
+      usage: "sort"
+    });
+
+    let items = Array.from(frag.querySelectorAll("richlistitem"));
+
     if (sortDirection === "descending") {
-      permissions.sort((a, b) => sortFunc(b, a));
+      items.sort((a, b) => sortFunc(b, a));
     } else {
-      permissions.sort(sortFunc);
+      items.sort(sortFunc);
     }
 
-    let cols = this._list.querySelectorAll("treecol");
+    // Re-append items in the correct order:
+    items.forEach(item => frag.appendChild(item));
+
+    let cols = list.querySelectorAll("treecol");
     cols.forEach(c => {
       c.removeAttribute("data-isCurrentSortCol");
       c.removeAttribute("sortDirection");
     });
     column.setAttribute("data-isCurrentSortCol", "true");
     column.setAttribute("sortDirection", sortDirection);
     column.setAttribute("data-last-sortDirection", sortDirection);
-
-    return permissions;
   },
 };
--- a/browser/components/preferences/sitePermissions.xul
+++ b/browser/components/preferences/sitePermissions.xul
@@ -18,19 +18,16 @@
         persist="screenX screenY width height"
         onkeypress="gSitePermissionsManager.onWindowKeyPress(event);">
 
   <link rel="localization" href="browser/preferences/permissions.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://browser/content/preferences/sitePermissions.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-
   <keyset>
     <key data-l10n-id="permissions-close-key" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="contentPane largeDialogContainer" flex="1">
     <description id="permissionsText" control="url"/>
     <separator class="thin"/>
     <hbox align="start">
--- a/browser/components/preferences/translation.xul
+++ b/browser/components/preferences/translation.xul
@@ -17,19 +17,16 @@
         persist="screenX screenY width height"
         onkeypress="gTranslationExceptions.onWindowKeyPress(event);">
 
   <link rel="localization" href="browser/preferences/translation.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://browser/content/preferences/translation.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-
   <keyset>
     <key data-l10n-id="translation-close-key" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="largeDialogContainer">
     <vbox class="contentPane" flex="1">
       <label id="languagesLabel"
              data-l10n-id="translation-languages-disabled-desc"
--- a/browser/locales/en-US/browser/preferences/blocklists.ftl
+++ b/browser/locales/en-US/browser/preferences/blocklists.ftl
@@ -15,8 +15,22 @@ blocklist-treehead-list =
 
 blocklist-button-cancel =
     .label = Cancel
     .accesskey = C
 
 blocklist-button-ok =
     .label = Save Changes
     .accesskey = S
+
+# This template constructs the name of the block list in the block lists dialog.
+# It combines the list name and description.
+# e.g. "Standard (Recommended). This list does a pretty good job."
+#
+# Variables:
+#   $listName {string, "Standard (Recommended)."} - List name.
+#   $description {string, "This list does a pretty good job."} - Description of the list.
+blocklist-item-list-template = { $listName } { $description }
+
+blocklist-item-moz-std-name = Disconnect.me basic protection (Recommended).
+blocklist-item-moz-std-desc = Allows some trackers so websites function properly.
+blocklist-item-moz-full-name = Disconnect.me strict protection.
+blocklist-item-moz-full-desc = Blocks known trackers. Some websites may not function properly.
--- a/browser/locales/en-US/browser/preferences/fonts.ftl
+++ b/browser/locales/en-US/browser/preferences/fonts.ftl
@@ -146,8 +146,19 @@ fonts-languages-fallback-name-korean =
 fonts-languages-fallback-name-thai =
     .label = Thai
 fonts-languages-fallback-name-turkish =
     .label = Turkish
 fonts-languages-fallback-name-vietnamese =
     .label = Vietnamese
 fonts-languages-fallback-name-other =
     .label = Other (incl. Western European)
+
+fonts-very-large-warning-title = Large minimum font size
+fonts-very-large-warning-message = You have selected a very large minimum font size (more than 24 pixels). This may make it difficult or impossible to use some important configuration pages like this one.
+fonts-very-large-warning-accept = Keep my changes anyway
+
+# Variables:
+#   $name {string, "Arial"} - Name of the default font
+fonts-label-default =
+    .label = Default ({ $name })
+fonts-label-default-unnamed =
+    .label = Default
--- a/browser/locales/en-US/browser/preferences/languages.ftl
+++ b/browser/locales/en-US/browser/preferences/languages.ftl
@@ -27,8 +27,21 @@ languages-customize-remove =
     .accesskey = R
 
 languages-customize-select-language =
     .placeholder = Select a language to add…
 
 languages-customize-add =
     .label = Add
     .accesskey = A
+
+# The pattern used to generate strings presented to the user in the
+# locale selection list.
+#
+# Example:
+#   Icelandic [is]
+#   Spanish (Chile) [es-CL]
+#
+# Variables:
+#   $locale (String) - A name of the locale (for example: "Icelandic", "Spanish (Chile)")
+#   $code (String) - Locale code of the locale (for example: "is", "es-CL")
+languages-code-format =
+    .label = { $locale } [{ $code }]
--- a/browser/locales/en-US/browser/preferences/permissions.ftl
+++ b/browser/locales/en-US/browser/preferences/permissions.ftl
@@ -44,16 +44,22 @@ permissions-button-cancel =
 
 permissions-button-ok =
     .label = Save Changes
     .accesskey = S
 
 permissions-searchbox =
     .placeholder = Search Website
 
+permissions-capabilities-allow =
+    .label = Allow
+permissions-capabilities-block =
+    .label = Block
+permissions-capabilities-prompt =
+    .label = Always Ask
 
 ## Invalid Hostname Dialog
 
 permissions-invalid-uri-title = Invalid Hostname Entered
 permissions-invalid-uri-label = Please enter a valid hostname
 
 ## Exceptions - Tracking Protection
 
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -715,16 +715,23 @@ history-clear-on-close-settings =
 history-clear-button =
     .label = Clear History…
     .accesskey = s
 
 ## Privacy Section - Site Data
 
 sitedata-header = Cookies and Site Data
 
+sitedata-total-size-calculating = Calculating site data and cache size…
+
+# Variables:
+#   $value (Number) - Value of the unit (for example: 4.6, 500)
+#   $unit (String) - Name of the unit (for example: "bytes", "KB")
+sitedata-total-size = Your stored cookies, site data and cache are currently using { $value } { $unit } of disk space.
+
 sitedata-learn-more = Learn more
 
 sitedata-accept-cookies-option =
     .label = Accept cookies and site data from websites (recommended)
     .accesskey = A
 
 sitedata-block-cookies-option =
     .label = Block cookies and site data (may cause websites to break)
--- a/browser/locales/en-US/browser/preferences/siteDataSettings.ftl
+++ b/browser/locales/en-US/browser/preferences/siteDataSettings.ftl
@@ -3,16 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
 ## Settings
 
 site-data-settings-window =
     .title = Manage Cookies and Site Data
 
+site-data-settings-description = The following websites store cookies and site data on your computer. { -brand-short-name } keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
+
 site-data-search-textbox =
     .placeholder = Search websites
     .accesskey = S
 
 site-data-column-host =
     .label = Site
 site-data-column-cookies =
     .label = Cookies
@@ -28,18 +30,33 @@ site-data-remove-selected =
 site-data-button-cancel =
     .label = Cancel
     .accesskey = C
 
 site-data-button-save =
     .label = Save Changes
     .accesskey = a
 
+# Variables:
+#   $value (Number) - Value of the unit (for example: 4.6, 500)
+#   $unit (String) - Name of the unit (for example: "bytes", "KB")
+site-usage-pattern = { $value } { $unit }
+site-usage-persistent = { site-usage-pattern } (Persistent)
+
+site-data-remove-all =
+    .label = Remove All
+    .accesskey = e
+
+site-data-remove-shown =
+    .label = Remove All Shown
+    .accesskey = e
+
 ## Removing
 
-site-data-removing-window =
+site-data-removing-dialog =
     .title = { site-data-removing-header }
+    .buttonlabelaccept = Remove
 
 site-data-removing-header = Removing Cookies and Site Data
 
 site-data-removing-desc = Removing cookies and site data may log you out of websites. Are you sure you want to make the changes?
 
 site-data-removing-table = Cookies and site data for the following websites will be removed
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -4,56 +4,21 @@
 
 #### Security
 
 # LOCALIZATION NOTE: phishBefore uses %S to represent the name of the provider
 #                    whose privacy policy must be accepted (for enabling
 #                    check-every-page-as-I-load-it phishing protection).
 phishBeforeText=Selecting this option will send the address of web pages you are viewing to %S. To continue, please review and accept the following terms of service.
 
-#### Fonts
-
-labelDefaultFont=Default (%S)
-labelDefaultFontUnnamed=Default
-
-veryLargeMinimumFontTitle=Large minimum font size
-veryLargeMinimumFontWarning=You have selected a very large minimum font size (more than 24 pixels). This may make it difficult or impossible to use some important configuration pages like this one.
-acceptVeryLargeMinimumFont=Keep my changes anyway
-
-#### Block List Manager
-
-# LOCALIZATION NOTE (mozNameTemplate): This template constructs the name of the
-# block list in the block lists dialog. It combines the list name and
-# description.
-#   e.g. mozNameTemplate : "Standard (Recommended). This list does a pretty good job."
-#   %1$S = list name (fooName), %2$S = list descriptive text (fooDesc)
-mozNameTemplate=%1$S %2$S
-# LOCALIZATION NOTE (mozstdName, etc.): These labels appear in the tracking
-# protection block lists dialog, mozNameTemplate is used to create the final
-# string. Note that in the future these two strings (name, desc) could be
-# displayed on two different lines.
-mozstdName=Disconnect.me basic protection (Recommended).
-mozstdDesc=Allows some trackers so websites function properly.
-mozfullName=Disconnect.me strict protection.
-mozfullDesc2=Blocks known trackers. Some websites may not function properly.
-
 #### Master Password
 
 pw_change2empty_in_fips_mode=You are currently in FIPS mode. FIPS requires a non-empty Master Password.
 pw_change_failed_title=Password Change Failed
 
-#### Fonts
-
-# LOCALIZATION NOTE: The string represents a localized locale name
-#   followed by the BCP47 locale code.
-#
-# Example: "French (Canada)  [fr-ca]"
-#   %1$S = locale name, %2$S = locale code
-languageCodeFormat=%1$S  [%2$S]
-
 #### Downloads
 
 desktopFolderName=Desktop
 downloadsFolderName=Downloads
 chooseDownloadFolderTitle=Choose Download Folder:
 
 #### Applications
 
@@ -90,41 +55,16 @@ typeDescriptionWithType=%S (%S)
 #### Permission labels
 
 can=Allow
 canAccessFirstParty=Allow first party only
 canSession=Allow for Session
 cannot=Block
 prompt=Always Ask
 
-#### Site Data Manager
-
-# LOCALIZATION NOTE (totalSiteDataSize2, siteUsage, siteUsagePersistent):
-#   This is the total usage of site data, where we insert storage size and unit.
-#   e.g., "The total usage is currently 200 MB"
-#   %1$S = size
-#   %2$S = unit (MB, KB, etc.)
-totalSiteDataSize2=Your stored cookies, site data and cache are currently using %1$S %2$S of disk space.
-siteUsage=%1$S %2$S
-siteUsagePersistent=%1$S %2$S (Persistent)
-loadingSiteDataSize1=Calculating site data and cache size…
-
-acceptRemove=Remove
-# LOCALIZATION NOTE (siteDataSettings3.description): %S = brandShortName
-siteDataSettings3.description=The following websites store cookies and site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
-# LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
-# removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
-# never displayed together and can share the same accesskey.
-# When only partial sites are shown as a result of keyword search,
-# removeAllShown is displayed as button label.
-# removeAll is displayed when no keyword search and all sites are shown.
-removeAllSiteData.label=Remove All
-removeAllSiteData.accesskey=e
-removeAllSiteDataShown.label=Remove All Shown
-removeAllSiteDataShown.accesskey=e
 spaceAlert.learnMoreButton.label=Learn More
 spaceAlert.learnMoreButton.accesskey=L
 spaceAlert.over5GB.prefButton.label=Open Preferences
 spaceAlert.over5GB.prefButton.accesskey=O
 # LOCALIZATION NOTE (spaceAlert.over5GB.prefButtonWin.label): On Windows Preferences is called Options
 spaceAlert.over5GB.prefButtonWin.label=Open Options
 spaceAlert.over5GB.prefButtonWin.accesskey=O
 # LOCALIZATION NOTE (spaceAlert.over5GB.message1): %S = brandShortName
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -57,16 +57,25 @@ ChromeUtils.defineModuleGetter(this, "Pl
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gHistoryObserver", function() {
   return Object.freeze({
     onClearHistory() {
       WinTaskbarJumpList.update();
     },
+    onBeginUpdateBatch() {},
+    onEndUpdateBatch() {},
+    onVisits() {},
+    onTitleChanged() {},
+    onFrecencyChanged() {},
+    onManyFrecenciesChanged() {},
+    onDeleteURI() {},
+    onPageChanged() {},
+    onDeleteVisits() {},
     QueryInterface: ChromeUtils.generateQI([Ci.nsINavHistoryObserver]),
   });
 });
 
 /**
  * Global functions
  */
 
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -147,8 +147,12 @@
 
 /* End private browsing and accessibility indicators */
 
 /* Force background for datepicker popup to white so themes don't override it */
 #DateTimePickerPanel[active="true"] > .panel-arrowcontainer > .panel-arrowbox,
 #DateTimePickerPanel[active="true"] > .panel-arrowcontainer > .panel-arrowcontent {
   --arrowpanel-background: #fff;
 }
+
+#widget-overflow .webextension-popup-browser {
+  background: #fff;
+}
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/python3-defaults-wheezy.diff
@@ -0,0 +1,31 @@
+diff --git a/debian/changelog b/debian/changelog
+index a2948ae..338ed66 100644
+--- a/debian/changelog
++++ b/debian/changelog
+@@ -1,3 +1,11 @@
++python3-defaults (3.5.3-1.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for wheezy.
++  * debian/control.in
++    * Remove :any from dependencies because it seems to confuse wheezy
++
++ -- Gregory Szorc <gps@mozilla.com>  Tue, 9 May 2018 15:00:00 -0800
++
+ python3-defaults (3.5.3-1) unstable; urgency=medium
+
+   * Bump version to 3.5.3.
+diff --git a/debian/control.in b/debian/control.in
+index 89e1aa4..e58be76 100644
+--- a/debian/control.in
++++ b/debian/control.in
+@@ -5,8 +5,8 @@ Maintainer: Matthias Klose <doko@debian.org>
+ Uploaders: Piotr O<C5><BC>arowski <piotr@debian.org>, Scott Kitterman <scott@kitterman.com>
+ Build-Depends: debhelper (>= 9), @bd_i586@
+   lsb-release,
+-  python3-minimal:any,
+-  python3.5-minimal:any,
++  python3-minimal,
++  python3.5-minimal,
+   python3-docutils,
+   debiandoc-sgml
+ Standards-Version: 3.9.8
--- a/build/gen_test_packages_manifest.py
+++ b/build/gen_test_packages_manifest.py
@@ -13,27 +13,29 @@ ALL_HARNESSES = [
     'mochitest',
     'reftest',
     'xpcshell',
     'cppunittest',
     'jittest',
     'mozbase',
     'web-platform',
     'talos',
+    'raptor',
     'awsy',
     'gtest',
 ]
 
 PACKAGE_SPECIFIED_HARNESSES = [
     'cppunittest',
     'mochitest',
     'reftest',
     'xpcshell',
     'web-platform',
     'talos',
+    'raptor',
     'awsy',
 ]
 
 # These packages are not present for every build configuration.
 OPTIONAL_PACKAGES = [
     'gtest',
 ]
 
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -255,33 +255,43 @@ NS_INTERFACE_MAP_BEGIN(nsSHistory)
   NS_INTERFACE_MAP_ENTRY(nsISHistoryInternal)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 // static
 uint32_t
 nsSHistory::CalcMaxTotalViewers()
 {
+  // This value allows tweaking how fast the allowed amount of content viewers
+  // grows with increasing amounts of memory. Larger values mean slower growth.
+  #ifdef ANDROID
+  #define MAX_TOTAL_VIEWERS_BIAS 15.9
+  #else
+  #define MAX_TOTAL_VIEWERS_BIAS 14
+  #endif
+
   // Calculate an estimate of how many ContentViewers we should cache based
   // on RAM.  This assumes that the average ContentViewer is 4MB (conservative)
   // and caps the max at 8 ContentViewers
   //
   // TODO: Should we split the cache memory betw. ContentViewer caching and
   // nsCacheService?
   //
-  // RAM      ContentViewers
-  // -----------------------
-  // 32   Mb       0
-  // 64   Mb       1
-  // 128  Mb       2
-  // 256  Mb       3
-  // 512  Mb       5
-  // 1024 Mb       8
-  // 2048 Mb       8
-  // 4096 Mb       8
+  // RAM    | ContentViewers | on Android
+  // -------------------------------------
+  // 32   Mb       0                0
+  // 64   Mb       1                0
+  // 128  Mb       2                0
+  // 256  Mb       3                1
+  // 512  Mb       5                2
+  // 768  Mb       6                2
+  // 1024 Mb       8                3
+  // 2048 Mb       8                5
+  // 3072 Mb       8                7
+  // 4096 Mb       8                8
   uint64_t bytes = PR_GetPhysicalMemorySize();
 
   if (bytes == 0) {
     return 0;
   }
 
   // Conversion from unsigned int64_t to double doesn't work on all platforms.
   // We need to truncate the value at INT64_MAX to make sure we don't
@@ -291,17 +301,17 @@ nsSHistory::CalcMaxTotalViewers()
   }
 
   double kBytesD = (double)(bytes >> 10);
 
   // This is essentially the same calculation as for nsCacheService,
   // except that we divide the final memory calculation by 4, since
   // we assume each ContentViewer takes on average 4MB
   uint32_t viewers = 0;
-  double x = std::log(kBytesD) / std::log(2.0) - 14;
+  double x = std::log(kBytesD) / std::log(2.0) - MAX_TOTAL_VIEWERS_BIAS;
   if (x > 0) {
     viewers = (uint32_t)(x * x - x + 2.001); // add .001 for rounding
     viewers /= 4;
   }
 
   // Cap it off at 8 max
   if (viewers > 8) {
     viewers = 8;
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1156,51 +1156,16 @@ XULDocument::Persist(const nsAString& aI
         }
 
         nameSpaceID = kNameSpaceID_None;
     }
 
     aRv = Persist(element, nameSpaceID, tag);
 }
 
-enum class ConversionDirection {
-    InnerToOuter,
-    OuterToInner,
-};
-
-static void
-ConvertWindowSize(nsIXULWindow* aWin,
-                  nsAtom* aAttr,
-                  ConversionDirection aDirection,
-                  nsAString& aInOutString)
-{
-    MOZ_ASSERT(aWin);
-    MOZ_ASSERT(aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height);
-
-    nsresult rv;
-    int32_t size = aInOutString.ToInteger(&rv);
-    if (NS_FAILED(rv)) {
-        return;
-    }
-
-    int32_t sizeDiff = aAttr == nsGkAtoms::width
-        ? aWin->GetOuterToInnerWidthDifferenceInCSSPixels()
-        : aWin->GetOuterToInnerHeightDifferenceInCSSPixels();
-
-    if (!sizeDiff) {
-        return;
-    }
-
-    int32_t multiplier =
-        aDirection == ConversionDirection::InnerToOuter ? 1 : - 1;
-
-    CopyASCIItoUTF16(nsPrintfCString("%d", size + multiplier * sizeDiff),
-                     aInOutString);
-}
-
 nsresult
 XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
                      nsAtom* aAttribute)
 {
     // For non-chrome documents, persistance is simply broken
     if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
         return NS_ERROR_NOT_AVAILABLE;
 
@@ -1231,26 +1196,19 @@ XULDocument::Persist(Element* aElement, 
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
     }
 
     if (hasAttr && valuestr.IsEmpty()) {
         return mLocalStore->RemoveValue(uri, id, attrstr);
     }
 
-    // Make sure we store the <window> attributes as outer window size, see
-    // bug 1444525 & co.
-    if (aElement->IsXULElement(nsGkAtoms::window) &&
-        (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
-        if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
-            ConvertWindowSize(win,
-                              aAttribute,
-                              ConversionDirection::InnerToOuter,
-                              valuestr);
-        }
+    // Persisting attributes to windows is handled by nsXULWindow.
+    if (aElement->IsXULElement(nsGkAtoms::window)) {
+        return NS_OK;
     }
 
     return mLocalStore->SetValue(uri, id, attrstr, valuestr);
 }
 
 
 nsresult
 XULDocument::GetViewportSize(int32_t* aWidth,
@@ -1832,31 +1790,19 @@ XULDocument::ApplyPersistentAttributesTo
 
         uint32_t cnt = aElements.Count();
         for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
             RefPtr<Element> element = aElements.SafeObjectAt(i);
             if (!element) {
                  continue;
             }
 
-            // Convert attributes from outer size to inner size for top-level
-            // windows, see bug 1444525 & co.
-            if (element->IsXULElement(nsGkAtoms::window) &&
-                (attr == nsGkAtoms::width || attr == nsGkAtoms::height)) {
-                if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
-                    nsAutoString maybeConvertedValue = value;
-                    ConvertWindowSize(win,
-                                      attr,
-                                      ConversionDirection::OuterToInner,
-                                      maybeConvertedValue);
-                    Unused <<
-                        element->SetAttr(kNameSpaceID_None, attr, maybeConvertedValue, true);
-
-                    continue;
-                }
+            // Applying persistent attributes to windows is handled by nsXULWindow.
+            if (element->IsXULElement(nsGkAtoms::window)) {
+                continue;
             }
 
             Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
         }
     }
 
     return NS_OK;
 }
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1727,48 +1727,61 @@ CompositorBridgeParent::RecvMapAndNotify
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvAdoptChild(const LayersId& child)
 {
   RefPtr<APZUpdater> oldApzUpdater;
   APZCTreeManagerParent* parent;
-  {
+  bool scheduleComposition = false;
+  RefPtr<CrossProcessCompositorBridgeParent> cpcp;
+  RefPtr<WebRenderBridgeParent> childWrBridge;
+
+  { // scope lock
     MonitorAutoLock lock(*sIndirectLayerTreesLock);
     if (sIndirectLayerTrees[child].mParent) {
       // We currently don't support adopting children from one compositor to
       // another if the two compositors don't have the same options.
       MOZ_ASSERT(sIndirectLayerTrees[child].mParent->mOptions == mOptions);
       oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
     }
     NotifyChildCreated(child);
     if (sIndirectLayerTrees[child].mLayerTree) {
       sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager, GetAnimationStorage());
       // Trigger composition to handle a case that mLayerTree was not composited yet
       // by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete.
-      ScheduleComposition();
+      scheduleComposition = true;
     }
-    if (mWrBridge && sIndirectLayerTrees[child].mWrBridge) {
-      RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
-      api = api->Clone();
-      sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
-                                                            api,
-                                                            mWrBridge->AsyncImageManager(),
-                                                            GetAnimationStorage());
-      // Pretend we composited, since parent CompositorBridgeParent was replaced.
-      CrossProcessCompositorBridgeParent* cpcp = sIndirectLayerTrees[child].mCrossProcessParent;
-      if (cpcp) {
-        TimeStamp now = TimeStamp::Now();
-        cpcp->DidCompositeLocked(child, now, now);
-      }
+    if (mWrBridge) {
+      childWrBridge = sIndirectLayerTrees[child].mWrBridge;
+      cpcp = sIndirectLayerTrees[child].mCrossProcessParent;
     }
     parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
   }
 
+  if (scheduleComposition) {
+    ScheduleComposition();
+  }
+
+  if (childWrBridge) {
+    MOZ_ASSERT(mWrBridge);
+    RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
+    api = api->Clone();
+    childWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
+                                   api,
+                                   mWrBridge->AsyncImageManager(),
+                                   GetAnimationStorage());
+    // Pretend we composited, since parent CompositorBridgeParent was replaced.
+    if (cpcp) {
+      TimeStamp now = TimeStamp::Now();
+      cpcp->DidComposite(child, now, now);
+    }
+  }
+
   if (oldApzUpdater) {
     // We don't support moving a child from an APZ-enabled compositor to a
     // APZ-disabled compositor. The mOptions assertion above should already
     // ensure this, since APZ-ness is one of the things in mOptions. Note
     // however it is possible for mApzUpdater to be non-null here with
     // oldApzUpdater null, because the child may not have been previously
     // composited.
     MOZ_ASSERT(mApzUpdater);
--- a/gfx/src/nsColor.cpp
+++ b/gfx/src/nsColor.cpp
@@ -253,69 +253,16 @@ NS_ComposeColors(nscolor aBG, nscolor aF
   }
   MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
   MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
   MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
 
   return NS_RGBA(r, g, b, a);
 }
 
-namespace mozilla {
-
-static uint32_t
-BlendColorComponent(uint32_t aBg, uint32_t aFg, uint32_t aFgAlpha)
-{
-  return RoundingDivideBy255(aBg * (255 - aFgAlpha) + aFg * aFgAlpha);
-}
-
-nscolor
-LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio)
-{
-  // Common case that either pure background or pure foreground
-  if (aFgRatio == 0) {
-    return aBg;
-  }
-  if (aFgRatio == 255) {
-    return aFg;
-  }
-  // Common case that alpha channel is equal (usually both are opaque)
-  if (NS_GET_A(aBg) == NS_GET_A(aFg)) {
-    auto r = BlendColorComponent(NS_GET_R(aBg), NS_GET_R(aFg), aFgRatio);
-    auto g = BlendColorComponent(NS_GET_G(aBg), NS_GET_G(aFg), aFgRatio);
-    auto b = BlendColorComponent(NS_GET_B(aBg), NS_GET_B(aFg), aFgRatio);
-    return NS_RGBA(r, g, b, NS_GET_A(aFg));
-  }
-
-  constexpr float kFactor = 1.0f / 255.0f;
-
-  float p1 = kFactor * (255 - aFgRatio);
-  float a1 = kFactor * NS_GET_A(aBg);
-  float r1 = a1 * NS_GET_R(aBg);
-  float g1 = a1 * NS_GET_G(aBg);
-  float b1 = a1 * NS_GET_B(aBg);
-
-  float p2 = 1.0f - p1;
-  float a2 = kFactor * NS_GET_A(aFg);
-  float r2 = a2 * NS_GET_R(aFg);
-  float g2 = a2 * NS_GET_G(aFg);
-  float b2 = a2 * NS_GET_B(aFg);
-
-  float a = p1 * a1 + p2 * a2;
-  if (a == 0.0) {
-    return NS_RGBA(0, 0, 0, 0);
-  }
-
-  auto r = ClampColor((p1 * r1 + p2 * r2) / a);
-  auto g = ClampColor((p1 * g1 + p2 * g2) / a);
-  auto b = ClampColor((p1 * b1 + p2 * b2) / a);
-  return NS_RGBA(r, g, b, NSToIntRound(a * 255));
-}
-
-} // namespace mozilla
-
 // Functions to convert from HSL color space to RGB color space.
 // This is the algorithm described in the CSS3 specification
 
 // helper
 static float
 HSL_HueToRGB(float m1, float m2, float h)
 {
   if (h < 0.0f)
--- a/gfx/src/nsColor.h
+++ b/gfx/src/nsColor.h
@@ -81,20 +81,16 @@ namespace mozilla {
 inline uint32_t RoundingDivideBy255(uint32_t n)
 {
   // There is an approximate alternative: ((n << 8) + n + 32896) >> 16
   // But that is actually slower than this simple expression on a modern
   // machine with a modern compiler.
   return (n + 127) / 255;
 }
 
-// Blend one RGBA color with another based on a given ratio.
-// It is a linear interpolation on each channel with alpha premultipled.
-nscolor LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio);
-
 } // namespace mozilla
 
 // Translate a hex string to a color. Return true if it parses ok,
 // otherwise return false.
 // This version accepts 1 to 9 digits (missing digits are 0)
 bool NS_LooseHexToRGB(const nsString& aBuf, nscolor* aResult);
 
 // There is no function to translate a color to a hex string, because
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -211,22 +211,16 @@ public:
    * Does the nsITheme implementation draw its own focus ring for this widget?
    */
   virtual bool ThemeDrawsFocusForWidget(uint8_t aWidgetType)=0;
   
   /**
     * Should we insert a dropmarker inside of combobox button?
    */
   virtual bool ThemeNeedsComboboxDropmarker()=0;
-
-  /**
-   * Should we hide scrollbars?
-   */
-  virtual bool ShouldHideScrollbars()
-  { return false; }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsITheme, NS_ITHEME_IID)
 
 // Creator function
 extern nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 #endif
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -189,17 +189,17 @@ JS::TraceIncomingCCWs(JSTracer* trc, con
 // simplicity and performance of FireFox's embedding of this engine.
 void
 gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape)
 {
     do {
         MOZ_ASSERT(shape->base());
         shape->base()->assertConsistency();
 
-        TraceEdge(trc, &shape->propidRef(), "propid");
+        // Don't trace the propid because the CC doesn't care about jsid.
 
         if (shape->hasGetterObject()) {
             JSObject* tmp = shape->getterObject();
             DoCallback(trc, &tmp, "getter");
             MOZ_ASSERT(tmp == shape->getterObject());
         }
 
         if (shape->hasSetterObject()) {
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -2000,45 +2000,83 @@ nsFloatManager::ImageShapeInfo::ImageSha
           DebugOnly<uint32_t> alphaIndex = col - dfOffset.x +
                                            (row - dfOffset.y) * aStride;
           MOZ_ASSERT(alphaIndex < (aStride * h),
             "Our aAlphaPixels index should be in-bounds.");
 
           df[index] = 0;
         } else {
           // Case 3: Other pixel.
-
-          // Backward-looking neighborhood distance from target pixel X
-          // with chamfer 5-7-11 looks like:
-          //
-          // +--+--+--+--+--+
-          // |  |11|  |11|  |
-          // +--+--+--+--+--+
-          // |11| 7| 5| 7|11|
-          // +--+--+--+--+--+
-          // |  | 5| X|  |  |
-          // +--+--+--+--+--+
-          //
-          // X should be set to the minimum of MAX_MARGIN_5X and the
-          // values of all of the numbered neighbors summed with the
-          // value in that chamfer cell.
-          MOZ_ASSERT(index - (wEx * 2) - 1 < (iSize * bSize) &&
-                     index - wEx - 2 < (iSize * bSize),
-                     "Our distance field most extreme indices should be "
-                     "in-bounds.");
-
-          df[index] = std::min<dfType>(MAX_MARGIN_5X,
-                      std::min<dfType>(df[index - (wEx * 2) - 1] + 11,
-                      std::min<dfType>(df[index - (wEx * 2) + 1] + 11,
-                      std::min<dfType>(df[index - wEx - 2] + 11,
-                      std::min<dfType>(df[index - wEx - 1] + 7,
-                      std::min<dfType>(df[index - wEx] + 5,
-                      std::min<dfType>(df[index - wEx + 1] + 7,
-                      std::min<dfType>(df[index - wEx + 2] + 11,
-                                       df[index - 1] + 5))))))));
+          if (aWM.IsVertical()) {
+            // Column-by-column, starting at the left, each column
+            // top-to-bottom.
+            // Backward-looking neighborhood distance from target pixel X
+            // with chamfer 5-7-11 looks like:
+            //
+            // +--+--+--+
+            // |  |11|  |   |    +
+            // +--+--+--+   |   /|
+            // |11| 7| 5|   |  / |
+            // +--+--+--+   | /  V
+            // |  | 5| X|   |/
+            // +--+--+--+   +
+            // |11| 7|  |
+            // +--+--+--+
+            // |  |11|  |
+            // +--+--+--+
+            //
+            // X should be set to the minimum of MAX_MARGIN_5X and the
+            // values of all of the numbered neighbors summed with the
+            // value in that chamfer cell.
+            MOZ_ASSERT(index - wEx - 2 < (iSize * bSize) &&
+                       index + wEx - 2 < (iSize * bSize) &&
+                       index - (wEx * 2) - 1 < (iSize * bSize),
+                       "Our distance field most extreme indices should be "
+                       "in-bounds.");
+
+            df[index] = std::min<dfType>(MAX_MARGIN_5X,
+                        std::min<dfType>(df[index - wEx - 2] + 11,
+                        std::min<dfType>(df[index + wEx - 2] + 11,
+                        std::min<dfType>(df[index - (wEx * 2) - 1] + 11,
+                        std::min<dfType>(df[index - wEx - 1] + 7,
+                        std::min<dfType>(df[index - 1] + 5,
+                        std::min<dfType>(df[index + wEx - 1] + 7,
+                        std::min<dfType>(df[index + (wEx * 2) - 1] + 11,
+                                         df[index - wEx] + 5))))))));
+          } else {
+            // Row-by-row, starting at the top, each row left-to-right.
+            // Backward-looking neighborhood distance from target pixel X
+            // with chamfer 5-7-11 looks like:
+            //
+            // +--+--+--+--+--+
+            // |  |11|  |11|  |   ----+
+            // +--+--+--+--+--+      /
+            // |11| 7| 5| 7|11|     /
+            // +--+--+--+--+--+    /
+            // |  | 5| X|  |  |   +-->
+            // +--+--+--+--+--+
+            //
+            // X should be set to the minimum of MAX_MARGIN_5X and the
+            // values of all of the numbered neighbors summed with the
+            // value in that chamfer cell.
+            MOZ_ASSERT(index - (wEx * 2) - 1 < (iSize * bSize) &&
+                       index - wEx - 2 < (iSize * bSize),
+                       "Our distance field most extreme indices should be "
+                       "in-bounds.");
+
+            df[index] = std::min<dfType>(MAX_MARGIN_5X,
+                        std::min<dfType>(df[index - (wEx * 2) - 1] + 11,
+                        std::min<dfType>(df[index - (wEx * 2) + 1] + 11,
+                        std::min<dfType>(df[index - wEx - 2] + 11,
+                        std::min<dfType>(df[index - wEx - 1] + 7,
+                        std::min<dfType>(df[index - wEx] + 5,
+                        std::min<dfType>(df[index - wEx + 1] + 7,
+                        std::min<dfType>(df[index - wEx + 2] + 11,
+                                         df[index - 1] + 5))))))));
+          }
         }
       }
     }
 
     // Okay, time for the second pass. This pass is in reverse order from
     // the first pass. All of our opaque pixels have been set to 0, and all
     // of our expanded region pixels have been set to MAX_MARGIN_5X. Other
     // pixels have been set to some value between those two (inclusive) but
@@ -2073,44 +2111,83 @@ nsFloatManager::ImageShapeInfo::ImageSha
         const uint32_t row = aWM.IsVertical() ? i : b;
         const uint32_t index = col + row * wEx;
         MOZ_ASSERT(index < (wEx * hEx),
                    "Our distance field index should be in-bounds.");
 
         // Only apply the chamfer calculation if the df value is not
         // already 0, since the chamfer can only reduce the value.
         if (df[index]) {
-          // Forward-looking neighborhood distance from target pixel X
-          // with chamfer 5-7-11 looks like:
-          //
-          // +--+--+--+--+--+
-          // |  |  | X| 5|  |
-          // +--+--+--+--+--+
-          // |11| 7| 5| 7|11|
-          // +--+--+--+--+--+
-          // |  |11|  |11|  |
-          // +--+--+--+--+--+
-          //
-          // X should be set to the minimum of its current value and
-          // the values of all of the numbered neighbors summed with
-          // the value in that chamfer cell.
-          MOZ_ASSERT(index + (wEx * 2) + 1 < (wEx * hEx) &&
-                     index + wEx + 2 < (wEx * hEx),
-                     "Our distance field most extreme indices should be "
-                     "in-bounds.");
-
-          df[index] = std::min<dfType>(df[index],
-                      std::min<dfType>(df[index + (wEx * 2) + 1] + 11,
-                      std::min<dfType>(df[index + (wEx * 2) - 1] + 11,
-                      std::min<dfType>(df[index + wEx + 2] + 11,
-                      std::min<dfType>(df[index + wEx + 1] + 7,
-                      std::min<dfType>(df[index + wEx] + 5,
-                      std::min<dfType>(df[index + wEx - 1] + 7,
-                      std::min<dfType>(df[index + wEx - 2] + 11,
-                                       df[index + 1] + 5))))))));
+          if (aWM.IsVertical()) {
+            // Column-by-column, starting at the right, each column
+            // bottom-to-top.
+            // Forward-looking neighborhood distance from target pixel X
+            // with chamfer 5-7-11 looks like:
+            //
+            // +--+--+--+
+            // |  |11|  |        +
+            // +--+--+--+       /|
+            // |  | 7|11|   A  / |
+            // +--+--+--+   | /  |
+            // | X| 5|  |   |/   |
+            // +--+--+--+   +    |
+            // | 5| 7|11|
+            // +--+--+--+
+            // |  |11|  |
+            // +--+--+--+
+            //
+            // X should be set to the minimum of its current value and
+            // the values of all of the numbered neighbors summed with
+            // the value in that chamfer cell.
+            MOZ_ASSERT(index + wEx + 2 < (wEx * hEx) &&
+                       index + (wEx * 2) + 1 < (wEx * hEx) &&
+                       index - (wEx * 2) + 1 < (wEx * hEx),
+                       "Our distance field most extreme indices should be "
+                       "in-bounds.");
+
+            df[index] = std::min<dfType>(df[index],
+                        std::min<dfType>(df[index + wEx + 2] + 11,
+                        std::min<dfType>(df[index - wEx + 2] + 11,
+                        std::min<dfType>(df[index + (wEx * 2) + 1] + 11,
+                        std::min<dfType>(df[index + wEx + 1] + 7,
+                        std::min<dfType>(df[index + 1] + 5,
+                        std::min<dfType>(df[index - wEx + 1] + 7,
+                        std::min<dfType>(df[index - (wEx * 2) + 1] + 11,
+                                         df[index + wEx] + 5))))))));
+          } else {
+            // Row-by-row, starting at the bottom, each row right-to-left.
+            // Forward-looking neighborhood distance from target pixel X
+            // with chamfer 5-7-11 looks like:
+            //
+            // +--+--+--+--+--+
+            // |  |  | X| 5|  |    <--+
+            // +--+--+--+--+--+      /
+            // |11| 7| 5| 7|11|     /
+            // +--+--+--+--+--+    /
+            // |  |11|  |11|  |   +----
+            // +--+--+--+--+--+
+            //
+            // X should be set to the minimum of its current value and
+            // the values of all of the numbered neighbors summed with
+            // the value in that chamfer cell.
+            MOZ_ASSERT(index + (wEx * 2) + 1 < (wEx * hEx) &&
+                       index + wEx + 2 < (wEx * hEx),
+                       "Our distance field most extreme indices should be "
+                       "in-bounds.");
+
+            df[index] = std::min<dfType>(df[index],
+                        std::min<dfType>(df[index + (wEx * 2) + 1] + 11,
+                        std::min<dfType>(df[index + (wEx * 2) - 1] + 11,
+                        std::min<dfType>(df[index + wEx + 2] + 11,
+                        std::min<dfType>(df[index + wEx + 1] + 7,
+                        std::min<dfType>(df[index + wEx] + 5,
+                        std::min<dfType>(df[index + wEx - 1] + 7,
+                        std::min<dfType>(df[index + wEx - 2] + 11,
+                                         df[index + 1] + 5))))))));
+          }
         }
 
         // Finally, we can check the df value and see if it's less than
         // or equal to the usedMargin5X value.
         if (df[index] <= usedMargin5X) {
           if (iMax == -1) {
             iMax = i;
           }
@@ -2177,18 +2254,21 @@ nsFloatManager::ImageShapeInfo::CreateIn
   // Depending on the writing mode, we now move the origin.
   if (aWM.IsVerticalRL()) {
     // vertical-rl or sideways-rl.
     // These writing modes proceed from the top right, and each interval
     // moves in a positive inline direction and negative block direction.
     // That means that the intervals will be reversed after all have been
     // constructed. We add 1 to aB to capture the end of the block axis pixel.
     origin.MoveBy(aIMin * aAppUnitsPerDevPixel, (aB + 1) * -aAppUnitsPerDevPixel);
-  } else if (aWM.IsVerticalLR() && aWM.IsSideways()) {
+  } else if (aWM.IsVerticalLR() && !aWM.IsLineInverted()) {
     // sideways-lr.
+    // Checking IsLineInverted is the only reliable way to distinguish
+    // vertical-lr from sideways-lr. IsSideways and IsInlineReversed are both
+    // affected by bidi and text-direction, and so complicate detection.
     // These writing modes proceed from the bottom left, and each interval
     // moves in a negative inline direction and a positive block direction.
     // We add 1 to aIMax to capture the end of the inline axis pixel.
     origin.MoveBy((aIMax + 1) * -aAppUnitsPerDevPixel, aB * aAppUnitsPerDevPixel);
   } else {
     // horizontal-tb or vertical-lr.
     // These writing modes proceed from the top left and each interval
     // moves in a positive step in both inline and block directions.
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3087,22 +3087,16 @@ struct HoveredStateComparator
 };
 
 void
 ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
                                        const nsDisplayListSet& aLists,
                                        bool                    aCreateLayer,
                                        bool                    aPositioned)
 {
-  nsITheme* theme = mOuter->PresContext()->GetTheme();
-  if (theme &&
-      theme->ShouldHideScrollbars()) {
-    return;
-  }
-
   bool overlayScrollbars =
     LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0;
 
   AutoTArray<nsIFrame*, 3> scrollParts;
   for (nsIFrame* kid : mOuter->PrincipalChildList()) {
     if (kid == mScrolledFrame ||
         (kid->IsAbsPosContainingBlock() || overlayScrollbars) != aPositioned) {
       continue;
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -339,18 +339,17 @@ public:
   nscolor GetTextColor();
 
   // SVG text has its own painting process, so we should never get its stroke
   // property from here.
   nscolor GetWebkitTextStrokeColor() {
     if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
       return 0;
     }
-    return mFrame->StyleColor()->
-      CalcComplexColor(mFrame->StyleText()->mWebkitTextStrokeColor);
+    return mFrame->StyleText()->mWebkitTextStrokeColor.CalcColor(mFrame);
   }
   float GetWebkitTextStrokeWidth() {
     if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
       return 0.0f;
     }
     nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
     return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
   }
@@ -5190,21 +5189,20 @@ void
 nsTextFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame");
 
-  const nsStyleColor* sc = StyleColor();
   const nsStyleText* st = StyleText();
   bool isTextTransparent =
-    NS_GET_A(sc->CalcComplexColor(st->mWebkitTextFillColor)) == 0 &&
-    NS_GET_A(sc->CalcComplexColor(st->mWebkitTextStrokeColor)) == 0;
+    NS_GET_A(st->mWebkitTextFillColor.CalcColor(this)) == 0 &&
+    NS_GET_A(st->mWebkitTextStrokeColor.CalcColor(this)) == 0;
   Maybe<bool> isSelected;
   if (((GetStateBits() & TEXT_NO_RENDERED_GLYPHS) ||
        (isTextTransparent && !StyleText()->HasTextShadow())) &&
       aBuilder->IsForPainting() && !nsSVGUtils::IsInSVGTextSubtree(this)) {
     isSelected.emplace(IsSelected());
     if (!isSelected.value()) {
       TextDecorations textDecs;
       GetTextDecorations(PresContext(), eResolvedColors, textDecs);
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -7,16 +7,17 @@
 
 #include "RetainedDisplayListBuilder.h"
 
 #include "DisplayListChecker.h"
 #include "gfxPrefs.h"
 #include "nsPlaceholderFrame.h"
 #include "nsSubDocumentFrame.h"
 #include "nsViewManager.h"
+#include "nsCanvasFrame.h"
 
 /**
  * Code for doing display list building for a modified subset of the window,
  * and then merging it into the existing display list (for the full window).
  *
  * The approach primarily hinges on the observation that the ‘true’ ordering of
  * display items is represented by a DAG (only items that intersect in 2d space
  * have a defined ordering). Our display list is just one of a many possible linear
@@ -661,25 +662,23 @@ HandlePreserve3D(nsIFrame* aFrame, nsRec
     CRR_LOG("HandlePreserve3D() Updated overflow rect to: %d %d %d %d\n",
              aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height);
   }
 
   return aFrame;
 }
 
 static void
-ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
-             AnimatedGeometryRoot** aAGR, nsRect& aOverflow,
-             nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
-             const bool aStopAtStackingContext)
+ProcessFrameInternal(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
+                     AnimatedGeometryRoot** aAGR, nsRect& aOverflow,
+                     nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
+                     const bool aStopAtStackingContext)
 {
   nsIFrame* currentFrame = aFrame;
 
-  aBuilder.MarkFrameForDisplayIfVisible(aFrame, aBuilder.RootReferenceFrame());
-
   while (currentFrame != aStopAtFrame) {
     CRR_LOG("currentFrame: %p (placeholder=%d), aOverflow: %d %d %d %d\n",
              currentFrame, !aStopAtStackingContext,
              aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height);
 
     currentFrame = HandlePreserve3D(currentFrame, aOverflow);
 
     // If the current frame is an OOF frame, DisplayListBuildingData needs to be
@@ -709,18 +708,18 @@ ProcessFrame(nsIFrame* aFrame, nsDisplay
 
       // Find a common ancestor frame to handle frame continuations.
       // TODO: It might be possible to write a more specific and efficient
       // function for this.
       nsIFrame* ancestor =
         nsLayoutUtils::FindNearestCommonAncestorFrame(currentFrame->GetParent(),
                                                       placeholder->GetParent());
 
-      ProcessFrame(placeholder, aBuilder, &dummyAGR, placeholderOverflow,
-                   ancestor, aOutFramesWithProps, false);
+      ProcessFrameInternal(placeholder, aBuilder, &dummyAGR, placeholderOverflow,
+                           ancestor, aOutFramesWithProps, false);
     }
 
     // Convert 'aOverflow' into the coordinate space of the nearest stacking context
     // or display port ancestor and update 'currentFrame' to point to that frame.
     aOverflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, aOverflow, aStopAtFrame,
                                                            nullptr, nullptr,
                                                            /* aStopAtStackingContextAndDisplayPortAndOOFFrame = */ true,
                                                            &currentFrame);
@@ -828,16 +827,112 @@ ProcessFrame(nsIFrame* aFrame, nsDisplay
       aOverflow.SetEmpty();
       *aAGR = nullptr;
 
       break;
     }
   }
 }
 
+bool
+RetainedDisplayListBuilder::ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
+             nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
+             const bool aStopAtStackingContext,
+             nsRect* aOutDirty,
+             AnimatedGeometryRoot** aOutModifiedAGR)
+{
+  if (aFrame->HasOverrideDirtyRegion()) {
+    aOutFramesWithProps.AppendElement(aFrame);
+  }
+
+  if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
+    return true;
+  }
+
+  // TODO: There is almost certainly a faster way of doing this, probably can be combined with the ancestor
+  // walk for TransformFrameRectToAncestor.
+  AnimatedGeometryRoot* agr = aBuilder.FindAnimatedGeometryRootFor(aFrame)->GetAsyncAGR();
+
+  CRR_LOG("Processing frame %p with agr %p\n", aFrame, agr->mFrame);
+
+  // Convert the frame's overflow rect into the coordinate space
+  // of the nearest stacking context that has an existing display item.
+  // We store that as a dirty rect on that stacking context so that we build
+  // all items that intersect the changed frame within the stacking context,
+  // and then we use MarkFrameForDisplayIfVisible to make sure the stacking
+  // context itself gets built. We don't need to build items that intersect outside
+  // of the stacking context, since we know the stacking context item exists in
+  // the old list, so we can trivially merge without needing other items.
+  nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
+
+  // If the modified frame is also a caret frame, include the caret area.
+  // This is needed because some frames (for example text frames without text)
+  // might have an empty overflow rect.
+  if (aFrame == aBuilder.GetCaretFrame()) {
+    overflow.UnionRect(overflow, aBuilder.GetCaretRect());
+  }
+
+  ProcessFrameInternal(aFrame, aBuilder, &agr, overflow, aStopAtFrame,
+                       aOutFramesWithProps, aStopAtStackingContext);
+
+  if (!overflow.IsEmpty()) {
+    aOutDirty->UnionRect(*aOutDirty, overflow);
+    CRR_LOG("Adding area to root draw area: %d %d %d %d\n",
+            overflow.x, overflow.y, overflow.width, overflow.height);
+
+    // If we get changed frames from multiple AGRS, then just give up as it gets really complex to
+    // track which items would need to be marked in MarkFramesForDifferentAGR.
+    if (!*aOutModifiedAGR) {
+      CRR_LOG("Setting %p as root stacking context AGR\n", agr);
+      *aOutModifiedAGR = agr;
+    } else if (agr && *aOutModifiedAGR != agr) {
+      CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
+      return false;
+    }
+  }
+  return true;
+}
+
+static void
+AddFramesForContainingBlock(nsIFrame* aBlock,
+                            const nsFrameList& aFrames,
+                            nsTArray<nsIFrame*>& aExtraFrames)
+{
+  for (nsIFrame* f : aFrames) {
+    if (!f->IsFrameModified() &&
+        AnyContentAncestorModified(f, aBlock)) {
+      CRR_LOG("Adding invalid OOF %p\n", f);
+      aExtraFrames.AppendElement(f);
+    }
+  }
+}
+
+// Placeholder descendants of aFrame don't contribute to aFrame's overflow area.
+// Find all the containing blocks that might own placeholders under us, walk
+// their OOF frames list, and manually invalidate any frames that are descendants
+// of a modified frame (us, or another frame we'll get to soon).
+// This is combined with the work required for MarkFrameForDisplayIfVisible,
+// so that we can avoid an extra ancestor walk, and we can reuse the flag
+// to detect when we've already visited an ancestor (and thus all further ancestors
+// must also be visited).
+void FindContainingBlocks(nsIFrame* aFrame,
+                          nsTArray<nsIFrame*>& aExtraFrames)
+{
+  for (nsIFrame* f = aFrame; f;
+       f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
+    if (f->ForceDescendIntoIfVisible())
+      return;
+    f->SetForceDescendIntoIfVisible(true);
+    CRR_LOG("Considering OOFs for %p\n", f);
+
+    AddFramesForContainingBlock(f, f->GetChildList(nsIFrame::kFloatList), aExtraFrames);
+    AddFramesForContainingBlock(f, f->GetChildList(f->GetAbsoluteListID()), aExtraFrames);
+  }
+}
+
 /**
  * Given a list of frames that has been modified, computes the region that we need to
  * do display list building for in order to build all modified display items.
  *
  * When a modified frame is within a stacking context (with an existing display item),
  * then we only contribute to the build area within the stacking context, as well as forcing
  * display list building to descend to the stacking context. We don't need to add build
  * area outside of the stacking context (and force items above/below the stacking context
@@ -861,67 +956,37 @@ ProcessFrame(nsIFrame* aFrame, nsDisplay
  */
 bool
 RetainedDisplayListBuilder::ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
                                                  nsRect* aOutDirty,
                                                  AnimatedGeometryRoot** aOutModifiedAGR,
                                                  nsTArray<nsIFrame*>& aOutFramesWithProps)
 {
   CRR_LOG("Computing rebuild regions for %zu frames:\n", aModifiedFrames.Length());
+  nsTArray<nsIFrame*> extraFrames;
   for (nsIFrame* f : aModifiedFrames) {
     MOZ_ASSERT(f);
 
-    if (f->HasOverrideDirtyRegion()) {
-      aOutFramesWithProps.AppendElement(f);
-    }
-
-    if (f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
-      continue;
-    }
-
-    // TODO: There is almost certainly a faster way of doing this, probably can be combined with the ancestor
-    // walk for TransformFrameRectToAncestor.
-    AnimatedGeometryRoot* agr = mBuilder.FindAnimatedGeometryRootFor(f)->GetAsyncAGR();
-
-    CRR_LOG("Processing frame %p with agr %p\n", f, agr->mFrame);
-
-    // Convert the frame's overflow rect into the coordinate space
-    // of the nearest stacking context that has an existing display item.
-    // We store that as a dirty rect on that stacking context so that we build
-    // all items that intersect the changed frame within the stacking context,
-    // and then we use MarkFrameForDisplayIfVisible to make sure the stacking
-    // context itself gets built. We don't need to build items that intersect outside
-    // of the stacking context, since we know the stacking context item exists in
-    // the old list, so we can trivially merge without needing other items.
-    nsRect overflow = f->GetVisualOverflowRectRelativeToSelf();
+    mBuilder.AddFrameMarkedForDisplayIfVisible(f);
+    FindContainingBlocks(f, extraFrames);
 
-    // If the modified frame is also a caret frame, include the caret area.
-    // This is needed because some frames (for example text frames without text)
-    // might have an empty overflow rect.
-    if (f == mBuilder.GetCaretFrame()) {
-      overflow.UnionRect(overflow, mBuilder.GetCaretRect());
+    if (!ProcessFrame(f, mBuilder, mBuilder.RootReferenceFrame(),
+                      aOutFramesWithProps, true,
+                      aOutDirty, aOutModifiedAGR)) {
+      return false;
     }
-
-    ProcessFrame(f, mBuilder, &agr, overflow, mBuilder.RootReferenceFrame(),
-                 aOutFramesWithProps, true);
+  }
 
-    if (!overflow.IsEmpty()) {
-      aOutDirty->UnionRect(*aOutDirty, overflow);
-      CRR_LOG("Adding area to root draw area: %d %d %d %d\n",
-              overflow.x, overflow.y, overflow.width, overflow.height);
+  for (nsIFrame* f : extraFrames) {
+    mBuilder.MarkFrameModifiedDuringBuilding(f);
 
-      // If we get changed frames from multiple AGRS, then just give up as it gets really complex to
-      // track which items would need to be marked in MarkFramesForDifferentAGR.
-      if (!*aOutModifiedAGR) {
-        CRR_LOG("Setting %p as root stacking context AGR\n", agr);
-        *aOutModifiedAGR = agr;
-      } else if (agr && *aOutModifiedAGR != agr) {
-        CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
-        return false;
-      }
+    if (!ProcessFrame(f, mBuilder, mBuilder.RootReferenceFrame(),
+                      aOutFramesWithProps, true,
+                      aOutDirty, aOutModifiedAGR)) {
+      return false;
     }
   }
 
   return true;
 }
 
 /*
  * A simple early exit heuristic to avoid slow partial display list rebuilds.
@@ -1050,16 +1115,26 @@ RetainedDisplayListBuilder::AttemptParti
       !ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
                            &modifiedAGR, framesWithProps.Frames()) ||
       !PreProcessDisplayList(&mList, modifiedAGR)) {
     mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), List());
     mList.ClearDAG();
     return PartialUpdateResult::Failed;
   }
 
+  // This is normally handled by EnterPresShell, but we skipped it so that we
+  // didn't call MarkFrameForDisplayIfVisible before ComputeRebuildRegion.
+  nsIScrollableFrame* sf = mBuilder.RootReferenceFrame()->PresShell()->GetRootScrollFrameAsScrollable();
+  if (sf) {
+    nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
+    if (canvasFrame) {
+      mBuilder.MarkFrameForDisplayIfVisible(canvasFrame, mBuilder.RootReferenceFrame());
+    }
+  }
+
   modifiedDirty.IntersectRect(modifiedDirty, mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf());
 
   PartialUpdateResult result = PartialUpdateResult::NoChange;
   if (!modifiedDirty.IsEmpty() ||
       !framesWithProps.IsEmpty()) {
     result = PartialUpdateResult::Updated;
   }
 
--- a/layout/painting/RetainedDisplayListBuilder.h
+++ b/layout/painting/RetainedDisplayListBuilder.h
@@ -54,16 +54,21 @@ private:
                          RetainedDisplayList* aOldList,
                          RetainedDisplayList* aOutList,
                          mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR);
 
   bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
                             nsRect* aOutDirty,
                             AnimatedGeometryRoot** aOutModifiedAGR,
                             nsTArray<nsIFrame*>& aOutFramesWithProps);
+  bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
+                    nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
+                    const bool aStopAtStackingContext,
+                    nsRect* aOutDirty,
+                    AnimatedGeometryRoot** aOutModifiedAGR);
 
   void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
 
   friend class MergeState;
 
   nsDisplayListBuilder mBuilder;
   RetainedDisplayList mList;
   WeakFrame mPreviousCaret;
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -795,19 +795,16 @@ ConstructBorderRenderer(nsPresContext* a
                         const nsRect& aDirtyRect,
                         const nsRect& aBorderArea,
                         const nsStyleBorder& aStyleBorder,
                         Sides aSkipSides,
                         bool* aNeedsClip)
 {
   nsMargin border = aStyleBorder.GetComputedBorder();
 
-  // Get our ComputedStyle's color struct.
-  const nsStyleColor* ourColor = aComputedStyle->StyleColor();
-
   // In NavQuirks mode we want to use the parent's context as a starting point
   // for determining the background color.
   bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
   nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(aForFrame, quirks);
   ComputedStyle* bgContext = bgFrame->Style();
   nscolor bgColor = bgContext->
     GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
 
@@ -856,17 +853,17 @@ ConstructBorderRenderer(nsPresContext* a
   Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);
 
   uint8_t borderStyles[4];
   nscolor borderColors[4];
 
   // pull out styles, colors
   NS_FOR_CSS_SIDES (i) {
     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
-    borderColors[i] = ourColor->CalcComplexColor(aStyleBorder.mBorderColor[i]);
+    borderColors[i] = aStyleBorder.mBorderColor[i].CalcColor(aComputedStyle);
   }
 
   PrintAsFormatString(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
 
   nsIDocument* document = nullptr;
   nsIContent* content = aForFrame->GetContent();
   if (content) {
     document = content->OwnerDoc();
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1076,19 +1076,25 @@ nsDisplayListBuilder::MarkFrameForDispla
     if (f == aStopAtFrame) {
       // we've reached a frame that we know will be painted, so we can stop.
       break;
     }
   }
 }
 
 void
-nsDisplayListBuilder::MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
+nsDisplayListBuilder::AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame)
 {
   mFramesMarkedForDisplayIfVisible.AppendElement(aFrame);
+}
+
+void
+nsDisplayListBuilder::MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
+{
+  AddFrameMarkedForDisplayIfVisible(aFrame);
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
     if (f->ForceDescendIntoIfVisible())
       return;
     f->SetForceDescendIntoIfVisible(true);
     if (f == aStopAtFrame) {
       // we've reached a frame that we know will be painted, so we can stop.
       break;
@@ -1289,23 +1295,26 @@ nsDisplayListBuilder::EnterPresShell(nsI
 {
   PresShellState* state = mPresShellStates.AppendElement();
   state->mPresShell = aReferenceFrame->PresShell();
   state->mCaretFrame = nullptr;
   state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
   state->mFirstFrameWithOOFData = mFramesWithOOFData.Length();
 
   nsIScrollableFrame* sf = state->mPresShell->GetRootScrollFrameAsScrollable();
-  if (sf) {
+  if (sf && IsInSubdocument()) {
     // We are forcing a rebuild of nsDisplayCanvasBackgroundColor to make sure
     // that the canvas background color will be set correctly, and that only one
     // unscrollable item will be created.
     // This is done to avoid, for example, a case where only scrollbar frames
     // are invalidated - we would skip creating nsDisplayCanvasBackgroundColor
     // and possibly end up with an extra nsDisplaySolidColor item.
+    // We skip this for the root document, since we don't want to use
+    // MarkFrameForDisplayIfVisible before ComputeRebuildRegion. We'll
+    // do it manually there.
     nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
     if (canvasFrame) {
       MarkFrameForDisplayIfVisible(canvasFrame, aReferenceFrame);
     }
   }
 
 #ifdef DEBUG
   state->mAutoLayoutPhase.emplace(aReferenceFrame->PresContext(), eLayoutPhase_DisplayListBuilding);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -894,16 +894,17 @@ public:
    * to ensure that display list construction descends into them
    * anyway. nsDisplayListBuilder will take care of unmarking them when it is
    * destroyed.
    */
   void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
                                 const nsFrameList& aFrames);
   void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame);
   void MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame);
+  void AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame);
 
   void ClearFixedBackgroundDisplayData();
   /**
    * Mark all child frames that Preserve3D() as needing display.
    * Because these frames include transforms set on their parent, dirty rects
    * for intermediate frames may be empty, yet child frames could still be visible.
    */
   void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame);
@@ -1470,34 +1471,16 @@ public:
       , mDirtyRect(aDirtyRect)
     {}
     const DisplayItemClipChain* mContainingBlockClipChain;
     const DisplayItemClipChain* mCombinedClipChain; // only necessary for the special case of top layer
     const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
     nsRect mVisibleRect;
     nsRect mDirtyRect;
 
-    static bool
-    AnyContentAncestorModified(nsIFrame* aFrame,
-                               nsIFrame* aStopAtFrame = nullptr)
-    {
-      for (nsIFrame* f = aFrame; f;
-           f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
-        if (f->IsFrameModified()) {
-          return true;
-        }
-
-        if (aStopAtFrame && f == aStopAtFrame) {
-          break;
-        }
-      }
-
-      return false;
-    }
-
     static nsRect ComputeVisibleRectForFrame(nsDisplayListBuilder* aBuilder,
                                              nsIFrame* aFrame,
                                              const nsRect& aVisibleRect,
                                              const nsRect& aDirtyRect,
                                              nsRect* aOutDirtyRect) {
       nsRect visible = aVisibleRect;
       nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
 
@@ -1533,23 +1516,16 @@ public:
         * prerendered if necessary.
         */
         overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
       }
 
       visible.IntersectRect(visible, overflowRect);
       aOutDirtyRect->IntersectRect(*aOutDirtyRect, overflowRect);
 
-      // If the nearest stacking context for the modified frame is an ancestor of
-      // of it, and if the stacking context is a descendant of the containing block
-      // of this OOF frame, we override the dirty rect to ensure that the frame will
-      // get marked.
-      if (AnyContentAncestorModified(aFrame, aFrame->GetParent())) {
-        *aOutDirtyRect = visible;
-      }
       return visible;
     }
 
     nsRect GetVisibleRectForFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                                   nsRect* aDirtyRect) {
       return ComputeVisibleRectForFrame(aBuilder, aFrame, mVisibleRect, mDirtyRect, aDirtyRect);
     }
   };
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1453541-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<body>
+
+<div id="empty" style="position:fixed; z-index: 4; left:200px; top:200px; width: 0px">
+  <div style="position:fixed; width:400px; height: 400px; background-color:green; top: 200px; left: 200px"></div>
+</div>
+<div style="width:400px; height: 400px; background-color:blue"></div>
+
+<script>
+  function doTest() {
+    document.getElementById("empty").style.left = "201px";
+    document.documentElement.removeAttribute("class");
+  }
+  document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1453541-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<body>
+
+<div id="empty" style="position:relative; z-index: 4; left:192px; top:192px; width: 0px">
+  <div style="position:fixed; width:400px; height: 400px; background-color:green; top: 200px; left: 200px"></div>
+</div>
+<div style="width:400px; height: 400px; background-color:blue"></div>
+
+<script>
+  function doTest() {
+    document.getElementById("empty").style.left = "193px";
+    document.documentElement.removeAttribute("class");
+  }
+  document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1453541-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<div id="empty" style="position:fixed; z-index: 4; left:200px; top:200px; width: 0px">
+  <div style="position:fixed; width:400px; height: 400px; background-color:green"></div>
+</div>
+<div style="width:400px; height: 400px; background-color:blue"></div>
+
+</body>
+</html>
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -23,9 +23,11 @@ needs-focus == 1429027-1.html 1429027-1-
 == 1432553-2.html 1432553-2-ref.html
 == 1436189-1.html 1436189-1-ref.html
 skip-if(!asyncPan) == 1437374-1.html 1437374-1-ref.html
 == 1439809-1.html 1439809-1-ref.html
 == 1443027-1.html 1443027-ref.html
 == 1443027-2.html 1443027-ref.html
 == 1443027-3.html 1443027-3-ref.html
 == 1451971-1.html 1451971-ref.html
+== 1453541-1.html 1453541-ref.html
+== 1453541-2.html 1453541-ref.html
 == 1452805-1.html 1452805-ref.html
--- a/layout/style/ComputedStyle.cpp
+++ b/layout/style/ComputedStyle.cpp
@@ -336,17 +336,17 @@ static nscolor
 ExtractColor(ComputedStyle* aStyle, const nscolor& aColor)
 {
   return aColor;
 }
 
 static nscolor
 ExtractColor(ComputedStyle* aStyle, const StyleComplexColor& aColor)
 {
-  return aStyle->StyleColor()->CalcComplexColor(aColor);
+  return aColor.CalcColor(aStyle);
 }
 
 static nscolor
 ExtractColor(ComputedStyle* aStyle, const nsStyleSVGPaint& aPaintServer)
 {
   return aPaintServer.Type() == eStyleSVGPaintType_Color
     ? aPaintServer.GetColor() : NS_RGBA(0, 0, 0, 0);
 }
new file mode 100644
--- /dev/null
+++ b/layout/style/StyleComplexColor.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/StyleComplexColor.h"
+
+#include "mozilla/ComputedStyle.h"
+#include "mozilla/ComputedStyleInlines.h"
+#include "nsIFrame.h"
+#include "nsStyleStruct.h"
+
+using namespace mozilla;
+
+static uint32_t
+BlendColorComponent(uint32_t aBg, uint32_t aFg, uint32_t aFgAlpha)
+{
+  return RoundingDivideBy255(aBg * (255 - aFgAlpha) + aFg * aFgAlpha);
+}
+
+// Blend one RGBA color with another based on a given ratio.
+// It is a linear interpolation on each channel with alpha premultipled.
+static nscolor
+LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio)
+{
+  // Common case that either pure background or pure foreground
+  if (aFgRatio == 0) {
+    return aBg;
+  }
+  if (aFgRatio == 255) {
+    return aFg;
+  }
+  // Common case that alpha channel is equal (usually both are opaque)
+  if (NS_GET_A(aBg) == NS_GET_A(aFg)) {
+    auto r = BlendColorComponent(NS_GET_R(aBg), NS_GET_R(aFg), aFgRatio);
+    auto g = BlendColorComponent(NS_GET_G(aBg), NS_GET_G(aFg), aFgRatio);
+    auto b = BlendColorComponent(NS_GET_B(aBg), NS_GET_B(aFg), aFgRatio);
+    return NS_RGBA(r, g, b, NS_GET_A(aFg));
+  }
+
+  constexpr float kFactor = 1.0f / 255.0f;
+
+  float p1 = kFactor * (255 - aFgRatio);
+  float a1 = kFactor * NS_GET_A(aBg);
+  float r1 = a1 * NS_GET_R(aBg);
+  float g1 = a1 * NS_GET_G(aBg);
+  float b1 = a1 * NS_GET_B(aBg);
+
+  float p2 = 1.0f - p1;
+  float a2 = kFactor * NS_GET_A(aFg);
+  float r2 = a2 * NS_GET_R(aFg);
+  float g2 = a2 * NS_GET_G(aFg);
+  float b2 = a2 * NS_GET_B(aFg);
+
+  float a = p1 * a1 + p2 * a2;
+  if (a == 0.0) {
+    return NS_RGBA(0, 0, 0, 0);
+  }
+
+  auto r = ClampColor((p1 * r1 + p2 * r2) / a);
+  auto g = ClampColor((p1 * g1 + p2 * g2) / a);
+  auto b = ClampColor((p1 * b1 + p2 * b2) / a);
+  return NS_RGBA(r, g, b, NSToIntRound(a * 255));
+}
+
+nscolor
+StyleComplexColor::CalcColor(mozilla::ComputedStyle* aStyle) const {
+  MOZ_ASSERT(aStyle);
+  auto foregroundColor = aStyle->StyleColor()->mColor;
+  return LinearBlendColors(mColor, foregroundColor, mForegroundRatio);
+}
+
+nscolor
+StyleComplexColor::CalcColor(const nsIFrame* aFrame) const {
+  return CalcColor(aFrame->Style());
+}
--- a/layout/style/StyleComplexColor.h
+++ b/layout/style/StyleComplexColor.h
@@ -6,18 +6,22 @@
 
 /* represent a color combines a numeric color and currentcolor */
 
 #ifndef mozilla_StyleComplexColor_h_
 #define mozilla_StyleComplexColor_h_
 
 #include "nsColor.h"
 
+class nsIFrame;
+
 namespace mozilla {
 
+class ComputedStyle;
+
 /**
  * This struct represents a combined color from a numeric color and
  * the current foreground color (currentcolor keyword).
  * Conceptually, the formula is "color * (1 - p) + currentcolor * p"
  * where p is mForegroundRatio. See mozilla::LinearBlendColors for
  * the actual algorithm.
  */
 struct StyleComplexColor
@@ -46,13 +50,25 @@ struct StyleComplexColor
   bool operator==(const StyleComplexColor& aOther) const {
     return mForegroundRatio == aOther.mForegroundRatio &&
            (IsCurrentColor() || mColor == aOther.mColor) &&
            mIsAuto == aOther.mIsAuto;
   }
   bool operator!=(const StyleComplexColor& aOther) const {
     return !(*this == aOther);
   }
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color from aStyle.
+   */
+  nscolor CalcColor(mozilla::ComputedStyle* aStyle) const;
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color from aFrame's ComputedStyle.
+   */
+  nscolor CalcColor(const nsIFrame* aFrame) const;
 };
 
 }
 
 #endif // mozilla_StyleComplexColor_h_
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -216,16 +216,17 @@ UNIFIED_SOURCES += [
     'ServoNamespaceRule.cpp',
     'ServoPageRule.cpp',
     'ServoSpecifiedValues.cpp',
     'ServoStyleRule.cpp',
     'ServoStyleSet.cpp',
     'ServoSupportsRule.cpp',
     'StreamLoader.cpp',
     'StyleAnimationValue.cpp',
+    'StyleComplexColor.cpp',
     'StyleSheet.cpp',
     'URLExtraData.cpp',
 ]
 
 SOURCES += [
     'nsCSSAnonBoxes.cpp',
     'nsCSSPseudoElements.cpp',
     # nsLayoutStylesheetCache.cpp uses nsExceptionHandler.h, which includes
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1183,17 +1183,17 @@ nsComputedDOMStyle::SetToRGBAColor(nsROC
 
   aValue->SetColor(rgbColor);
 }
 
 void
 nsComputedDOMStyle::SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
                                              const StyleComplexColor& aColor)
 {
-  SetToRGBAColor(aValue, StyleColor()->CalcComplexColor(aColor));
+  SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleColor()->mColor);
   return val.forget();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3367,17 +3367,17 @@ nsStyleBackground::BackgroundColor(const
 
 nscolor
 nsStyleBackground::BackgroundColor(mozilla::ComputedStyle* aStyle) const
 {
   // In majority of cases, background-color should just be a numeric color.
   // In that case, we can skip resolving StyleColor().
   return mBackgroundColor.IsNumericColor()
     ? mBackgroundColor.mColor
-    : aStyle->StyleColor()->CalcComplexColor(mBackgroundColor);
+    : mBackgroundColor.CalcColor(aStyle);
 }
 
 bool
 nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const
 {
   return IsTransparent(aFrame->Style());
 }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -517,21 +517,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   explicit nsStyleColor(const nsPresContext* aContext);
   nsStyleColor(const nsStyleColor& aOther);
   ~nsStyleColor() {
     MOZ_COUNT_DTOR(nsStyleColor);
   }
   void FinishStyle(nsPresContext*, const nsStyleColor*) {}
   const static bool kHasFinishStyle = false;
 
-  nscolor CalcComplexColor(const mozilla::StyleComplexColor& aColor) const {
-    return mozilla::LinearBlendColors(aColor.mColor, mColor,
-                                      aColor.mForegroundRatio);
-  }
-
   nsChangeHint CalcDifference(const nsStyleColor& aNewData) const;
 
   // Don't add ANY members to this struct!  We can achieve caching in the rule
   // tree (rather than the style tree) by letting color stay by itself! -dwh
   nscolor mColor;                 // [inherited]
 };
 
 struct nsStyleImageLayers {
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -422,18 +422,17 @@ nsTextBoxFrame::DrawText(gfxContext&    
       }
       const nsStyleTextReset* styleText = context->StyleTextReset();
 
       if (decorMask & styleText->mTextDecorationLine) {  // a decoration defined here
         nscolor color;
         if (aOverrideColor) {
           color = *aOverrideColor;
         } else {
-          color = context->StyleColor()->
-            CalcComplexColor(styleText->mTextDecorationColor);
+          color = styleText->mTextDecorationColor.CalcColor(context);
         }
         uint8_t style = styleText->mTextDecorationStyle;
 
         if (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE & decorMask &
               styleText->mTextDecorationLine) {
           underColor = color;
           underStyle = style;
           decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -3302,18 +3302,17 @@ nsTreeBodyFrame::PaintCell(int32_t      
                     twistyContext);
 
       nsMargin twistyMargin;
       twistyContext->StyleMargin()->GetMargin(twistyMargin);
       twistyRect.Inflate(twistyMargin);
 
       const nsStyleBorder* borderStyle = lineContext->StyleBorder();
       // Resolve currentcolor values against the treeline context
-      nscolor color = lineContext->StyleColor()->
-        CalcComplexColor(borderStyle->mBorderLeftColor);
+      nscolor color = borderStyle->mBorderLeftColor.CalcColor(lineContext);
       ColorPattern colorPatt(ToDeviceColor(color));
 
       uint8_t style = borderStyle->GetBorderStyle(eSideLeft);
       StrokeOptions strokeOptions;
       nsLayoutUtils::InitDashPattern(strokeOptions, style);
 
       nscoord srcX = currX + twistyRect.width - mIndentation / 2;
       nscoord lineY = (aRowIndex - mTopRowIndex) * mRowHeight + aPt.y;
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -111,29 +111,29 @@ MOZ_MTLOG_MODULE("mtransport")
 
 const char kNrIceTransportUdp[] = "udp";
 const char kNrIceTransportTcp[] = "tcp";
 const char kNrIceTransportTls[] = "tls";
 
 static bool initialized = false;
 
 // Implement NSPR-based crypto algorithms
-static int nr_crypto_nss_random_bytes(UCHAR *buf, int len) {
+static int nr_crypto_nss_random_bytes(UCHAR *buf, size_t len) {
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   if (!slot)
     return R_INTERNAL;
 
   SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), buf, len);
   if (rv != SECSuccess)
     return R_INTERNAL;
 
   return 0;
 }
 
-static int nr_crypto_nss_hmac(UCHAR *key, int keyl, UCHAR *buf, int bufl,
+static int nr_crypto_nss_hmac(UCHAR *key, size_t keyl, UCHAR *buf, size_t bufl,
                               UCHAR *result) {
   CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
   PK11SlotInfo *slot = nullptr;
   MOZ_ASSERT(keyl > 0);
   SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)};
   PK11SymKey *skey = nullptr;
   PK11Context *hmac_ctx = nullptr;
   SECStatus status;
@@ -175,17 +175,17 @@ static int nr_crypto_nss_hmac(UCHAR *key
  abort:
   if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
   if (skey) PK11_FreeSymKey(skey);
   if (slot) PK11_FreeSlot(slot);
 
   return err;
 }
 
-static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) {
+static int nr_crypto_nss_md5(UCHAR *buf, size_t bufl, UCHAR *result) {
   int err = R_INTERNAL;
   SECStatus rv;
 
   const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5);
   MOZ_ASSERT(ho);
   if (!ho)
     goto abort;
 
@@ -727,21 +727,21 @@ void NrIceCtx::internal_DeinitializeGlob
   initialized = false;
 }
 
 void NrIceCtx::internal_SetTimerAccelarator(int divider) {
   ctx_->test_timer_divider = divider;
 }
 
 void NrIceCtx::AccumulateStats(const NrIceStats& stats) {
-  nr_ice_accumulate_count(&(ctx_->stats.stun_retransmits),
-                          stats.stun_retransmits);
-  nr_ice_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s);
-  nr_ice_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s);
-  nr_ice_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s);
+  nr_accumulate_count(&(ctx_->stats.stun_retransmits),
+                      stats.stun_retransmits);
+  nr_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s);
+  nr_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s);
+  nr_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s);
 }
 
 NrIceStats NrIceCtx::Destroy() {
   // designed to be called more than once so if stats are desired, this can be
   // called just prior to the destructor
   MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'");
   for (auto& stream : streams_) {
     if (stream) {
--- a/media/mtransport/third_party/moz.build
+++ b/media/mtransport/third_party/moz.build
@@ -47,16 +47,18 @@ nICEr_non_unified_sources = [
     'nICEr/src/stun/stun_util.c',
     'nICEr/src/stun/turn_client_ctx.c',
     'nICEr/src/util/cb_args.c',
     'nICEr/src/util/ice_util.c',
 ]
 
 nrappkit_non_unified_sources = [
     'nrappkit/src/log/r_log.c',
+    'nrappkit/src/registry/registry.c',
+    'nrappkit/src/registry/registry_local.c',
     'nrappkit/src/util/byteorder.c',
     'nrappkit/src/util/hex.c',
     'nrappkit/src/util/libekr/debug.c',
     'nrappkit/src/util/libekr/r_assoc.c',
     'nrappkit/src/util/libekr/r_crc32.c',
     'nrappkit/src/util/libekr/r_data.c',
     'nrappkit/src/util/libekr/r_errors.c',
     'nrappkit/src/util/libekr/r_list.c',
@@ -64,19 +66,15 @@ nrappkit_non_unified_sources = [
     'nrappkit/src/util/libekr/r_replace.c',
     'nrappkit/src/util/libekr/r_time.c',
     'nrappkit/src/util/p_buf.c',
     'nrappkit/src/util/util.c',
 ]
 
 GYP_DIRS['nICEr'].input = 'nICEr/nicer.gyp'
 GYP_DIRS['nICEr'].variables = gyp_vars_copy
-# We allow warnings for third-party code that can be updated from upstream.
-GYP_DIRS['nICEr'].sandbox_vars['COMPILE_FLAGS'] = {'WARNINGS_AS_ERRORS': []}
 GYP_DIRS['nICEr'].sandbox_vars['FINAL_LIBRARY'] = 'xul'
 GYP_DIRS['nICEr'].non_unified_sources += nICEr_non_unified_sources
 
 GYP_DIRS['nrappkit'].input = 'nrappkit/nrappkit.gyp'
 GYP_DIRS['nrappkit'].variables = gyp_vars_copy
-# We allow warnings for third-party code that can be updated from upstream.
-GYP_DIRS['nrappkit'].sandbox_vars['COMPILE_FLAGS'] = {'WARNINGS_AS_ERRORS': []}
 GYP_DIRS['nrappkit'].sandbox_vars['FINAL_LIBRARY'] = 'xul'
 GYP_DIRS['nrappkit'].non_unified_sources += nrappkit_non_unified_sources
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -12,25 +12,25 @@
   'targets' : [
       {
           'target_name' : 'nicer',
           'type' : 'static_library',
 
           'include_dirs' : [
               ## EXTERNAL
               # nrappkit
-	      '../nrappkit/src/event',
-	      '../nrappkit/src/log',
+              '../nrappkit/src/event',
+              '../nrappkit/src/log',
               '../nrappkit/src/plugin',
-	      '../nrappkit/src/registry',
-	      '../nrappkit/src/share',
-	      '../nrappkit/src/stats',
-	      '../nrappkit/src/util',
-	      '../nrappkit/src/util/libekr',
- 	      '../nrappkit/src/port/generic/include',
+              '../nrappkit/src/registry',
+              '../nrappkit/src/share',
+              '../nrappkit/src/stats',
+              '../nrappkit/src/util',
+              '../nrappkit/src/util/libekr',
+              '../nrappkit/src/port/generic/include',
 
               # INTERNAL
               "./src/crypto",
               "./src/ice",
               "./src/net",
               "./src/stun",
               "./src/util",
           ],
@@ -128,23 +128,23 @@
               'USE_TURN',
               'USE_ICE',
               'USE_RFC_3489_BACKWARDS_COMPATIBLE',
               'USE_STUND_0_96',
               'USE_STUN_PEDANTIC',
               'USE_TURN',
               'NR_SOCKET_IS_VOID_PTR',
               'restrict=',
-	      'R_PLATFORM_INT_TYPES=<stdint.h>',
-	      'R_DEFINED_INT2=int16_t',
-	      'R_DEFINED_UINT2=uint16_t',
-	      'R_DEFINED_INT4=int32_t',
-	      'R_DEFINED_UINT4=uint32_t',
-	      'R_DEFINED_INT8=int64_t',
-	      'R_DEFINED_UINT8=uint64_t',
+              'R_PLATFORM_INT_TYPES=<stdint.h>',
+              'R_DEFINED_INT2=int16_t',
+              'R_DEFINED_UINT2=uint16_t',
+              'R_DEFINED_INT4=int32_t',
+              'R_DEFINED_UINT4=uint32_t',
+              'R_DEFINED_INT8=int64_t',
+              'R_DEFINED_UINT8=uint64_t',
           ],
 
           'conditions' : [
               ## Mac and BSDs
               [ 'OS == "mac" or OS == "ios"', {
                 'defines' : [
                     'DARWIN',
                 ],
@@ -170,43 +170,45 @@
                      'HAVE_SYS_TIME_H=1',
                      'HAVE_VFPRINTF=1',
                      'NEW_STDIO'
                      'RETSIGTYPE=void',
                      'TIME_WITH_SYS_TIME_H=1',
                      '__UNUSED__=__attribute__((unused))',
                  ],
 
-		 'include_dirs': [
-		     '../nrappkit/src/port/darwin/include'
-		 ],
+                 'include_dirs': [
+                     '../nrappkit/src/port/darwin/include'
+                 ],
 
-		 'sources': [
-		 ],
+                 'sources': [
+                 ],
               }],
 
               ## Win
               [ 'OS == "win"', {
                 'defines' : [
                     'WIN32',
+                    '_WINSOCK_DEPRECATED_NO_WARNINGS',
                     'USE_ICE',
                     'USE_TURN',
                     'USE_RFC_3489_BACKWARDS_COMPATIBLE',
                     'USE_STUND_0_96',
                     'USE_STUN_PEDANTIC',
                     '_CRT_SECURE_NO_WARNINGS',
                     '__UNUSED__=',
                     'HAVE_STRDUP',
                     'NO_REG_RPC'
                 ],
 
-		 'include_dirs': [
-		     '../nrappkit/src/port/win32/include'
-		 ],
+                 'include_dirs': [
+                     '../nrappkit/src/port/win32/include'
+                 ],
               }],
+
               ## Linux/Android
               [ '(OS == "linux") or (OS=="android")', {
                 'cflags_mozilla': [
                     '-Wall',
                     '-Wno-parentheses',
                     '-Wno-strict-prototypes',
                     '-Wmissing-prototypes',
                     '-Wno-format',
@@ -220,22 +222,22 @@
                      'HAVE_SYS_TIME_H=1',
                      'HAVE_VFPRINTF=1',
                      'NEW_STDIO'
                      'RETSIGTYPE=void',
                      'TIME_WITH_SYS_TIME_H=1',
                      '__UNUSED__=__attribute__((unused))',
                  ],
 
-		 'include_dirs': [
-		     '../nrappkit/src/port/linux/include'
-		 ],
+                 'include_dirs': [
+                     '../nrappkit/src/port/linux/include'
+                 ],
 
-		 'sources': [
-		 ],
+                 'sources': [
+                 ],
              }],
              ['have_ethtool_cmd_speed_hi==0', {
                'defines': [
                   "DONT_HAVE_ETHTOOL_SPEED_HI",
                ]
              }],
         ['libfuzzer == 1', {
           'cflags_mozilla': [
--- a/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.c
+++ b/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.c
@@ -32,31 +32,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 
 
 static char *RCSSTRING __UNUSED__="$Id: nr_crypto.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
 
 #include <nr_api.h>
 #include "nr_crypto.h"
 
-static int nr_ice_crypto_dummy_random_bytes(UCHAR *buf, int len)
+static int nr_ice_crypto_dummy_random_bytes(UCHAR *buf, size_t len)
   {
     fprintf(stderr,"Need to define crypto API implementation\n");
 
     exit(1);
   }
 
-static int nr_ice_crypto_dummy_hmac_sha1(UCHAR *key, int key_l, UCHAR *buf, int buf_l, UCHAR digest[20])
+static int nr_ice_crypto_dummy_hmac_sha1(UCHAR *key, size_t key_l, UCHAR *buf, size_t buf_l, UCHAR digest[20])
   {
     fprintf(stderr,"Need to define crypto API implementation\n");
 
     exit(1);
   }
 
-static int nr_ice_crypto_dummy_md5(UCHAR *buf, int buf_l, UCHAR digest[16])
+static int nr_ice_crypto_dummy_md5(UCHAR *buf, size_t buf_l, UCHAR digest[16])
   {
     fprintf(stderr,"Need to define crypto API implementation\n");
 
     exit(1);
   }
 
 static nr_ice_crypto_vtbl nr_ice_crypto_dummy_vtbl= {
   nr_ice_crypto_dummy_random_bytes,
--- a/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.h
+++ b/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.h
@@ -32,19 +32,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 
 
 #ifndef _nr_crypto_h
 #define _nr_crypto_h
 
 
 typedef struct nr_ice_crypto_vtbl_ {
-  int (*random_bytes)(UCHAR *buf, int len);
-  int (*hmac_sha1)(UCHAR *key, int key_l, UCHAR *buf, int buf_l, UCHAR digest[20]);
-  int (*md5)(UCHAR *buf, int buf_l, UCHAR digest[16]);
+  int (*random_bytes)(UCHAR *buf, size_t len);
+  int (*hmac_sha1)(UCHAR *key, size_t key_l, UCHAR *buf, size_t buf_l, UCHAR digest[20]);
+  int (*md5)(UCHAR *buf, size_t buf_l, UCHAR digest[16]);
 } nr_ice_crypto_vtbl;
 
 extern nr_ice_crypto_vtbl *nr_crypto_vtbl;
 
 #define nr_crypto_random_bytes(a,b) nr_crypto_vtbl->random_bytes(a,b)
 #define nr_crypto_hmac_sha1(a,b,c,d,e) nr_crypto_vtbl->hmac_sha1(a,b,c,d,e)
 #define nr_crypto_md5(a,b,c) nr_crypto_vtbl->md5(a,b,c)
 
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -318,24 +318,24 @@ int nr_ice_candidate_destroy(nr_ice_cand
 
     switch(cand->type){
       case HOST:
         break;
 #ifdef USE_TURN
       case RELAYED:
         // record stats back to the ice ctx on destruction
         if (cand->u.relayed.turn) {
-          nr_ice_accumulate_count(&(cand->ctx->stats.turn_401s), cand->u.relayed.turn->cnt_401s);
-          nr_ice_accumulate_count(&(cand->ctx->stats.turn_403s), cand->u.relayed.turn->cnt_403s);
-          nr_ice_accumulate_count(&(cand->ctx->stats.turn_438s), cand->u.relayed.turn->cnt_438s);
+          nr_accumulate_count(&(cand->ctx->stats.turn_401s), cand->u.relayed.turn->cnt_401s);
+          nr_accumulate_count(&(cand->ctx->stats.turn_403s), cand->u.relayed.turn->cnt_403s);
+          nr_accumulate_count(&(cand->ctx->stats.turn_438s), cand->u.relayed.turn->cnt_438s);
 
           nr_turn_stun_ctx* stun_ctx;
           stun_ctx = STAILQ_FIRST(&cand->u.relayed.turn->stun_ctxs);
           while (stun_ctx) {
-            nr_ice_accumulate_count(&(cand->ctx->stats.stun_retransmits), stun_ctx->stun->retransmit_ct);
+            nr_accumulate_count(&(cand->ctx->stats.stun_retransmits), stun_ctx->stun->retransmit_ct);
 
             stun_ctx = STAILQ_NEXT(stun_ctx, entry);
           }
         }
         if (cand->u.relayed.turn_handle)
           nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
         if (cand->u.relayed.srvflx_candidate)
           cand->u.relayed.srvflx_candidate->u.srvrflx.relay_candidate=0;
@@ -375,17 +375,19 @@ static int nr_ice_get_foundation(nr_ice_
     int i=0;
     char fnd[20];
     int _status;
 
     foundation=STAILQ_FIRST(&ctx->foundations);
     while(foundation){
       if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
         goto next;
-      if(cand->type != foundation->type)
+      // cast necessary because there is no guarantee that enum is signed.
+      // foundation->type should probably match nr_ice_candidate_type
+      if((int)cand->type != foundation->type)
         goto next;
       if(cand->stun_server != foundation->stun_server)
         goto next;
 
       snprintf(fnd,sizeof(fnd),"%d",i);
       if(!(cand->foundation=r_strdup(fnd)))
         ABORT(R_NO_MEMORY);
       return(0);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
@@ -149,17 +149,17 @@ int nr_ice_candidate_pair_destroy(nr_ice
     if(!pairp || !*pairp)
       return(0);
 
     pair=*pairp;
     *pairp=0;
 
     // record stats back to the ice ctx on destruction
     if (pair->stun_client) {
-      nr_ice_accumulate_count(&(pair->local->ctx->stats.stun_retransmits), pair->stun_client->retransmit_ct);
+      nr_accumulate_count(&(pair->local->ctx->stats.stun_retransmits), pair->stun_client->retransmit_ct);
     }
 
     RFREE(pair->as_string);
     RFREE(pair->foundation);
     nr_ice_socket_deregister(pair->local->isock,pair->stun_client_handle);
     if (pair->stun_client) {
       RFREE(pair->stun_client->params.ice_binding_request.username);
       RFREE(pair->stun_client->params.ice_binding_request.password.data);
@@ -352,16 +352,22 @@ static void nr_ice_candidate_pair_stun_c
         if(r!=R_NOT_FOUND)
           ABORT(r);
       }
     }
 
   done:
     _status=0;
   abort:
+    if (_status) {
+      // cb doesn't return anything, but we should probably log that we aborted
+      // This also quiets the unused variable warnings.
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s): STUN cb pair addr = %s abort with status: %d",
+        pair->pctx->label,pair->local->stream->label,pair->codeword,pair->as_string, _status);
+    }
     return;
   }
 
 static void nr_ice_candidate_pair_restart(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
   {
     int r,_status;
     UINT4 mode;
 
@@ -638,16 +644,22 @@ void nr_ice_candidate_pair_restart_stun_
     if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_USE_CANDIDATE,nr_ice_candidate_pair_stun_cb,pair))
       ABORT(r);
 
     if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))
       ABORT(r);
 
     _status=0;
   abort:
+    if (_status) {
+      // cb doesn't return anything, but we should probably log that we aborted
+      // This also quiets the unused variable warnings.
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s)/COMP(%d): STUN nominated cb pair as nominated: %s abort with status: %d",
+        pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string, _status);
+    }
     return;
   }
 
 static void nr_ice_candidate_pair_restart_stun_role_change_cb(NR_SOCKET s, int how, void *cb_arg)
  {
     nr_ice_cand_pair *pair=cb_arg;
 
     pair->restart_role_change_cb_timer=0;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -46,20 +46,26 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "nr_socket_turn.h"
 #include "nr_socket_wrapper.h"
 #include "nr_socket_buffered_stun.h"
 #include "nr_socket_multi_tcp.h"
 #include "ice_reg.h"
 #include "nr_crypto.h"
 #include "r_time.h"
 
+static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg);
 static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error);
 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
+int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote);
+int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right);
+void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp);
 void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp);
-void nr_ice_component_consent_destroy(nr_ice_component *comp);
+int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg);
+int nr_ice_component_setup_consent(nr_ice_component *comp);
+int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free);
 
 /* This function takes ownership of the contents of req (but not req itself) */
 static int nr_ice_pre_answer_request_create(nr_transport_addr *dst, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
   {
     int r, _status;
     nr_ice_pre_answer_request *par = 0;
     nr_stun_message_attribute *attr;
 
@@ -808,17 +814,17 @@ static int nr_ice_component_handle_trigg
      * would not get the nomination status cloned with it.*/
     if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
       *error=(r==R_NO_MEMORY)?500:400;
       ABORT(r);
     }
 
     _status=0;
   abort:
-    return(r);
+    return(_status);
   }
 
 /* Section 7.2.1 */
 static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
   {
     nr_ice_cand_pair *pair;
     nr_ice_candidate *pcand=0;
     nr_stun_message *sreq=req->request;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -93,15 +93,16 @@ int nr_ice_component_service_pre_answer_
 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_check_if_failed(nr_ice_component *comp);
 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
 int nr_ice_component_set_failed(nr_ice_component *comp);
 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
 int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
+void nr_ice_component_consent_destroy(nr_ice_component *comp);
 void nr_ice_component_refresh_consent_now(nr_ice_component *comp);
 void nr_ice_component_disconnected(nr_ice_component *comp);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -684,17 +684,17 @@ static int nr_ice_get_default_local_addr
       }
     }
 
     // if default addr is not in local addrs, just copy the transport addr
     // to output arg.
     if (i == addr_ct) {
       if ((r=nr_transport_addr_copy(&addrp->addr, &default_addr)))
         ABORT(r);
-      strlcpy(addrp->addr.ifname, "default route", sizeof(addrp->addr.ifname));
+      (void)strlcpy(addrp->addr.ifname, "default route", sizeof(addrp->addr.ifname));
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_ice_set_local_addresses(nr_ice_ctx *ctx,
@@ -909,17 +909,17 @@ int nr_ice_get_global_attributes(nr_ice_
       RFREE(attrs);
     }
     return(_status);
   }
 
 static int nr_ice_random_string(char *str, int len)
   {
     unsigned char bytes[100];
-    int needed;
+    size_t needed;
     int r,_status;
 
     if(len%2) ABORT(R_BAD_ARGS);
     needed=len/2;
 
     if(needed>sizeof(bytes)) ABORT(R_BAD_ARGS);
 
     if(r=nr_crypto_random_bytes(bytes,needed))
@@ -1082,22 +1082,8 @@ int nr_ice_get_new_ice_pwd(char** pwd)
     _status=0;
   abort:
     if(_status) {
       RFREE(*pwd);
       *pwd = 0;
     }
     return(_status);
   }
-
-#ifndef UINT2_MAX
-#define UINT2_MAX ((UINT2)(65535U))
-#endif
-
-void nr_ice_accumulate_count(UINT2* orig_count, UINT2 new_count)
-  {
-    if (UINT2_MAX - new_count < *orig_count) {
-      // don't rollover, just stop accumulating at MAX value
-      *orig_count = UINT2_MAX;
-    } else {
-      *orig_count += new_count;
-    }
-  }
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -194,18 +194,16 @@ int nr_ice_ctx_copy_turn_servers(nr_ice_
 int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver);
 int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *prioritizer);
 int nr_ice_ctx_set_turn_tcp_socket_wrapper(nr_ice_ctx *ctx, nr_socket_wrapper_factory *wrapper);
 void nr_ice_ctx_set_socket_factory(nr_ice_ctx *ctx, nr_socket_factory *factory);
 int nr_ice_ctx_set_trickle_cb(nr_ice_ctx *ctx, nr_ice_trickle_candidate_cb cb, void *cb_arg);
 int nr_ice_ctx_hide_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
 int nr_ice_get_new_ice_ufrag(char** ufrag);
 int nr_ice_get_new_ice_pwd(char** pwd);
-// accumulate a count without worrying about rollover
-void nr_ice_accumulate_count(UINT2* orig_count, UINT2 new_count);
 
 #define NR_ICE_MAX_ATTRIBUTE_SIZE 256
 
 extern int LOG_ICE;
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -371,16 +371,22 @@ static void nr_ice_media_stream_check_ti
       NR_ASYNC_TIMER_SET(timer_val,nr_ice_media_stream_check_timer_cb,cb_arg,&stream->timer);
     }
     else {
       r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): no pairs for %s",stream->pctx->label,stream->label);
     }
 
     _status=0;
   abort:
+    if (_status) {
+      // cb doesn't return anything, but we should probably log that we aborted
+      // This also quiets the unused variable warnings.
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): check timer cb for media stream %s abort with status: %d",
+        stream->pctx->label,stream->label, _status);
+    }
     return;
   }
 
 /* Start checks for this media stream (aka check list) */
 int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
   {
     int r,_status;
 
@@ -559,18 +565,18 @@ int nr_ice_media_stream_dump_state(nr_ic
   }
 
 int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state)
   {
     /* Make no-change a no-op */
     if (state == str->ice_state)
       return 0;
 
-    assert(state < sizeof(nr_ice_media_stream_states)/sizeof(char *));
-    assert(str->ice_state < sizeof(nr_ice_media_stream_states)/sizeof(char *));
+    assert((size_t)state < sizeof(nr_ice_media_stream_states)/sizeof(char *));
+    assert((size_t)str->ice_state < sizeof(nr_ice_media_stream_states)/sizeof(char *));
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): stream %s state %s->%s",
       str->pctx->label,str->label,
       nr_ice_media_stream_states[str->ice_state],
       nr_ice_media_stream_states[state]);
 
     if(state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE)
       str->pctx->active_streams++;
--- a/media/mtransport/third_party/nICEr/src/net/nr_socket.h
+++ b/media/mtransport/third_party/nICEr/src/net/nr_socket.h
@@ -44,16 +44,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #endif
 
 #include "transport_addr.h"
 #include "csi_platform.h"
 
 #ifdef __cplusplus
 #define restrict
 #elif defined(WIN32)
+/* Undef before defining to avoid a compiler warning */
+#undef restrict
 #define restrict __restrict
 #endif
 
 typedef enum {
   TCP_TYPE_NONE=0,
   TCP_TYPE_ACTIVE,
   TCP_TYPE_PASSIVE,
   TCP_TYPE_SO,
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -532,17 +532,17 @@ nr_transport_addr_mask nr_private_ipv4_a
 };
 
 int nr_transport_addr_get_private_addr_range(nr_transport_addr *addr)
   {
     switch(addr->ip_version){
       case NR_IPV4:
         {
           UINT4 ip = ntohl(addr->u.addr4.sin_addr.s_addr);
-          for (int i=0; i<(sizeof(nr_private_ipv4_addrs)/sizeof(nr_transport_addr_mask)); i++) {
+          for (size_t i=0; i<(sizeof(nr_private_ipv4_addrs)/sizeof(nr_transport_addr_mask)); i++) {
             if ((ip & nr_private_ipv4_addrs[i].mask) == nr_private_ipv4_addrs[i].addr)
               return i + 1;
           }
         }
         break;
       case NR_IPV6:
         return(0);
       default:
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
@@ -109,18 +109,19 @@ nr_reg_get_transport_addr(NR_registry pr
             ABORT(R_BAD_DATA);
     }
 
     if (!keep) memset(addr, 0, sizeof(*addr));
 
     if ((r=nr_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
         ABORT(r);
 
-    if (ifname)
-        strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
+    if (ifname) {
+        (void)strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
+    }
 
     _status=0;
   abort:
     RFREE(protocol);
     RFREE(ifname);
     RFREE(address);
     return(_status);
 }
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.c
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.c
@@ -322,17 +322,17 @@ stun_getifaddrs(nr_local_addr addrs[], i
             {
                addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
                /* TODO (Bug 896913): find backend network type of this VPN */
             }
 #else
             addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
             addrs[*count].interface.estimated_speed = 0;
 #endif
-            strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
+            (void)strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
             ++(*count);
           }
           break;
         default:
           ;
       }
     }
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_build.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_build.c
@@ -303,17 +303,17 @@ nr_stun_build_req_ice(nr_stun_client_ice
 
    Per RFC 5389 S 15.4
 */
 int
 nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm,
                                               Data *password, Data *hmac_key)
 {
   char digest_input[1000];
-  int i;
+  size_t i;
   int r, _status;
   size_t len;
 
   /* First check that the password is ASCII. We are supposed to
      SASLprep but we don't support this yet
      TODO(ekr@rtfm.com): Add SASLprep for password.
  */
   for (i=0; i<password->len; i++) {
--- a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
@@ -248,32 +248,38 @@ static void nr_stun_client_timer_expired
         ctx->state=NR_STUN_CLIENT_STATE_TIMED_OUT;
         ABORT(R_FAILED);
     }
 
     if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
         ABORT(R_NOT_PERMITTED);
 
     // track retransmits for ice telemetry
-    nr_ice_accumulate_count(&(ctx->retransmit_ct), 1);
+    nr_accumulate_count(&(ctx->retransmit_ct), 1);
 
     /* as a side effect will reset the timer */
     nr_stun_client_send_request(ctx);
 
     _status = 0;
   abort:
     if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
         /* Cancel the timer firing */
         if (ctx->timer_handle){
             NR_async_timer_cancel(ctx->timer_handle);
             ctx->timer_handle=0;
         }
 
         nr_stun_client_fire_finished_cb(ctx);
     }
+    if (_status) {
+      // cb doesn't return anything, but we should probably log that we aborted
+      // This also quiets the unused variable warnings.
+      r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired cb abort with status: %d",
+        ctx->label, _status);
+    }
     return;
   }
 
 int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx)
   {
     int r,_status;
 
     if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
--- a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.h
@@ -162,17 +162,17 @@ struct nr_stun_client_ctx_ {
   nr_transport_addr peer_addr;
   nr_socket *sock;
   nr_stun_client_auth_params auth_params;
   nr_stun_client_params params;
   nr_stun_client_results results;
   char *nonce;
   char *realm;
   void *timer_handle;
-  int request_ct;
+  UINT2 request_ct;
   UINT2 retransmit_ct;
   UINT4 rto_ms;    /* retransmission time out */
   double retransmission_backoff_factor;
   UINT4 maximum_transmits;
   UINT4 maximum_transmits_timeout_ms;
   UINT4 mapped_addr_check_mask;  /* What checks to run on mapped addresses */
   int timeout_ms;
   struct timeval timer_set;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -57,153 +57,153 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #define NR_STUN_IPV6_FAMILY  0x02
 
 #define SKIP_ATTRIBUTE_DECODE -1
 
 static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info);
 
 static int nr_stun_fix_attribute_ordering(nr_stun_message *msg);
 
-static int nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset);
-static int nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset);
-static int nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset);
-static int nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset);
+static int nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset);
 
-static int nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data);
-static int nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data);
-static int nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data);
-static int nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data);
+static int nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data);
+static int nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data);
+static int nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data);
+static int nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data);
 
-static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars);
+static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars);
 
-static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
-static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
-static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
-static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
-static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
+static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
 static int
-nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data);
+nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data);
 
 
 int
-nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset)
+nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset)
 {
    UINT2 d = htons(data);
 
    if (*offset + sizeof(d) >= buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd >= %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&buf[*offset], &d, sizeof(d));
    *offset += sizeof(d);
 
    return 0;
 }
 
 int
-nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset)
+nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset)
 {
    UINT4 d = htonl(data);
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&buf[*offset], &d, sizeof(d));
    *offset += sizeof(d);
 
    return 0;
 }
 
 int
-nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
+nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset)
 {
    UINT8 d = nr_htonll(data);
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&buf[*offset], &d, sizeof(d));
    *offset += sizeof(d);
 
    return 0;
 }
 
 int
-nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset)
+nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset)
 {
    if (*offset + length > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&buf[*offset], data, length);
    *offset += length;
 
    return 0;
 }
 
 
 int
-nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data)
+nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data)
 {
    UINT2 d;
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&d, &buf[*offset], sizeof(d));
    *offset += sizeof(d);
    *data = htons(d);
 
    return 0;
 }
 
 int
-nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data)
+nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data)
 {
    UINT4 d;
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&d, &buf[*offset], sizeof(d));
    *offset += sizeof(d);
    *data = htonl(d);
 
    return 0;
 }
 
 int
-nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data)
+nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data)
 {
    UINT8 d;
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&d, &buf[*offset], sizeof(d));
    *offset += sizeof(d);
    *data = nr_htonll(d);
 
    return 0;
 }
 
 int
-nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data)
+nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data)
 {
    if (*offset + length > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
       return R_BAD_DATA;
    }
 
    memcpy(data, &buf[*offset], length);
    *offset += length;
@@ -232,107 +232,105 @@ nr_count_utf8_code_points_without_valida
             ++nchars;
         }
         ++s;
     }
     return nchars;
 }
 
 int
-nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars)
+nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars)
 {
     int _status;
     char *s = data;
     size_t nchars;
 
     if (len > max_bytes) {
         r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %d bytes", attr_info->name, len);
         ABORT(R_FAILED);
     }
 
-    if (max_chars >= 0) {
-        nchars = nr_count_utf8_code_points_without_validation(s);
-        if (nchars > max_chars) {
-            r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %zd characters", attr_info->name, nchars);
-            ABORT(R_FAILED);
-        }
+    nchars = nr_count_utf8_code_points_without_validation(s);
+    if (nchars > max_chars) {
+        r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %zd characters", attr_info->name, nchars);
+        ABORT(R_FAILED);
     }
 
     _status = 0;
   abort:
     return _status;
 }
 
 int
-nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
+nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
 {
     int r,_status;
     nr_stun_attr_error_code *ec = data;
 
     if (ec->number < 300 || ec->number > 699)
         ABORT(R_FAILED);
 
     if ((r=nr_stun_attr_string_illegal(attr_info, strlen(ec->reason), ec->reason, NR_STUN_MAX_ERROR_CODE_REASON_BYTES, NR_STUN_MAX_ERROR_CODE_REASON_CHARS)))
         ABORT(r);
 
     _status = 0;
   abort:
     return _status;
 }
 
 int
-nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
+nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
 {
     return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_NONCE_BYTES, NR_STUN_MAX_NONCE_CHARS);
 }
 
 int
-nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
+nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
 {
     return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_REALM_BYTES, NR_STUN_MAX_REALM_CHARS);
 }
 
 int
-nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
+nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
 {
     return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_SERVER_BYTES, NR_STUN_MAX_SERVER_CHARS);
 }
 
 int
-nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
+nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
 {
     return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_USERNAME_BYTES, -1);
 }
 
 static int
 nr_stun_attr_codec_UCHAR_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UCHAR*)data);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
     UINT4 tmp = *((UCHAR *)data);
     tmp <<= 24;
 
     if (nr_stun_encode_htons(attr_info->type    , buflen, buf, &offset)
      || nr_stun_encode_htons(sizeof(UINT4)      , buflen, buf, &offset)
      || nr_stun_encode_htonl(tmp                , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     UINT4 tmp;
 
     if (attrlen != sizeof(UINT4)) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
         return R_FAILED;
     }
 
@@ -354,32 +352,32 @@ nr_stun_attr_codec nr_stun_attr_codec_UC
 static int
 nr_stun_attr_codec_UINT4_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UINT4*)data);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
 
     if (nr_stun_encode_htons(attr_info->type    , buflen, buf, &offset)
      || nr_stun_encode_htons(sizeof(UINT4)      , buflen, buf, &offset)
      || nr_stun_encode_htonl(*(UINT4*)data      , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     if (attrlen != sizeof(UINT4)) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
         return R_FAILED;
     }
 
     if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data))
         return R_FAILED;
@@ -397,32 +395,32 @@ nr_stun_attr_codec nr_stun_attr_codec_UI
 static int
 nr_stun_attr_codec_UINT8_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %llu", msg, attr_info->name, *(UINT8*)data);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
 
     if (nr_stun_encode_htons(attr_info->type   , buflen, buf, &offset)
      || nr_stun_encode_htons(sizeof(UINT8)     , buflen, buf, &offset)
      || nr_stun_encode_htonll(*(UINT8*)data    , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     if (attrlen != sizeof(UINT8)) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
         return R_FAILED;
     }
 
     if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data))
         return R_FAILED;
@@ -440,17 +438,17 @@ nr_stun_attr_codec nr_stun_attr_codec_UI
 static int
 nr_stun_attr_codec_addr_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", msg, attr_info->name, ((nr_transport_addr*)data)->as_string);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int r,_status;
     int start = offset;
     nr_transport_addr *addr = data;
     UCHAR pad = '\0';
     UCHAR family;
 
     if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset)))
@@ -486,17 +484,17 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
     *attrlen = offset - start;
 
     _status = 0;
   abort:
     return _status;
 }
 
 static int
-nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     UCHAR pad;
     UCHAR family;
     UINT2 port;
     UINT4 addr4;
     struct in6_addr addr6;
     nr_transport_addr *result = data;
@@ -556,33 +554,33 @@ static int
 nr_stun_attr_codec_data_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     nr_stun_attr_data *d = data;
     r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)d->data, d->length);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     nr_stun_attr_data *d = data;
     int start = offset;
 
     if (nr_stun_encode_htons(attr_info->type     , buflen, buf, &offset)
      || nr_stun_encode_htons(d->length           , buflen, buf, &offset)
      || nr_stun_encode(d->data, d->length        , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     nr_stun_attr_data *result = data;
 
     /* -1 because it is going to be null terminated just to be safe */
     if (attrlen >= (sizeof(result->data) - 1)) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Too much data: %d bytes", attrlen);
         ABORT(R_FAILED);
@@ -612,17 +610,17 @@ nr_stun_attr_codec_error_code_print(nr_s
     nr_stun_attr_error_code *error_code = data;
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %d %s",
                           msg, attr_info->name, error_code->number,
                           error_code->reason);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     nr_stun_attr_error_code *error_code = data;
     int start = offset;
     int length = strlen(error_code->reason);
     UCHAR pad[2] = { 0 };
     UCHAR class = error_code->number / 100;
     UCHAR number = error_code->number % 100;
 
@@ -635,24 +633,24 @@ nr_stun_attr_codec_error_code_encode(nr_
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     nr_stun_attr_error_code *result = data;
     UCHAR pad[2];
     UCHAR class;
     UCHAR number;
-    int size_reason;
+    size_t size_reason;
 
     if (nr_stun_decode(2, buf, buflen, &offset, pad)
      || nr_stun_decode(1, buf, buflen, &offset, &class)
      || nr_stun_decode(1, buf, buflen, &offset, &number))
         ABORT(R_FAILED);
 
     result->number = (class * 100) + number;
 
@@ -685,17 +683,17 @@ static int
 nr_stun_attr_codec_fingerprint_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     nr_stun_attr_fingerprint *fingerprint = data;
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %08x", msg, attr_info->name, fingerprint->checksum);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     UINT4 checksum;
     nr_stun_attr_fingerprint *fingerprint = data;
     nr_stun_message_header *header = (nr_stun_message_header*)buf;
 
     /* the length must include the FINGERPRINT attribute when computing
      * the fingerprint */
     header->length = ntohs(header->length);
@@ -711,22 +709,22 @@ nr_stun_attr_codec_fingerprint_encode(nr
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum);
 
     fingerprint->valid = 1;
     return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
 }
 
 static int
-nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int r,_status;
     nr_stun_attr_fingerprint *fingerprint = data;
     nr_stun_message_header *header = (nr_stun_message_header*)buf;
-    int length;
+    size_t length;
     UINT4 checksum;
 
     if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
         ABORT(r);
 
     offset -= 4; /* rewind to before the length and type fields */
 
     /* the length must include the FINGERPRINT attribute when computing
@@ -768,31 +766,31 @@ nr_stun_attr_codec nr_stun_attr_codec_fi
 static int
 nr_stun_attr_codec_flag_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: on", msg, attr_info->name);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
 
     if (nr_stun_encode_htons(attr_info->type  , buflen, buf, &offset)
      || nr_stun_encode_htons(0                , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     if (attrlen != 0) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Illegal flag length: %d", attrlen);
         return R_FAILED;
     }
 
     return 0;
 }
@@ -839,17 +837,17 @@ nr_stun_compute_message_integrity(UCHAR 
 
     _status=0;
  abort:
     header->length = hold;
     return _status;
 }
 
 static int
-nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
     nr_stun_attr_message_integrity *integrity = data;
 
     if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash))
         return R_FAILED;
 
     if (nr_stun_encode_htons(attr_info->type                         , buflen, buf, &offset)
@@ -858,17 +856,17 @@ nr_stun_attr_codec_message_integrity_enc
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     int start;
     nr_stun_attr_message_integrity *result = data;
     UCHAR computedHMAC[20];
 
     result->valid = 0;
 
@@ -904,17 +902,17 @@ nr_stun_attr_codec_message_integrity_dec
 nr_stun_attr_codec nr_stun_attr_codec_message_integrity = {
     "message_integrity",
     nr_stun_attr_codec_message_integrity_print,
     nr_stun_attr_codec_message_integrity_encode,
     nr_stun_attr_codec_message_integrity_decode
 };
 
 static int
-nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     return SKIP_ATTRIBUTE_DECODE;
 }
 
 nr_stun_attr_codec nr_stun_attr_codec_noop = {
     "NOOP",
     0,  /* ignore, never print these attributes */
     0,  /* ignore, never encode these attributes */
@@ -925,25 +923,25 @@ static int
 nr_stun_attr_codec_quoted_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
                           msg, attr_info->name, (char*)data);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
 //TODO: !nn! syntax check, conversion if not quoted already?
 //We'll just restrict this in the API -- EKR
     return nr_stun_attr_codec_string.encode(attr_info, data, offset, buflen, buf, attrlen);
 }
 
 static int
-nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
 //TODO: !nn! I don't see any need to unquote this but we may
 //find one later -- EKR
     return nr_stun_attr_codec_string.decode(attr_info, attrlen, buf, offset, buflen, data);
 }
 
 nr_stun_attr_codec nr_stun_attr_codec_quoted_string = {
     "quoted_string",
@@ -956,34 +954,34 @@ static int
 nr_stun_attr_codec_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
 {
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
                           msg, attr_info->name, (char*)data);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int start = offset;
     char *str = data;
     int length = strlen(str);
 
     if (nr_stun_encode_htons(attr_info->type  , buflen, buf, &offset)
      || nr_stun_encode_htons(length           , buflen, buf, &offset)
      || nr_stun_encode((UCHAR*)str, length    , buflen, buf, &offset))
         return R_FAILED;
 
     *attrlen = offset - start;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     char *result = data;
 
     /* actual enforcement of the specific string size happens elsewhere */
     if (attrlen >= NR_STUN_MAX_STRING_SIZE) {
         r_log(NR_LOG_STUN, LOG_WARNING, "String is too large: %d bytes", attrlen);
         ABORT(R_FAILED);
@@ -1028,17 +1026,17 @@ nr_stun_attr_codec_unknown_attributes_pr
         strlcat(str, type, sizeof(str));
     }
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s", str);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     int _status;
     int start = offset;
     nr_stun_attr_unknown_attributes *unknown_attributes = data;
     int length = (2 * unknown_attributes->num_attributes);
     int i;
 
     if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) {
@@ -1058,17 +1056,17 @@ nr_stun_attr_codec_unknown_attributes_en
     *attrlen = offset - start;
 
     _status = 0;
   abort:
     return _status;
 }
 
 static int
-nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int _status;
     nr_stun_attr_unknown_attributes *unknown_attributes = data;
     int i;
     UINT2 *a;
 
     if ((attrlen % 4) != 0) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Attribute is illegal size: %d", attrlen);
@@ -1107,17 +1105,17 @@ nr_stun_attr_codec_xor_mapped_address_pr
     r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s (unmasked) %s (masked)",
                           msg, attr_info->name,
                           xor_mapped_address->unmasked.as_string,
                           xor_mapped_address->masked.as_string);
     return 0;
 }
 
 static int
-nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
+nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
 {
     nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
     nr_stun_message_header *header = (nr_stun_message_header*)buf;
     UINT4 magic_cookie;
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     /* this needs to be the magic cookie in the header and not
@@ -1132,17 +1130,17 @@ nr_stun_attr_codec_xor_mapped_address_en
 
     if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
         return R_FAILED;
 
     return 0;
 }
 
 static int
-nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
+nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
 {
     int r,_status;
     nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
     nr_stun_message_header *header = (nr_stun_message_header*)buf;
     UINT4 magic_cookie;
 
     if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked)))
         ABORT(r);
@@ -1234,17 +1232,17 @@ static nr_stun_attr_info attrs[] = {
 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
 };
 
 
 int
 nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
 {
     int _status;
-    int i;
+    size_t i;
 
     *info = 0;
     for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) {
         if (type == attrs[i].type) {
             *info = &attrs[i];
             break;
         }
     }
@@ -1273,16 +1271,23 @@ nr_stun_fix_attribute_ordering(nr_stun_m
     if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &fingerprint)) {
         TAILQ_REMOVE(&msg->attributes, fingerprint, entry);
         TAILQ_INSERT_TAIL(&msg->attributes, fingerprint, entry);
     }
 
     return 0;
 }
 
+// Since this sanity check is only a collection of assert statements and those
+// assert statements are compiled out in non-debug builds, undef SANITY_CHECKS
+// so we can avoid the warning that padding_bytes is never used in opt builds.
+#ifdef NDEBUG
+#undef SANITY_CHECKS
+#endif
+
 #ifdef SANITY_CHECKS
 static void sanity_check_encoding_stuff(nr_stun_message *msg)
 {
     nr_stun_message_attribute *attr = 0;
     int padding_bytes;
     int l;
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Starting to sanity check encoding");
@@ -1302,18 +1307,18 @@ static void sanity_check_encoding_stuff(
 }
 #endif /* SANITY_CHECKS */
 
 
 int
 nr_stun_encode_message(nr_stun_message *msg)
 {
     int r,_status;
-    int length_offset;
-    int length_offset_hold;
+    size_t length_offset;
+    size_t length_offset_hold;
     nr_stun_attr_info *attr_info;
     nr_stun_message_attribute *attr;
     int padding_bytes;
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Encoding STUN message");
 
     nr_stun_fix_attribute_ordering(msg);
 
@@ -1466,17 +1471,17 @@ nr_stun_decode_message(nr_stun_message *
         attr->length            = ntohs(attr->encoding->length);
         attr->encoding_length   = attr->length + 4;
 
         if ((attr->length % 4) != 0) {
             padding_bytes = 4 - (attr->length % 4);
             attr->encoding_length += padding_bytes;
         }
 
-        if ((attr->encoding_length) > size) {
+        if ((attr->encoding_length) > (size_t)size) {
            r_log(NR_LOG_STUN, LOG_WARNING, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size);
            ABORT(R_FAILED);
         }
 
         if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
             if (attr->type <= 0x7FFF)
                 ++msg->comprehension_required_unknown_attributes;
             else
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.h
@@ -37,25 +37,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 #include "stun_msg.h"
 
 typedef struct nr_stun_attr_info_  nr_stun_attr_info;
 
 typedef struct nr_stun_attr_codec_ {
     char     *name;
     int     (*print)(nr_stun_attr_info *attr_info, char *msg, void *data);
-    int     (*encode)(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen);
-    int     (*decode)(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data);
+    int     (*encode)(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen);
+    int     (*decode)(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data);
 } nr_stun_attr_codec;
 
 struct nr_stun_attr_info_ {
      UINT2                 type;
      char                 *name;
      nr_stun_attr_codec   *codec;
-     int                 (*illegal)(nr_stun_attr_info *attr_info, int attrlen, void *data);
+     int                 (*illegal)(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
 };
 
 extern nr_stun_attr_codec nr_stun_attr_codec_UINT4;
 extern nr_stun_attr_codec nr_stun_attr_codec_UINT8;
 extern nr_stun_attr_codec nr_stun_attr_codec_addr;
 extern nr_stun_attr_codec nr_stun_attr_codec_bytes;
 extern nr_stun_attr_codec nr_stun_attr_codec_data;
 extern nr_stun_attr_codec nr_stun_attr_codec_error_code;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_hint.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_hint.c
@@ -50,17 +50,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "stun.h"
 
 
 /* returns 0 if it's not a STUN message
  *         1 if it's likely to be a STUN message
  *         2 if it's super likely to be a STUN message
  *         3 if it really is a STUN message */
 int
-nr_is_stun_message(UCHAR *buf, int len)
+nr_is_stun_message(UCHAR *buf, size_t len)
 {
    const UINT4 cookie = htonl(NR_STUN_MAGIC_COOKIE);
    const UINT4 cookie2 = htonl(NR_STUN_MAGIC_COOKIE2);
 #if 0
    nr_stun_message msg;
 #endif
    UINT2 type;
    nr_stun_encoded_attribute* attr;
@@ -158,51 +158,51 @@ nr_is_stun_message(UCHAR *buf, int len)
 
    /* and the fingerprint is good, so it's gotta be a STUN message */
 #endif
 
    return 3;
 }
 
 int
-nr_is_stun_request_message(UCHAR *buf, int len)
+nr_is_stun_request_message(UCHAR *buf, size_t len)
 {
    UINT2 type;
 
    if (sizeof(nr_stun_message_header) > len)
        return 0;
 
    if (!nr_is_stun_message(buf, len))
        return 0;
 
    memcpy(&type, buf, 2);
    type = ntohs(type);
 
    return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_REQUEST;
 }
 
 int
-nr_is_stun_indication_message(UCHAR *buf, int len)
+nr_is_stun_indication_message(UCHAR *buf, size_t len)
 {
    UINT2 type;
 
    if (sizeof(nr_stun_message_header) > len)
        return 0;
 
    if (!nr_is_stun_message(buf, len))
        return 0;
 
    memcpy(&type, buf, 2);
    type = ntohs(type);
 
    return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_INDICATION;
 }
 
 int
-nr_is_stun_response_message(UCHAR *buf, int len)
+nr_is_stun_response_message(UCHAR *buf, size_t len)
 {
    UINT2 type;
 
    if (sizeof(nr_stun_message_header) > len)
        return 0;
 
    if (!nr_is_stun_message(buf, len))
        return 0;
@@ -210,17 +210,17 @@ nr_is_stun_response_message(UCHAR *buf, 
    memcpy(&type, buf, 2);
    type = ntohs(type);
 
    return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_RESPONSE
        || NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_ERROR_RESPONSE;
 }
 
 int
-nr_has_stun_cookie(UCHAR *buf, int len)
+nr_has_stun_cookie(UCHAR *buf, size_t len)
 {
    static UINT4 cookie;
 
    cookie = htonl(NR_STUN_MAGIC_COOKIE);
 
    if (sizeof(nr_stun_message_header) > len)
        return 0;
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_hint.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_hint.h
@@ -29,16 +29,16 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 
 #ifndef _stun_hint_h
 #define _stun_hint_h
 
-int nr_is_stun_message(UCHAR *buf, int len);
-int nr_is_stun_request_message(UCHAR *buf, int len);
-int nr_is_stun_response_message(UCHAR *buf, int len);
-int nr_is_stun_indication_message(UCHAR *buf, int len);
-int nr_has_stun_cookie(UCHAR *buf, int len);
+int nr_is_stun_message(UCHAR *buf, size_t len);
+int nr_is_stun_request_message(UCHAR *buf, size_t len);
+int nr_is_stun_response_message(UCHAR *buf, size_t len);
+int nr_is_stun_indication_message(UCHAR *buf, size_t len);
+int nr_has_stun_cookie(UCHAR *buf, size_t len);
 int nr_stun_message_length(UCHAR *buf, int len, int *length);
 
 #endif
--- a/media/mtransport/third_party/nICEr/src/stun/stun_msg.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_msg.c
@@ -64,17 +64,17 @@ nr_stun_message_create(nr_stun_message *
     *msg = m;
 
     _status=0;
   abort:
     return(_status);
 }
 
 int
-nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, int length)
+nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, size_t length)
 {
     int r,_status;
     nr_stun_message *m = 0;
 
     if (length > sizeof(m->buffer)) {
         ABORT(R_BAD_DATA);
     }
 
@@ -204,17 +204,17 @@ NR_STUN_MESSAGE_ADD_ATTRIBUTE(
 )
 
 int
 nr_stun_message_add_error_code_attribute(nr_stun_message *msg, UINT2 number, char *reason)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_ERROR_CODE,
     {
         attr->u.error_code.number = number;
-        strlcpy(attr->u.error_code.reason, reason, sizeof(attr->u.error_code.reason));
+        (void)strlcpy(attr->u.error_code.reason, reason, sizeof(attr->u.error_code.reason));
     }
 )
 
 int
 nr_stun_message_add_fingerprint_attribute(nr_stun_message *msg)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_FINGERPRINT,
     {}
@@ -232,45 +232,45 @@ NR_STUN_MESSAGE_ADD_ATTRIBUTE(
         attr->u.message_integrity.passwordlen = password->len;
     }
 )
 
 int
 nr_stun_message_add_nonce_attribute(nr_stun_message *msg, char *nonce)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_NONCE,
-    { strlcpy(attr->u.nonce, nonce, sizeof(attr->u.nonce)); }
+    { (void)strlcpy(attr->u.nonce, nonce, sizeof(attr->u.nonce)); }
 )
 
 int
 nr_stun_message_add_realm_attribute(nr_stun_message *msg, char *realm)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_REALM,
-    { strlcpy(attr->u.realm, realm, sizeof(attr->u.realm)); }
+    { (void)strlcpy(attr->u.realm, realm, sizeof(attr->u.realm)); }
 )
 
 int
 nr_stun_message_add_server_attribute(nr_stun_message *msg, char *server_name)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_SERVER,
-    { strlcpy(attr->u.server_name, server_name, sizeof(attr->u.server_name)); }
+    { (void)strlcpy(attr->u.server_name, server_name, sizeof(attr->u.server_name)); }
 )
 
 int
 nr_stun_message_add_unknown_attributes_attribute(nr_stun_message *msg, nr_stun_attr_unknown_attributes *unknown_attributes)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_UNKNOWN_ATTRIBUTES,
     { memcpy(&attr->u.unknown_attributes, unknown_attributes, sizeof(attr->u.unknown_attributes)); }
 )
 
 int
 nr_stun_message_add_username_attribute(nr_stun_message *msg, char *username)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_USERNAME,
-    { strlcpy(attr->u.username, username, sizeof(attr->u.username)); }
+    { (void)strlcpy(attr->u.username, username, sizeof(attr->u.username)); }
 )
 
 int
 nr_stun_message_add_requested_transport_attribute(nr_stun_message *msg, UCHAR protocol)
 NR_STUN_MESSAGE_ADD_ATTRIBUTE(
     NR_STUN_ATTR_REQUESTED_TRANSPORT,
     { attr->u.requested_transport = protocol; }
 )
--- a/media/mtransport/third_party/nICEr/src/stun/stun_msg.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_msg.h
@@ -82,17 +82,17 @@ typedef struct nr_stun_attr_unknown_attr
 
 typedef struct nr_stun_attr_xor_mapped_address_ {
         nr_transport_addr               masked;
         nr_transport_addr               unmasked;
 } nr_stun_attr_xor_mapped_address;
 
 typedef struct nr_stun_attr_data_ {
     UCHAR  data[NR_STUN_MAX_MESSAGE_SIZE];
-    int    length;
+    size_t length;
 } nr_stun_attr_data;
 
 
 typedef struct nr_stun_encoded_attribute_ {
     UINT2                               type;
     UINT2                               length;
     UCHAR                               value[NR_STUN_MAX_MESSAGE_SIZE];
 } nr_stun_encoded_attribute;
@@ -132,17 +132,17 @@ typedef struct nr_stun_message_attribute
         UINT4                           change_request;
 #endif /* USE_STUND_0_96 */
 
         /* make sure there's enough room here to place any possible
          * attribute */
         UCHAR                           largest_possible_attribute[NR_STUN_MAX_MESSAGE_SIZE];
     } u;
     nr_stun_encoded_attribute          *encoding;
-    int                                 encoding_length;
+    size_t                              encoding_length;
     char                               *name;
     char                               *type_name;
     int                                 invalid;
     TAILQ_ENTRY(nr_stun_message_attribute_)  entry;
 } nr_stun_message_attribute;
 
 typedef TAILQ_HEAD(nr_stun_message_attribute_head_,nr_stun_message_attribute_) nr_stun_message_attribute_head;
 
@@ -151,25 +151,25 @@ typedef struct nr_stun_message_header_ {
     UINT2                               length;
     UINT4                               magic_cookie;
     UINT12                              id;
 } nr_stun_message_header;
 
 typedef struct nr_stun_message_ {
     char                               *name;
     UCHAR                               buffer[NR_STUN_MAX_MESSAGE_SIZE];
-    int                                 length;
+    size_t                              length;
     nr_stun_message_header              header;
     int                                 comprehension_required_unknown_attributes;
     int                                 comprehension_optional_unknown_attributes;
     nr_stun_message_attribute_head      attributes;
 } nr_stun_message;
 
 int nr_stun_message_create(nr_stun_message **msg);
-int nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, int length);
+int nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, size_t length);
 int nr_stun_message_destroy(nr_stun_message **msg);
 
 int nr_stun_message_attribute_create(nr_stun_message *msg, nr_stun_message_attribute **attr);
 int nr_stun_message_attribute_destroy(nr_stun_message *msg, nr_stun_message_attribute **attr);
 
 int nr_stun_message_has_attribute(nr_stun_message *msg, UINT2 type, nr_stun_message_attribute **attribute);
 
 int nr_stun_message_add_alternate_server_attribute(nr_stun_message *msg, nr_transport_addr *alternate_server);
--- a/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
@@ -381,28 +381,20 @@ int nr_stun_server_process_request(nr_st
     }
 
     return(_status);
   }
 
 static int nr_stun_server_send_response(nr_stun_server_ctx *ctx, nr_socket *sock, nr_transport_addr *peer_addr, nr_stun_message *res, nr_stun_server_client *clnt)
   {
     int r,_status;
-    Data *hmacPassword;
     char string[256];
 
     r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(label=%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);
 
-    if (clnt) {
-        hmacPassword = &clnt->password;
-    }
-    else {
-        hmacPassword = 0;
-    }
-
     if ((r=nr_stun_encode_message(res))) {
         /* should never happen */
         r_log(NR_LOG_STUN,LOG_ERR,"STUN-SERVER(label=%s): Unable to encode message", ctx->label);
     }
     else {
         snprintf(string, sizeof(string)-1, "STUN(%s): Sending to %s ", ctx->label, peer_addr->as_string);
         r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)res->buffer, res->length);
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.c
@@ -89,17 +89,17 @@ nr_stun_xor_mapped_address(UINT4 magicCo
             UINT4 addr32[4];
           } maskedAddr;
 
           maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
           memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
 
           /* We now have the mask in network byte order */
           /* Xor the address in network byte order */
-          for (int i = 0; i < sizeof(maskedAddr); ++i) {
+          for (size_t i = 0; i < sizeof(maskedAddr); ++i) {
             maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
           }
 
           nr_ip6_port_to_transport_addr(
               (struct in6_addr*)&maskedAddr,
               (ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
               from->protocol, to);
         }
@@ -201,34 +201,34 @@ nr_stun_find_local_addresses(nr_local_ad
 
      _status=0;
  abort:
      //RFREE(children);
      return _status;
 }
 
 int
-nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req)
+nr_stun_different_transaction(UCHAR *msg, size_t len, nr_stun_message *req)
 {
     int _status;
     nr_stun_message_header header;
     char reqid[44];
     char msgid[44];
-    int len2;
+    size_t unused;
 
     if (sizeof(header) > len)
         ABORT(R_FAILED);
 
     assert(sizeof(header.id) == sizeof(UINT12));
 
     memcpy(&header, msg, sizeof(header));
 
     if (memcmp(&req->header.id, &header.id, sizeof(header.id))) {
-        nr_nbin2hex((UCHAR*)&req->header.id, sizeof(req->header.id), reqid, sizeof(reqid), &len2);
-        nr_nbin2hex((UCHAR*)&header.id, sizeof(header.id), msgid, sizeof(msgid), &len2);
+        nr_nbin2hex((UCHAR*)&req->header.id, sizeof(req->header.id), reqid, sizeof(reqid), &unused);
+        nr_nbin2hex((UCHAR*)&header.id, sizeof(header.id), msgid, sizeof(msgid), &unused);
         r_log(NR_LOG_STUN, LOG_DEBUG, "Mismatched message IDs %s/%s", reqid, msgid);
         ABORT(R_NOT_FOUND);
     }
 
    _status=0;
  abort:
    return _status;
 }
@@ -334,8 +334,22 @@ nr_random_alphanum(char *alphanum, int s
     nr_crypto_random_bytes((UCHAR*)alphanum, size);
 
     /* now convert from binary to alphanumeric */
     for (i = 0; i < size; ++i)
         alphanum[i] = alphanums[(UCHAR)alphanum[i]];
 
     return 0;
 }
+
+#ifndef UINT2_MAX
+#define UINT2_MAX ((UINT2)(65535U))
+#endif
+
+void nr_accumulate_count(UINT2* orig_count, UINT2 add_count)
+  {
+    if (UINT2_MAX - add_count < *orig_count) {
+      // don't rollover, just stop accumulating at MAX value
+      *orig_count = UINT2_MAX;
+    } else {
+      *orig_count += add_count;
+    }
+  }
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.h
@@ -44,16 +44,19 @@ int nr_stun_startup(void);
 
 int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
 
 // removes duplicates, and based on prefs, loopback and link_local addresses
 int nr_stun_filter_local_addresses(nr_local_addr addrs[], int *count);
 
 int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);
 
-int nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req);
+int nr_stun_different_transaction(UCHAR *msg, size_t len, nr_stun_message *req);
 
 char* nr_stun_msg_type(int type);
 
 int nr_random_alphanum(char *alphanum, int size);
 
+// accumulate a count without worrying about rollover
+void nr_accumulate_count(UINT2* orig_count, UINT2 add_count);
+
 #endif
 
--- a/media/mtransport/third_party/nICEr/src/stun/turn_client_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/turn_client_ctx.c
@@ -252,23 +252,23 @@ static void nr_turn_stun_ctx_cb(NR_SOCKE
     case NR_STUN_CLIENT_STATE_FAILED:
       /* Special case: if this is an authentication error,
          we retry once. This allows the 401/438 nonce retry
          paradigm. After that, we fail */
       /* TODO(ekr@rtfm.com): 401 needs a #define */
       /* TODO(ekr@rtfm.com): Add alternate-server (Mozilla bug 857688) */
       if (ctx->stun->error_code == 438) {
         // track 438s for ice telemetry
-        nr_ice_accumulate_count(&(ctx->tctx->cnt_438s), 1);
+        nr_accumulate_count(&(ctx->tctx->cnt_438s), 1);
       }
       if (ctx->stun->error_code == 401 || ctx->stun->error_code == 438) {
         if (ctx->retry_ct > 0) {
           if (ctx->stun->error_code == 401) {
             // track 401s for ice telemetry
-            nr_ice_accumulate_count(&(ctx->tctx->cnt_401s), 1);
+            nr_accumulate_count(&(ctx->tctx->cnt_401s), 1);
           }
           r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Exceeded the number of retries", ctx->tctx->label);
           ABORT(R_FAILED);
         }
 
         if (!ctx->stun->nonce) {
           r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no nonce", ctx->tctx->label);
           ABORT(R_FAILED);
@@ -610,17 +610,17 @@ static void nr_turn_client_error_cb(NR_S
 }
 
 static void nr_turn_client_permission_error_cb(NR_SOCKET s, int how, void *arg)
 {
   nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
 
   if (ctx->last_error_code == 403) {
     // track 403s for ice telemetry
-    nr_ice_accumulate_count(&(ctx->tctx->cnt_403s), 1);
+    nr_accumulate_count(&(ctx->tctx->cnt_403s), 1);
     r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, permission denied",
           ctx->tctx->label, ctx->mode);
 
   } else{
     nr_turn_client_error_cb(0, 0, ctx);
   }
 }
 
--- a/media/mtransport/third_party/nrappkit/nrappkit.gyp
+++ b/media/mtransport/third_party/nrappkit/nrappkit.gyp
@@ -3,42 +3,42 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 #
 # nrappkit.gyp
 #
 #
 {
   'targets' : [
       {
-        	'target_name' : 'nrappkit',
+          'target_name' : 'nrappkit',
           'type' : 'static_library',
 
           'include_dirs' : [
               # EXTERNAL
               # INTERNAL
-	      'src/event',
-	      'src/log',
+              'src/event',
+              'src/log',
               'src/port/generic/include',
-	      'src/registry',
-	      'src/share',
-	      'src/stats',
-	      'src/util',
-	      'src/util/libekr',
+              'src/registry',
+              'src/share',
+              'src/stats',
+              'src/util',
+              'src/util/libekr',
           ],
 
           'sources' : [
-	      # Shared
+              # Shared
 #              './src/share/nr_api.h',
               './src/share/nr_common.h',
 #              './src/share/nr_dynlib.h',
               './src/share/nr_reg_keys.h',
 #              './src/share/nr_startup.c',
 #              './src/share/nr_startup.h',
 #              './src/share/nrappkit_static_plugins.c',
-	       './src/port/generic/include'
+               './src/port/generic/include'
 
               # libekr
               './src/util/libekr/assoc.h',
               './src/util/libekr/debug.c',
               './src/util/libekr/debug.h',
               './src/util/libekr/r_assoc.c',
               './src/util/libekr/r_assoc.h',
 #              './src/util/libekr/r_assoc_test.c',
@@ -59,52 +59,52 @@
               './src/util/libekr/r_replace.c',
               './src/util/libekr/r_thread.h',
               './src/util/libekr/r_time.c',
               './src/util/libekr/r_time.h',
               './src/util/libekr/r_types.h',
               './src/util/libekr/debug.c',
               './src/util/libekr/debug.h',
 
-	      # Utilities
+              # Utilities
               './src/util/byteorder.c',
               './src/util/byteorder.h',
               #'./src/util/escape.c',
               #'./src/util/escape.h',
               #'./src/util/filename.c',
               #'./src/util/getopt.c',
               #'./src/util/getopt.h',
               './src/util/hex.c',
               './src/util/hex.h',
-	      #'./src/util/mem_util.c',
+              #'./src/util/mem_util.c',
               #'./src/util/mem_util.h',
               #'./src/util/mutex.c',
               #'./src/util/mutex.h',
               './src/util/p_buf.c',
               './src/util/p_buf.h',
               #'./src/util/ssl_util.c',
               #'./src/util/ssl_util.h',
               './src/util/util.c',
               './src/util/util.h',
               #'./src/util/util_db.c',
               #'./src/util/util_db.h',
 
-	      # Events
+              # Events
 #              './src/event/async_timer.c',
               './src/event/async_timer.h',
 #              './src/event/async_wait.c',
               './src/event/async_wait.h',
               './src/event/async_wait_int.h',
 
-	      # Logging
+              # Logging
               './src/log/r_log.c',
               './src/log/r_log.h',
               #'./src/log/r_log_plugin.c',
 
-	      # Registry
+              # Registry
               './src/registry/c2ru.c',
               './src/registry/c2ru.h',
               #'./src/registry/mod_registry/mod_registry.c',
               #'./src/registry/nrregctl.c',
               #'./src/registry/nrregistryctl.c',
               './src/registry/registry.c',
               './src/registry/registry.h',
               './src/registry/registry_int.h',
@@ -117,35 +117,35 @@
               #'./src/registry/regrpc_client.c',
               #'./src/registry/regrpc_client.h',
               #'./src/registry/regrpc_client_cb.c',
               #'./src/registry/regrpc_clnt.c',
               #'./src/registry/regrpc_server.c',
               #'./src/registry/regrpc_svc.c',
               #'./src/registry/regrpc_xdr.c',
 
-	      # Statistics
+              # Statistics
               #'./src/stats/nrstats.c',
               #'./src/stats/nrstats.h',
               #'./src/stats/nrstats_app.c',
               #'./src/stats/nrstats_int.h',
               #'./src/stats/nrstats_memory.c',
           ],
-          
+
           'defines' : [
               'SANITY_CHECKS',
-	      'R_PLATFORM_INT_TYPES=<stdint.h>',
-	      'R_DEFINED_INT2=int16_t',
-	      'R_DEFINED_UINT2=uint16_t',
-	      'R_DEFINED_INT4=int32_t',
-	      'R_DEFINED_UINT4=uint32_t',
-	      'R_DEFINED_INT8=int64_t',
-	      'R_DEFINED_UINT8=uint64_t',
+              'R_PLATFORM_INT_TYPES=<stdint.h>',
+              'R_DEFINED_INT2=int16_t',
+              'R_DEFINED_UINT2=uint16_t',
+              'R_DEFINED_INT4=int32_t',
+              'R_DEFINED_UINT4=uint32_t',
+              'R_DEFINED_INT8=int64_t',
+              'R_DEFINED_UINT8=uint64_t',
           ],
-          
+
           'conditions' : [
               ## Mac and BSDs
               [ 'OS == "mac"', {
                 'defines' : [
                     'DARWIN',
                 ],
               }],
               [ 'os_bsd == 1', {
@@ -169,43 +169,44 @@
                      'HAVE_SYS_TIME_H=1',
                      'HAVE_VFPRINTF=1',
                      'NEW_STDIO'
                      'RETSIGTYPE=void',
                      'TIME_WITH_SYS_TIME_H=1',
                      '__UNUSED__=__attribute__((unused))',
                  ],
 
-		 'include_dirs': [
-		     'src/port/darwin/include'
-		 ],
-		 
-		 'sources': [
-              	      './src/port/darwin/include/csi_platform.h',
-		 ],
+                 'include_dirs': [
+                     'src/port/darwin/include'
+                 ],
+
+                 'sources': [
+                      './src/port/darwin/include/csi_platform.h',
+                 ],
               }],
-              
+
               ## Win
               [ 'OS == "win"', {
                  'defines' : [
                      'WIN',
                      '__UNUSED__=',
                      'HAVE_STRDUP=1',
                      'NO_REG_RPC'
                  ],
 
-		 'include_dirs': [
-		     'src/port/win32/include'
-		 ],
+                 'include_dirs': [
+                     'src/port/win32/include'
+                 ],
 
-		 'sources': [
-              	      './src/port/win32/include/csi_platform.h',
-		 ],
+                 'sources': [
+                      './src/port/win32/include/csi_platform.h',
+                 ],
               }],
-              ## Linux
+
+              ## Linux/Android
               [ '(OS == "linux") or (OS == "android")', {
                  'cflags_mozilla': [
                      '-Wall',
                      '-Wno-parentheses',
                      '-Wno-strict-prototypes',
                      '-Wmissing-prototypes',
                      '-Wno-format',
                      '-Wno-format-security',
@@ -219,20 +220,20 @@
                      'HAVE_VFPRINTF=1',
                      'NEW_STDIO'
                      'RETSIGTYPE=void',
                      'TIME_WITH_SYS_TIME_H=1',
                      'NO_REG_RPC=1',
                      '__UNUSED__=__attribute__((unused))',
                  ],
 
-		 'include_dirs': [
-		     'src/port/linux/include'
-		 ],
-		 'sources': [
-              	      './src/port/linux/include/csi_platform.h',
-		 ],
+                 'include_dirs': [
+                     'src/port/linux/include'
+                 ],
+                 'sources': [
+                      './src/port/linux/include/csi_platform.h',
+                 ],
               }]
           ]
       }]
 }
 
 
--- a/media/mtransport/third_party/nrappkit/src/log/r_log.c
+++ b/media/mtransport/third_party/nrappkit/src/log/r_log.c
@@ -190,24 +190,24 @@ int r_log_register(char *facility_name,i
     *log_facility=log_type_ct;
     log_type_ct++;
 
     for(j=0; j<LOG_NUM_DESTINATIONS; j++){
       log_types[i].level[j]=LOG_LEVEL_UNDEFINED;
 
       if(NR_reg_initted()){
 
-        if(snprintf(dest_prefix,sizeof(NR_registry),
+        if((size_t)snprintf(dest_prefix,sizeof(NR_registry),
           "logging.%s.facility",log_destinations[j].dest_name)>=sizeof(NR_registry))
           ABORT(R_INTERNAL);
 
         if (r=NR_reg_make_registry(dest_prefix,facility_name,dest_facility_prefix))
           ABORT(r);
 
-        if(snprintf(log_types[i].dest_facility_key[j],sizeof(NR_registry),
+        if((size_t)snprintf(log_types[i].dest_facility_key[j],sizeof(NR_registry),
           "%s.level",dest_facility_prefix)>=sizeof(NR_registry))
           ABORT(R_INTERNAL);
 
         if(!r_log_get_reg_level(log_types[i].dest_facility_key[j],&level)){
           log_types[i].level[j]=level;
         }
 
         /* Set a callback for the facility's level */
@@ -278,16 +278,18 @@ static void r_log_facility_change_cb(voi
 
     if(r=r_log_get_reg_level(name,&level))
       ABORT(r);
 
     *lt_level=level;
 
     _status=0;
   abort:
+    (void)_status; // to avoid unused variable warning and still conform to
+                   // pattern of using ABORT
     return;
   }
 
 /* Handle the case where a value is deleted */
 static void r_log_facility_delete_cb(void *cb_arg, char action, NR_registry name)
   {
     int *lt_level=(int *)cb_arg;
 
@@ -304,17 +306,17 @@ int r_log(int facility,int level,const c
     va_end(ap);
 
     return(0);
   }
 
 int r_dump(int facility,int level,char *name,char *data,int len)
   {
     char *hex = 0;
-    int unused;
+    size_t unused;
 
     if(!r_logging(facility,level))
       return(0);
 
     hex=RMALLOC((len*2)+1);
     if (!hex)
       return(R_FAILED);
 
@@ -560,17 +562,17 @@ static int r_log_get_destinations(int us
       NR_registry reg_key;
       int i;
       int value;
       char c;
 
       /* Get the data out of the registry */
       for(i=0; i<LOG_NUM_DESTINATIONS; i++){
         /* set callback for default level */
-        if(snprintf(reg_key,sizeof(reg_key),"%s.%s.level",LOGGING_REG_PREFIX,
+        if((size_t)snprintf(reg_key,sizeof(reg_key),"%s.%s.level",LOGGING_REG_PREFIX,
           log_destinations[i].dest_name)>=sizeof(reg_key))
           ABORT(R_INTERNAL);
 
         NR_reg_register_callback(reg_key,
           NR_REG_CB_ACTION_ADD|NR_REG_CB_ACTION_CHANGE|NR_REG_CB_ACTION_DELETE,
           r_log_default_level_change_cb,0);
 
         if(r=r_log_get_reg_level(reg_key,&value)){
@@ -578,17 +580,17 @@ static int r_log_get_destinations(int us
             log_destinations[i].default_level=LOG_LEVEL_UNDEFINED;
           else
             ABORT(R_INTERNAL);
         }
         else
           log_destinations[i].default_level=value;
 
         /* set callback for the enabled key for this logging dest */
-        if(snprintf(reg_key,sizeof(reg_key),"%s.%s.enabled",LOGGING_REG_PREFIX,
+        if((size_t)snprintf(reg_key,sizeof(reg_key),"%s.%s.enabled",LOGGING_REG_PREFIX,
           log_destinations[i].dest_name)>=sizeof(reg_key))
           ABORT(R_INTERNAL);
 
         NR_reg_register_callback(reg_key,
           NR_REG_CB_ACTION_ADD|NR_REG_CB_ACTION_CHANGE|NR_REG_CB_ACTION_DELETE,
           r_log_destination_change_cb,0);
 
         if(r=NR_reg_get_char(reg_key,&c)){
--- a/media/mtransport/third_party/nrappkit/src/registry/c2ru.c
+++ b/media/mtransport/third_party/nrappkit/src/registry/c2ru.c
@@ -216,17 +216,17 @@ abort:
 }
 
 int
 nr_c2ru_get_children(NR_registry parent, char *child, void *ptr, size_t size, int (*get)(NR_registry, void*))
 {
   int r, _status;
   NR_registry registry;
   unsigned int count;
-  int i;
+  unsigned int i;
   NR_registry name;
   struct entry { TAILQ_ENTRY(entry) entries; } *entry;
   TAILQ_HEAD(, entry) *tailq = (void*)ptr;
 
   TAILQ_INIT(tailq);
 
   if ((r=nr_c2ru_make_registry(parent, child, registry)))
     ABORT(r);
--- a/media/mtransport/third_party/nrappkit/src/registry/registry.c
+++ b/media/mtransport/third_party/nrappkit/src/registry/registry.c
@@ -336,17 +336,17 @@ nr_reg_type_name(int type)
 
     return(typenames[type]);
 }
 
 int
 nr_reg_compute_type(char *typename, int *type)
 {
     int _status;
-    int i;
+    size_t i;
 
 #ifdef SANITY_CHECKS
     assert(!strcasecmp(typenames[NR_REG_TYPE_CHAR],     "char"));
     assert(!strcasecmp(typenames[NR_REG_TYPE_UCHAR],    "UCHAR"));
     assert(!strcasecmp(typenames[NR_REG_TYPE_INT2],     "INT2"));
     assert(!strcasecmp(typenames[NR_REG_TYPE_UINT2],    "UINT2"));
     assert(!strcasecmp(typenames[NR_REG_TYPE_INT4],     "INT4"));
     assert(!strcasecmp(typenames[NR_REG_TYPE_UINT4],    "UINT4"));
@@ -556,20 +556,20 @@ NR_reg_get2_child_registry(NR_registry b
   }
 
 
 /* requires parent already in legal form */
 int
 NR_reg_make_registry(NR_registry parent, char *child, NR_registry out)
 {
     int r, _status;
-    int plen;
-    int clen;
+    size_t plen;
+    size_t clen;
     char *c;
-    int i;
+    size_t i;
 
     if ((r=nr_reg_is_valid(parent)))
         ABORT(r);
 
     if (*child == '.')
         ABORT(R_BAD_ARGS);
 
     clen = strlen(child);
--- a/media/mtransport/third_party/nrappkit/src/registry/registrycb.c
+++ b/media/mtransport/third_party/nrappkit/src/registry/registrycb.c
@@ -96,17 +96,17 @@ nr_reg_cb_init()
     }
     return(_status);
 }
 
 int
 nr_reg_validate_action(char action)
 {
     int _status;
-    int i;
+    size_t i;
 
     for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
         if (action == CB_ACTIONS[i])
             return 0;
     }
     ABORT(R_BAD_ARGS);
 
     _status=0;
@@ -392,17 +392,17 @@ nr_reg_raise_event(char *name, int actio
 
 
 /* PUBLIC METHODS */
 
 int
 NR_reg_register_callback(NR_registry name, char action, void (*cb)(void *cb_arg, char action, NR_registry name), void *cb_arg)
 {
     int r, _status;
-    int i;
+    size_t i;
 
     for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
         if (action & CB_ACTIONS[i]) {
             if ((r=nr_reg_register_callback(name, CB_ACTIONS[i], cb, cb_arg)))
                 ABORT(r);
 
             action &= ~(CB_ACTIONS[i]);
         }
@@ -415,17 +415,17 @@ NR_reg_register_callback(NR_registry nam
   abort:
     return(_status);
 }
 
 int
 NR_reg_unregister_callback(char *name, char action, void (*cb)(void *cb_arg, char action, NR_registry name))
 {
     int r, _status;
-    int i;
+    size_t i;
 
     for (i = 0; i < sizeof(CB_ACTIONS); ++i) {
         if (action & CB_ACTIONS[i]) {
             if ((r=nr_reg_unregister_callback(name, CB_ACTIONS[i], cb)))
                 ABORT(r);
 
             action &= ~(CB_ACTIONS[i]);
         }
--- a/media/mtransport/third_party/nrappkit/src/util/hex.c
+++ b/media/mtransport/third_party/nrappkit/src/util/hex.c
@@ -46,48 +46,50 @@ static char *RCSSTRING __UNUSED__ ="$Id:
 #include "hex.h"
 #include "r_log.h"
 
 static char bin2hex_map[][3] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff" };
 
 static int hex2bin_map[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 /* '0' */, 1 /* '1' */, 2 /* '2' */, 3 /* '3' */, 4 /* '4' */, 5 /* '5' */, 6 /* '6' */, 7 /* '7' */, 8 /* '8' */, 9 /* '9' */, -1, -1, -1, -1, -1, -1, -1, 10 /* 'A' */, 11 /* 'B' */, 12 /* 'C' */, 13 /* 'D' */, 14 /* 'E' */, 15 /* 'F' */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10 /* 'a' */, 11 /* 'b' */, 12 /* 'c' */, 13 /* 'd' */, 14 /* 'e' */, 15 /* 'f' */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
 
 int
-nr_nbin2hex(UCHAR *bin, int binlen, char hex[], size_t size, int *len)
+nr_nbin2hex(UCHAR *bin, size_t binlen, char hex[], size_t size, size_t *len)
 {
     int _status;
-    int i;
+    size_t i;
+    size_t hexlen;
 
-    if (size < (2*binlen))
+    hexlen = 2*binlen;
+    if (size < hexlen)
         ABORT(R_BAD_ARGS);
 
     for (i = 0; i < binlen; ++i) {
         *hex++ = bin2hex_map[bin[i]][0];
         *hex++ = bin2hex_map[bin[i]][1];
     }
 
-    if (size >= (2*binlen)+1)
+    if (size >= hexlen+1)
         *hex = '\0';
 
-    *len = (2*binlen);
+    *len = hexlen;
 
     _status=0;
   abort:
     return(_status);
 }
 
 
 int
-nr_nhex2bin(char *hex, int hexlen, UCHAR bin[], size_t size, int *len)
+nr_nhex2bin(char *hex, size_t hexlen, UCHAR bin[], size_t size, size_t *len)
 {
     int _status;
-    int binlen;
+    size_t binlen;
     int h1;
     int h2;
-    int i;
+    size_t i;
 
     if (hexlen % 2)
         ABORT(R_BAD_ARGS);
 
     binlen = hexlen/2;
 
     if (size < binlen)
         ABORT(R_BAD_ARGS);
--- a/media/mtransport/third_party/nrappkit/src/util/hex.h
+++ b/media/mtransport/third_party/nrappkit/src/util/hex.h
@@ -35,13 +35,13 @@
 
    briank@network-resonance.com
  */
 
 
 #ifndef _hex_h
 #define _hex_h
 
-int nr_nbin2hex(UCHAR *bin, int binlen, char hex[], size_t size, int *len);
-int nr_nhex2bin(char *hex, int hexlen, UCHAR bin[], size_t size, int *len);
+int nr_nbin2hex(UCHAR *bin, size_t binlen, char hex[], size_t size, size_t *len);
+int nr_nhex2bin(char *hex, size_t hexlen, UCHAR bin[], size_t size, size_t *len);
 
 #endif
 
--- a/media/mtransport/third_party/nrappkit/src/util/libekr/r_data.c
+++ b/media/mtransport/third_party/nrappkit/src/util/libekr/r_data.c
@@ -85,17 +85,17 @@ static char *RCSSTRING __UNUSED__ =(char
 #include <string.h>
 #include <r_common.h>
 #include <r_data.h>
 #include <string.h>
 
 int r_data_create(dp,d,l)
   Data **dp;
   const UCHAR *d;
-  int l;
+  size_t l;
   {
     Data *d_=0;
     int _status;
 
     if(!(d_=(Data *)RCALLOC(sizeof(Data))))
       ABORT(R_NO_MEMORY);
     if(!(d_->data=(UCHAR *)RMALLOC(l)))
       ABORT(R_NO_MEMORY);
@@ -111,32 +111,32 @@ int r_data_create(dp,d,l)
       r_data_destroy(&d_);
 
     return(_status);
   }
 
 
 int r_data_alloc_mem(d,l)
   Data *d;
-  int l;
+  size_t l;
   {
     int _status;
 
     if(!(d->data=(UCHAR *)RMALLOC(l)))
       ABORT(R_NO_MEMORY);
     d->len=l;
 
     _status=0;
   abort:
     return(_status);
   }
 
 int r_data_alloc(dp,l)
   Data **dp;
-  int l;
+  size_t l;
   {
     Data *d_=0;
     int _status;
 
     if(!(d_=(Data *)RCALLOC(sizeof(Data))))
       ABORT(R_NO_MEMORY);
     if(!(d_->data=(UCHAR *)RCALLOC(l)))
       ABORT(R_NO_MEMORY);
@@ -150,17 +150,17 @@ int r_data_alloc(dp,l)
       r_data_destroy(&d_);
 
     return(_status);
   }
 
 int r_data_make(dp,d,l)
   Data *dp;
   const UCHAR *d;
-  int l;
+  size_t l;
   {
     if(!(dp->data=(UCHAR *)RMALLOC(l)))
       ERETURN(R_NO_MEMORY);
 
     memcpy(dp->data,d,l);
     dp->len=l;
 
     return(0);
--- a/media/mtransport/third_party/nrappkit/src/util/libekr/r_data.h
+++ b/media/mtransport/third_party/nrappkit/src/util/libekr/r_data.h
@@ -81,23 +81,23 @@
  */
 
 
 #ifndef _r_data_h
 #define _r_data_h
 
 typedef struct Data_ {
      UCHAR *data;
-     int len;
+     size_t len;
 } Data;
 
-int r_data_create(Data **dp,const UCHAR *d,int l);
-int r_data_alloc(Data **dp, int l);
-int r_data_make(Data *dp, const UCHAR *d,int l);
-int r_data_alloc_mem(Data *d,int l);
+int r_data_create(Data **dp,const UCHAR *d,size_t l);
+int r_data_alloc(Data **dp, size_t l);
+int r_data_make(Data *dp, const UCHAR *d,size_t l);
+int r_data_alloc_mem(Data *d,size_t l);
 int r_data_destroy(Data **dp);
 int r_data_destroy_v(void *v);
 int r_data_destroy_vp(void **vp);
 int r_data_copy(Data *dst,Data *src);
 int r_data_zfree(Data *d);
 int r_data_compare(Data *d1,Data *d2);
 
 #define INIT_DATA(a,b,c) (a).data=b; (a).len=c
--- a/media/mtransport/third_party/nrappkit/src/util/libekr/r_errors.c
+++ b/media/mtransport/third_party/nrappkit/src/util/libekr/r_errors.c
@@ -106,17 +106,17 @@ int nr_verr_exit(char *fmt,...)
 
     exit(1);
   }
 
 char *
 nr_strerror(int errnum)
 {
     static char unknown_error[256];
-    int i;
+    size_t i;
     char *error = 0;
 
     for (i = 0; i < sizeof(errors)/sizeof(*errors); ++i) {
         if (errnum == errors[i].errnum) {
             error = errors[i].str;
             break;
         }
     }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -121,17 +121,17 @@ pref("network.predictor.preserve", 50); 
 
 // Use JS mDNS as a fallback
 pref("network.mdns.use_js_fallback", false);
 
 /* How many times should have passed before the remote tabs list is refreshed */
 pref("browser.display.remotetabs.timeout", 10);
 
 /* session history */
-pref("browser.sessionhistory.max_total_viewers", 1);
+pref("browser.sessionhistory.max_total_viewers", -1);
 pref("browser.sessionhistory.max_entries", 50);
 pref("browser.sessionhistory.contentViewerTimeout", 360);
 pref("browser.sessionhistory.bfcacheIgnoreMemoryPressure", false);
 
 /* session store */
 pref("browser.sessionstore.resume_from_crash", true);
 pref("browser.sessionstore.interval", 10000); // milliseconds
 pref("browser.sessionstore.backupInterval", 120000); // milliseconds -> 2 minutes
--- a/mobile/android/base/java/org/mozilla/gecko/MemoryMonitor.java
+++ b/mobile/android/base/java/org/mozilla/gecko/MemoryMonitor.java
@@ -200,27 +200,39 @@ class MemoryMonitor extends BroadcastRec
 
     /**
      * Thread-safe due to mStoragePressure's volatility.
      */
     boolean isUnderStoragePressure() {
         return mStoragePressure;
     }
 
+    @WrapForJNI
+    private static native void dispatchMemoryPressureStop();
+
+    /**
+     * @return False if we have decremented all the way down to {@code MEMORY_PRESSURE_NONE}.
+     */
     private boolean decreaseMemoryPressure() {
         int newLevel;
         synchronized (this) {
-            if (mMemoryPressure <= 0) {
+            if (mMemoryPressure <= MEMORY_PRESSURE_NONE) {
                 return false;
+            } else {
+                newLevel = --mMemoryPressure;
             }
-
-            newLevel = --mMemoryPressure;
         }
         Log.d(LOGTAG, "Decreased memory pressure to " + newLevel);
 
+        if (newLevel == MEMORY_PRESSURE_NONE) {
+            if (GeckoThread.isRunning()) {
+                dispatchMemoryPressureStop();
+            }
+        }
+
         return true;
     }
 
     class PressureDecrementer implements Runnable {
         private static final int DECREMENT_DELAY = 5 * 60 * 1000; // 5 minutes
 
         private boolean mPosted;
 
--- a/mobile/android/chrome/content/MemoryObserver.js
+++ b/mobile/android/chrome/content/MemoryObserver.js
@@ -1,23 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+const MAX_CONTENT_VIEWERS_PREF = "browser.sessionhistory.max_total_viewers";
+
 var MemoryObserver = {
+  // When we turn off the bfcache by overwriting the old default value, we want
+  // to be able to restore it later on if memory pressure decreases again.
+  _defaultMaxContentViewers: -1,
+
   observe: function mo_observe(aSubject, aTopic, aData) {
     if (aTopic == "memory-pressure") {
       if (aData != "heap-minimize") {
         this.handleLowMemory();
       }
       // The JS engine would normally GC on this notification, but since we
       // disabled that in favor of this method (bug 669346), we should gc here.
       // See bug 784040 for when this code was ported from XUL to native Fennec.
       this.gc();
+    } else if (aTopic == "memory-pressure-stop") {
+      this.handleEnoughMemory();
     } else if (aTopic == "Memory:Dump") {
       this.dumpMemoryStats(aData);
     }
   },
 
   handleLowMemory: function() {
     // do things to reduce memory usage here
     if (!Services.prefs.getBoolPref("browser.tabs.disableBackgroundZombification")) {
@@ -28,22 +36,28 @@ var MemoryObserver = {
           tabs[i].zombify();
         }
       }
     }
 
     // Change some preferences temporarily for only this session
     let defaults = Services.prefs.getDefaultBranch(null);
 
-    // Reduce the amount of decoded image data we keep around
-    defaults.setIntPref("image.mem.max_decoded_image_kb", 0);
-
     // Stop using the bfcache
     if (!Services.prefs.getBoolPref("browser.sessionhistory.bfcacheIgnoreMemoryPressure")) {
-      defaults.setIntPref("browser.sessionhistory.max_total_viewers", 0);
+      this._defaultMaxContentViewers = defaults.getIntPref(MAX_CONTENT_VIEWERS_PREF);
+      defaults.setIntPref(MAX_CONTENT_VIEWERS_PREF, 0);
+    }
+  },
+
+  handleEnoughMemory: function() {
+    // Re-enable the bfcache
+    let defaults = Services.prefs.getDefaultBranch(null);
+    if (!Services.prefs.getBoolPref("browser.sessionhistory.bfcacheIgnoreMemoryPressure")) {
+      defaults.setIntPref(MAX_CONTENT_VIEWERS_PREF, this._defaultMaxContentViewers);
     }
   },
 
   gc: function() {
     window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
     Cu.forceGC();
   },
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -133,17 +133,20 @@ lazilyLoadedBrowserScripts.forEach(funct
   XPCOMUtils.defineLazyGetter(window, name, function() {
     let sandbox = {};
     Services.scriptloader.loadSubScript(script, sandbox);
     return sandbox[name];
   });
 });
 
 var lazilyLoadedObserverScripts = [
-  ["MemoryObserver", ["memory-pressure", "Memory:Dump"], "chrome://browser/content/MemoryObserver.js"],
+  ["MemoryObserver", ["memory-pressure",
+                      "memory-pressure-stop",
+                      "Memory:Dump"],
+   "chrome://browser/content/MemoryObserver.js"],
   ["ConsoleAPI", ["console-api-log-event"], "chrome://browser/content/ConsoleAPI.js"],
   ["ExtensionPermissions", ["webextension-permission-prompt",
                             "webextension-update-permissions",
                             "webextension-optional-permission-prompt"],
    "chrome://browser/content/ExtensionPermissions.js"],
 ];
 
 lazilyLoadedObserverScripts.forEach(function (aScript) {
--- a/mobile/android/chrome/geckoview/GeckoViewNavigationContent.js
+++ b/mobile/android/chrome/geckoview/GeckoViewNavigationContent.js
@@ -34,15 +34,15 @@ class GeckoViewNavigationContent extends
     debug `loadURI: uri=${aUri && aUri.spec}
                     where=${aWhere} flags=${aFlags}`;
 
     // TODO: Remove this when we have a sensible error API.
     if (aUri && aUri.displaySpec.startsWith("about:certerror")) {
       addEventListener("click", ErrorPageEventHandler, true);
     }
 
-    return LoadURIDelegate.load(this.eventDispatcher, aUri, aWhere, aFlags,
-                                aTriggeringPrincipal);
+    return LoadURIDelegate.load(content, this.eventDispatcher,
+                                aUri, aWhere, aFlags);
   }
 }
 
 let {debug, warn} = GeckoViewNavigationContent.initLogging("GeckoViewNavigation");
 let module = GeckoViewNavigationContent.create(this);
--- a/mobile/android/components/geckoview/GeckoViewPermission.js
+++ b/mobile/android/components/geckoview/GeckoViewPermission.js
@@ -50,17 +50,17 @@ GeckoViewPermission.prototype = {
     let perms = [];
     if (aType === "video" || aType === "all") {
       perms.push(PERM_CAMERA);
     }
     if (aType === "audio" || aType === "all") {
       perms.push(PERM_RECORD_AUDIO);
     }
 
-    let dispatcher = GeckoViewUtils.getActiveDispatcher();
+    let [dispatcher] = GeckoViewUtils.getActiveDispatcherAndWindow();
     let callback = _ => {
       Services.obs.notifyObservers(aCallback, "getUserMedia:got-device-permission");
     };
 
     if (dispatcher) {
       this.getAppPermissions(dispatcher, perms).then(callback, callback);
     } else {
       // No dispatcher; just bail.
--- a/mobile/android/components/geckoview/GeckoViewPrompt.js
+++ b/mobile/android/components/geckoview/GeckoViewPrompt.js
@@ -339,17 +339,18 @@ PromptFactory.prototype = {
 function PromptDelegate(aDomWin) {
   this._domWin = aDomWin;
 
   if (aDomWin) {
     this._dispatcher = GeckoViewUtils.getDispatcherForWindow(aDomWin);
   }
 
   if (!this._dispatcher) {
-    this._dispatcher = GeckoViewUtils.getActiveDispatcher();
+    [this._dispatcher, this._domWin] =
+        GeckoViewUtils.getActiveDispatcherAndWindow();
   }
 }
 
 PromptDelegate.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPrompt]),
 
   BUTTON_TYPE_POSITIVE: 0,
   BUTTON_TYPE_NEUTRAL: 1,
@@ -387,24 +388,25 @@ PromptDelegate.prototype = {
   },
 
   /**
    * Shows a native prompt, and then spins the event loop for this thread while we wait
    * for a response
    */
   _showPrompt: function(aMsg) {
     let result = undefined;
-    if (!this._changeModalState(/* aEntering */ true)) {
+    if (!this._domWin || !this._changeModalState(/* aEntering */ true)) {
       return;
     }
     try {
       this.asyncShowPrompt(aMsg, res => result = res);
 
       // Spin this thread while we wait for a result
-      Services.tm.spinEventLoopUntil(() => result !== undefined);
+      Services.tm.spinEventLoopUntil(() =>
+          this._domWin.closed || result !== undefined);
     } finally {
       this._changeModalState(/* aEntering */ false);
     }
     return result;
   },
 
   asyncShowPrompt: function(aMsg, aCallback) {
     let handled = false;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoBundle.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoBundle.java
@@ -35,31 +35,16 @@ public final class GeckoBundle implement
     @WrapForJNI(calledFrom = "gecko")
     private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
     private static final int[] EMPTY_INT_ARRAY = new int[0];
     private static final long[] EMPTY_LONG_ARRAY = new long[0];
     private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
     private static final GeckoBundle[] EMPTY_BUNDLE_ARRAY = new GeckoBundle[0];
 
-    @WrapForJNI(calledFrom = "gecko")
-    private static Object box(boolean b) { return b; }
-    @WrapForJNI(calledFrom = "gecko")
-    private static Object box(int i) { return i; }
-    @WrapForJNI(calledFrom = "gecko")
-    private static Object box(double d) { return d; }
-    @WrapForJNI(calledFrom = "gecko")
-    private static boolean unboxBoolean(Boolean b) { return b; }
-    @WrapForJNI(calledFrom = "gecko")
-    private static int unboxInteger(Number i) { return i.intValue(); }
-    @WrapForJNI(calledFrom = "gecko")
-    private static double unboxDouble(Number d) { return d.doubleValue(); }
-    @WrapForJNI(calledFrom = "gecko")
-    private static String unboxString(Object s) { return s.toString(); }
-
     private SimpleArrayMap<String, Object> mMap;
 
     /**
      * Construct an empty GeckoBundle.
      */
     public GeckoBundle() {
         mMap = new SimpleArrayMap<>();
     }
--- a/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
@@ -134,33 +134,34 @@ class GeckoViewNavigation extends GeckoV
 
     let browser = undefined;
     this.eventDispatcher.sendRequestForResult(message).then(sessionId => {
       return this.waitAndSetupWindow(sessionId, {
         opener: (aFlags & Ci.nsIBrowserDOMWindow.OPEN_NO_OPENER) ? null : aOpener,
         nextTabParentId: aNextTabParentId
       });
     }).then(window => {
-      browser = (window && window.browser);
+      browser = (window && window.browser) || null;
     }, () => {
       browser = null;
     });
 
     // Wait indefinitely for app to respond with a browser or null
-    Services.tm.spinEventLoopUntil(() => browser !== undefined);
-    return browser;
+    Services.tm.spinEventLoopUntil(() =>
+        this.window.closed || browser !== undefined);
+    return browser || null;
   }
 
   // nsIBrowserDOMWindow.
   createContentWindow(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
     debug `createContentWindow: uri=${aUri && aUri.spec}
                                 where=${aWhere} flags=${aFlags}`;
 
-    if (LoadURIDelegate.load(this.eventDispatcher, aUri, aWhere, aFlags,
-                             aTriggeringPrincipal)) {
+    if (LoadURIDelegate.load(this.window, this.eventDispatcher,
+                             aUri, aWhere, aFlags)) {
       // The app has handled the load, abort open-window handling.
       Components.returnCode = Cr.NS_ERROR_ABORT;
       return null;
     }
 
     const browser = this.handleNewSession(aUri, aOpener, aWhere, aFlags, null);
     if (!browser) {
       Components.returnCode = Cr.NS_ERROR_ABORT;
@@ -174,17 +175,18 @@ class GeckoViewNavigation extends GeckoV
   createContentWindowInFrame(aUri, aParams, aWhere, aFlags, aNextTabParentId,
                              aName) {
     debug `createContentWindowInFrame: uri=${aUri && aUri.spec}
                                        params=${aParams} where=${aWhere}
                                        flags=${aFlags}
                                        nextTabParentId=${aNextTabParentId}
                                        name=${aName}`;
 
-    if (LoadURIDelegate.load(this.eventDispatcher, aUri, aWhere, aFlags, null)) {
+    if (LoadURIDelegate.load(this.window, this.eventDispatcher,
+                             aUri, aWhere, aFlags)) {
       // The app has handled the load, abort open-window handling.
       Components.returnCode = Cr.NS_ERROR_ABORT;
       return null;
     }
 
     const browser = this.handleNewSession(aUri, null, aWhere, aFlags, aNextTabParentId);
     if (!browser) {
       Components.returnCode = Cr.NS_ERROR_ABORT;
@@ -194,18 +196,18 @@ class GeckoViewNavigation extends GeckoV
     return browser;
   }
 
   handleOpenUri(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal,
                 aNextTabParentId) {
     debug `handleOpenUri: uri=${aUri && aUri.spec}
                           where=${aWhere} flags=${aFlags}`;
 
-    if (LoadURIDelegate.load(this.eventDispatcher, aUri, aWhere, aFlags,
-                             aTriggeringPrincipal)) {
+    if (LoadURIDelegate.load(this.window, this.eventDispatcher,
+                             aUri, aWhere, aFlags)) {
       return null;
     }
 
     let browser = this.browser;
 
     if (aWhere === Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW ||
         aWhere === Ci.nsIBrowserDOMWindow.OPEN_NEWTAB ||
         aWhere === Ci.nsIBrowserDOMWindow.OPEN_SWITCHTAB) {
--- a/mobile/android/modules/geckoview/GeckoViewUtils.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewUtils.jsm
@@ -284,31 +284,32 @@ var GeckoViewUtils = {
       if (!win.closed) {
         return win.WindowEventDispatcher || EventDispatcher.for(win);
       }
     } catch (e) {
     }
     return null;
   },
 
-  getActiveDispatcher: function() {
-    let dispatcher = this.getDispatcherForWindow(Services.focus.activeWindow);
+  getActiveDispatcherAndWindow: function() {
+    let win = Services.focus.activeWindow;
+    let dispatcher = this.getDispatcherForWindow(win);
     if (dispatcher) {
-      return dispatcher;
+      return [dispatcher, win];
     }
 
     let iter = Services.wm.getEnumerator(/* windowType */ null);
     while (iter.hasMoreElements()) {
-      dispatcher = this.getDispatcherForWindow(
-          iter.getNext().QueryInterface(Ci.nsIDOMWindow));
+      win = iter.getNext().QueryInterface(Ci.nsIDOMWindow);
+      dispatcher = this.getDispatcherForWindow(win);
       if (dispatcher) {
-        return dispatcher;
+        return [dispatcher, win];
       }
     }
-    return null;
+    return [null, null];
   },
 
   /**
    * Add logging functions to the specified scope that forward to the given
    * Log.jsm logger. Currently "debug" and "warn" functions are supported. To
    * log something, call the function through a template literal:
    *
    *   function foo(bar, baz) {
--- a/mobile/android/modules/geckoview/LoadURIDelegate.jsm
+++ b/mobile/android/modules/geckoview/LoadURIDelegate.jsm
@@ -10,29 +10,34 @@ ChromeUtils.import("resource://gre/modul
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Services: "resource://gre/modules/Services.jsm",
 });
 
 var LoadURIDelegate = {
   // Delegate URI loading to the app.
   // Return whether the loading has been handled.
-  load: function(aEventDispatcher, aUri, aWhere, aFlags, aTriggeringPrincipal) {
+  load: function(aWindow, aEventDispatcher, aUri, aWhere, aFlags) {
+    if (!aWindow) {
+      return false;
+    }
+
     const message = {
       type: "GeckoView:OnLoadRequest",
       uri: aUri ? aUri.displaySpec : "",
       where: aWhere,
       flags: aFlags
     };
 
     let handled = undefined;
     aEventDispatcher.sendRequestForResult(message).then(response => {
       handled = response;
     }, () => {
       // There was an error or listener was not registered in GeckoSession,
       // treat as unhandled.
       handled = false;
     });
-    Services.tm.spinEventLoopUntil(() => handled !== undefined);
+    Services.tm.spinEventLoopUntil(() =>
+        aWindow.closed || handled !== undefined);
 
-    return handled;
+    return handled || false;
   }
 };
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3206,17 +3206,16 @@ pref("dom.ipc.processCount.extension", 1
 // Whether a native event loop should be used in the content process.
 #if defined(XP_WIN)
 pref("dom.ipc.useNativeEventProcessing.content", false);
 #else
 pref("dom.ipc.useNativeEventProcessing.content", true);
 #endif
 
 // Quantum DOM scheduling:
-pref("dom.ipc.scheduler", false);
 pref("dom.ipc.scheduler.useMultipleQueues", true);
 pref("dom.ipc.scheduler.preemption", false);
 pref("dom.ipc.scheduler.threadCount", 2);
 pref("dom.ipc.scheduler.chaoticScheduling", false);
 
 // Disable support for SVG
 pref("svg.disabled", false);
 
@@ -5414,20 +5413,18 @@ pref("browser.safebrowsing.reportPhishUR
 pref("browser.safebrowsing.provider.mozilla.pver", "2.2");
 pref("browser.safebrowsing.provider.mozilla.lists", "base-track-digest256,mozstd-trackwhite-digest256,content-track-digest256,mozplugin-block-digest256,mozplugin2-block-digest256,block-flash-digest256,except-flash-digest256,allow-flashallow-digest256,except-flashallow-digest256,block-flashsubdoc-digest256,except-flashsubdoc-digest256,except-flashinfobar-digest256,ads-track-digest256,social-track-digest256,analytics-track-digest256");
 pref("browser.safebrowsing.provider.mozilla.updateURL", "https://shavar.services.mozilla.com/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2");
 pref("browser.safebrowsing.provider.mozilla.gethashURL", "https://shavar.services.mozilla.com/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2");
 // Set to a date in the past to force immediate download in new profiles.
 pref("browser.safebrowsing.provider.mozilla.nextupdatetime", "1");
 // Block lists for tracking protection. The name values will be used as the keys
 // to lookup the localized name in preferences.properties.
-pref("browser.safebrowsing.provider.mozilla.lists.base.name", "mozstdName");
-pref("browser.safebrowsing.provider.mozilla.lists.base.description", "mozstdDesc");
-pref("browser.safebrowsing.provider.mozilla.lists.content.name", "mozfullName");
-pref("browser.safebrowsing.provider.mozilla.lists.content.description", "mozfullDesc2");
+pref("browser.safebrowsing.provider.mozilla.lists.base", "moz-std");
+pref("browser.safebrowsing.provider.mozilla.lists.content", "moz-full");
 
 // The table and global pref for blocking plugin content
 pref("browser.safebrowsing.blockedURIs.enabled", true);
 pref("urlclassifier.blockedTable", "test-block-simple,mozplugin-block-digest256");
 
 // Flash blocking tables
 pref("urlclassifier.flashAllowTable", "allow-flashallow-digest256");
 pref("urlclassifier.flashAllowExceptTable", "except-flashallow-digest256");
--- a/package-lock.json
+++ b/package-lock.json
@@ -175,17 +175,17 @@
     "chardet": {
       "version": "0.4.2",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
       "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
     },
     "circular-json": {
       "version": "0.3.3",
       "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
-      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
+      "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY="
     },
     "cli-cursor": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
       "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
       "requires": {
         "restore-cursor": "2.0.0"
       }
@@ -269,17 +269,17 @@
         "pify": "2.3.0",
         "pinkie-promise": "2.0.1",
         "rimraf": "2.6.2"
       }
     },
     "doctrine": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=",
       "requires": {
         "esutils": "2.0.2"
       }
     },
     "dom-serializer": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
       "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
@@ -859,17 +859,17 @@
       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
       "requires": {
         "pinkie": "2.0.4"
       }
     },
     "pluralize": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
-      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
+      "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c="
     },
     "prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
       "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
     },
     "process-nextick-args": {
       "version": "2.0.0",
@@ -926,17 +926,17 @@
       "requires": {
         "onetime": "2.0.1",
         "signal-exit": "3.0.2"
       }
     },
     "rimraf": {
       "version": "2.6.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
-      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=",
       "requires": {
         "glob": "7.1.2"
       }
     },
     "run-async": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
       "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
@@ -970,17 +970,17 @@
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
     },
     "semver": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
-      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+      "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs="
     },
     "shebang-command": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
       "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
       "requires": {
         "shebang-regex": "1.0.0"
       }
@@ -1071,17 +1071,17 @@
     "through": {
       "version": "2.3.8",
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
     },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=",
       "requires": {
         "os-tmpdir": "1.0.2"
       }
     },
     "type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
       "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
@@ -1097,17 +1097,17 @@
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
     },
     "which": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
-      "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+      "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=",
       "requires": {
         "isexe": "2.0.0"
       }
     },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
       "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
new file mode 100644
--- /dev/null
+++ b/python/l10n/fluent_migrations/bug_1457021_js_subdialogs.py
@@ -0,0 +1,185 @@
+# coding=utf8
+
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from __future__ import absolute_import
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import MESSAGE_REFERENCE, EXTERNAL_ARGUMENT, transforms_from
+from fluent.migrate import REPLACE
+
+
+def migrate(ctx):
+    """Bug 1457021 - Migrate the JS of Preferences subdialogs to Fluent, part {index}."""
+
+    ctx.add_transforms(
+        'browser/browser/preferences/permissions.ftl',
+        'browser/browser/preferences/permissions.ftl',
+        transforms_from(
+"""
+permissions-capabilities-allow =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "can") }
+permissions-capabilities-block =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "cannot") }
+permissions-capabilities-prompt =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "prompt") }
+""")
+    )
+
+    ctx.add_transforms(
+        'browser/browser/preferences/blocklists.ftl',
+        'browser/browser/preferences/blocklists.ftl',
+        transforms_from(
+"""
+blocklist-item-moz-std-name = { COPY("browser/chrome/browser/preferences/preferences.properties", "mozstdName") }
+blocklist-item-moz-std-desc = { COPY("browser/chrome/browser/preferences/preferences.properties", "mozstdDesc") }
+blocklist-item-moz-full-name = { COPY("browser/chrome/browser/preferences/preferences.properties", "mozfullName") }
+blocklist-item-moz-full-desc = { COPY("browser/chrome/browser/preferences/preferences.properties", "mozfullDesc2") }
+""") + [
+            FTL.Message(
+                id=FTL.Identifier('blocklist-item-list-template'),
+                value=REPLACE(
+                    'browser/chrome/browser/preferences/preferences.properties',
+                    'mozNameTemplate',
+                    {
+                        '%1$S': EXTERNAL_ARGUMENT(
+                            'listName'
+                        ),
+                        '%2$S': EXTERNAL_ARGUMENT(
+                            'description'
+                        )
+                    }
+                )
+            )
+        ]
+    )
+
+    ctx.add_transforms(
+        'browser/browser/preferences/fonts.ftl',
+        'browser/browser/preferences/fonts.ftl',
+        transforms_from(
+"""
+fonts-very-large-warning-title = { COPY("browser/chrome/browser/preferences/preferences.properties", "veryLargeMinimumFontTitle") }
+fonts-very-large-warning-message = { COPY("browser/chrome/browser/preferences/preferences.properties", "veryLargeMinimumFontWarning") }
+fonts-very-large-warning-accept = { COPY("browser/chrome/browser/preferences/preferences.properties", "acceptVeryLargeMinimumFont") }
+fonts-label-default-unnamed =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "labelDefaultFontUnnamed") }
+""") + [
+            FTL.Message(
+                id=FTL.Identifier('fonts-label-default'),
+                attributes=[
+                    FTL.Attribute(
+                        FTL.Identifier('label'),
+                        REPLACE(
+                            'browser/chrome/browser/preferences/preferences.properties',
+                            'labelDefaultFont',
+                            {
+                                '%S': EXTERNAL_ARGUMENT(
+                                    'name'
+                                )
+                            }
+                        )
+                    ),
+                ]
+            )
+        ]
+    )
+
+    ctx.add_transforms(
+        'browser/browser/preferences/preferences.ftl',
+        'browser/browser/preferences/preferences.ftl',
+        transforms_from(
+"""
+sitedata-total-size-calculating = { COPY("browser/chrome/browser/preferences/preferences.properties", "loadingSiteDataSize1") }
+""") + [
+            FTL.Message(
+                id=FTL.Identifier('sitedata-total-size'),
+                value=REPLACE(
+                    'browser/chrome/browser/preferences/preferences.properties',
+                    'totalSiteDataSize2',
+                    {
+                        '%1$S': EXTERNAL_ARGUMENT(
+                            'value'
+                        ),
+                        '%2$S': EXTERNAL_ARGUMENT(
+                            'unit'
+                        )
+                    }
+                )
+            )
+        ]
+    )
+
+    ctx.add_transforms(
+        'browser/browser/preferences/siteDataSettings.ftl',
+        'browser/browser/preferences/siteDataSettings.ftl',
+        transforms_from(
+"""
+site-usage-persistent = { site-usage-pattern } (Persistent)
+site-data-remove-all =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "removeAllSiteData.label") }
+    .accesskey = { COPY("browser/chrome/browser/preferences/preferences.properties", "removeAllSiteData.accesskey") }
+site-data-remove-shown =
+    .label = { COPY("browser/chrome/browser/preferences/preferences.properties", "removeAllSiteDataShown.label") }
+    .accesskey = { COPY("browser/chrome/browser/preferences/preferences.properties", "removeAllSiteDataShown.accesskey") }
+site-data-removing-dialog =
+    .title = { site-data-removing-header }
+    .buttonlabelaccept = { COPY("browser/chrome/browser/preferences/preferences.properties", "acceptRemove") }
+
+""") + [
+            FTL.Message(
+                id=FTL.Identifier('site-data-settings-description'),
+                value=REPLACE(
+                    'browser/chrome/browser/preferences/preferences.properties',
+                    'siteDataSettings3.description',
+                    {
+                        '%S': MESSAGE_REFERENCE(
+                            '-brand-short-name'
+                        )
+                    }
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier('site-usage-pattern'),
+                value=REPLACE(
+                    'browser/chrome/browser/preferences/preferences.properties',
+                    'siteUsage',
+                    {
+                        '%1$S': EXTERNAL_ARGUMENT(
+                            'value'
+                        ),
+                        '%2$S': EXTERNAL_ARGUMENT(
+                            'unit'
+                        )
+                    }
+                )
+            )
+        ]
+    )
+
+    ctx.add_transforms(
+        'browser/browser/preferences/languages.ftl',
+        'browser/browser/preferences/languages.ftl',
+        [
+            FTL.Message(
+                id=FTL.Identifier('languages-code-format'),
+                attributes=[
+                    FTL.Attribute(
+                        FTL.Identifier('label'),
+                        REPLACE(
+                            'browser/chrome/browser/preferences/preferences.properties',
+                            'languageCodeFormat',
+                            {
+                                '%1$S': EXTERNAL_ARGUMENT(
+                                    'locale'
+                                ),
+                                '%2$S': EXTERNAL_ARGUMENT(
+                                    'code'
+                                )
+                            }
+                        )
+                    )
+                ]
+            )
+        ]
+    )
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -101,16 +101,17 @@ ARCHIVE_FILES = {
             'base': '',
             'pattern': '**',
             'ignore': [
                 'cppunittest/**',
                 'gtest/**',
                 'mochitest/**',
                 'reftest/**',
                 'talos/**',
+                'raptor/**',
                 'awsy/**',
                 'web-platform/**',
                 'xpcshell/**',
             ],
         },
         {
             'source': buildconfig.topobjdir,
             'base': '_tests',
@@ -400,16 +401,29 @@ ARCHIVE_FILES = {
         },
         {
             'source': buildconfig.topsrcdir,
             'base': 'third_party/webkit/PerformanceTests',
             'pattern': '**',
             'dest': 'talos/talos/tests/webkit/PerformanceTests/',
         },
     ],
+    'raptor': [
+        {
+            'source': buildconfig.topsrcdir,
+            'base': 'testing',
+            'pattern': 'raptor/**',
+        },
+        {
+            'source': buildconfig.topsrcdir,
+            'base': 'third_party/webkit/PerformanceTests',
+            'pattern': '**',
+            'dest': 'raptor/raptor/tests/webkit/PerformanceTests/',
+        },
+    ],
     'awsy': [
         {
             'source': buildconfig.topsrcdir,
             'base': 'testing',
             'pattern': 'awsy/**',
         },
     ],
     'web-platform': [
--- a/python/mozbuild/mozbuild/schedules.py
+++ b/python/mozbuild/mozbuild/schedules.py
@@ -45,16 +45,17 @@ EXCLUSIVE_COMPONENTS = [
     'awsy',
     'cppunittest',
     'firefox-ui',
     'geckoview',
     'geckoview-junit',
     'gtest',
     'marionette',
     'mochitest',
+    'raptor',
     'reftest',
     'robocop',
     'talos',
     'telemetry-tests-client',
     'xpcshell',
     'xpcshell-coverage',
     'web-platform-tests',
     'web-platform-tests-reftests',
--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -281,79 +281,16 @@ VerifyEntryContentDigest(nsIZipReader* z
   nsresult rv = zip->GetInputStream(aFilename, getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
   }
 
   return VerifyStreamContentDigest(stream, digestFromManifest, buf);
 }
 
-// @oaram aDir       directory containing the unpacked signed archive
-// @param aFilename  path of the target file relative to aDir
-// @param digestFromManifest The digest that we're supposed to check the file's
-//                           contents against, from the manifest
-// @param buf A scratch buffer that we use for doing the I/O
-nsresult
-VerifyFileContentDigest(nsIFile* aDir, const nsAString& aFilename,
-                        const DigestWithAlgorithm& digestFromManifest,
-                        SECItem& buf)
-{
-  // Find the file corresponding to the manifest path
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = aDir->Clone(getter_AddRefs(file));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // We don't know how to handle JARs with signed directory entries.
-  // It's technically possible in the manifest but makes no sense on disk.
-  // Inside an archive we just ignore them, but here we have to treat it
-  // as an error because the signed bytes never got unpacked.
-  int32_t pos = 0;
-  int32_t slash;
-  int32_t namelen = aFilename.Length();
-  if (namelen == 0 || aFilename[namelen - 1] == '/') {
-    return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
-  }
-
-  // Append path segments one by one
-  do {
-    slash = aFilename.FindChar('/', pos);
-    int32_t segend = (slash == kNotFound) ? namelen : slash;
-    rv = file->Append(Substring(aFilename, pos, (segend - pos)));
-    if (NS_FAILED(rv)) {
-      return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
-    }
-    pos = slash + 1;
-  }  while (pos < namelen && slash != kNotFound);
-
-  bool exists;
-  rv = file->Exists(&exists);
-  if (NS_FAILED(rv) || !exists) {
-    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
-  }
-
-  bool isDir;
-  rv = file->IsDirectory(&isDir);
-  if (NS_FAILED(rv) || isDir) {
-    // We only support signed files, not directory entries
-    return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
-  }
-
-  // Open an input stream for that file and verify it.
-  nsCOMPtr<nsIInputStream> stream;
-  rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file, -1, -1,
-                                  nsIFileInputStream::CLOSE_ON_EOF);
-  if (NS_FAILED(rv) || !stream) {
-    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
-  }
-
-  return VerifyStreamContentDigest(stream, digestFromManifest, buf);
-}
-
 // On input, nextLineStart is the start of the current line. On output,
 // nextLineStart is the start of the next line.
 nsresult
 ReadLine(/*in/out*/ const char* & nextLineStart, /*out*/ nsCString & line,
          bool allowContinuations = true)
 {
   line.Truncate();
   size_t previousLength = 0;
@@ -1512,535 +1449,16 @@ nsNSSCertificateDB::OpenSignedAppFileAsy
   SignaturePolicy policy(policyInt);
   RefPtr<OpenSignedAppFileTask> task(new OpenSignedAppFileTask(aTrustedRoot,
                                                                aJarFile,
                                                                policy,
                                                                aCallback));
   return task->Dispatch("SignedJAR");
 }
 
-//
-// Signature verification for archives unpacked into a file structure
-//
-
-// Finds the "*.rsa" signature file in the META-INF directory and returns
-// the name. It is an error if there are none or more than one .rsa file
-nsresult
-FindSignatureFilename(nsIFile* aMetaDir,
-                      /*out*/ nsAString& aFilename)
-{
-  nsCOMPtr<nsISimpleEnumerator> entries;
-  nsresult rv = aMetaDir->GetDirectoryEntries(getter_AddRefs(entries));
-  nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(entries);
-  if (NS_FAILED(rv) || !files) {
-    return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-
-  bool found = false;
-  nsCOMPtr<nsIFile> file;
-  rv = files->GetNextFile(getter_AddRefs(file));
-
-  while (NS_SUCCEEDED(rv) && file) {
-    nsAutoString leafname;
-    rv = file->GetLeafName(leafname);
-    if (NS_SUCCEEDED(rv)) {
-      if (StringEndsWith(leafname, NS_LITERAL_STRING(".rsa"))) {
-        if (!found) {
-          found = true;
-          aFilename = leafname;
-        } else {
-          // second signature file is an error
-          rv = NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-          break;
-        }
-      }
-      rv = files->GetNextFile(getter_AddRefs(file));
-    }
-  }
-
-  if (!found) {
-    rv = NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-
-  files->Close();
-  return rv;
-}
-
-// Loads the signature metadata file that matches the given filename in
-// the passed-in Meta-inf directory. If bufDigest is not null then on
-// success bufDigest will contain the SHA1 or SHA256 digest of the entry
-// (depending on what aDigestAlgorithm is).
-nsresult
-LoadOneMetafile(nsIFile* aMetaDir,
-                const nsAString& aFilename,
-                /*out*/ SECItem& aBuf,
-                /*optional, in*/ SECOidTag aDigestAlgorithm = SEC_OID_SHA1,
-                /*optional, out*/ Digest* aBufDigest = nullptr)
-{
-  nsCOMPtr<nsIFile> metafile;
-  nsresult rv = aMetaDir->Clone(getter_AddRefs(metafile));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = metafile->Append(aFilename);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool exists;
-  rv = metafile->Exists(&exists);
-  if (NS_FAILED(rv) || !exists) {
-    // we can call a missing .rsa file "unsigned" but FindSignatureFilename()
-    // already found one: missing other metadata files means a broken signature.
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  nsCOMPtr<nsIInputStream> stream;
-  rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), metafile);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = ReadStream(stream, aBuf);
-  stream->Close();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aBufDigest) {
-    rv = aBufDigest->DigestBuf(aDigestAlgorithm, aBuf.data, aBuf.len - 1);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
-
-// Parses MANIFEST.MF and verifies the contents of the unpacked files
-// listed in the manifest.
-// The filenames of all entries will be returned in aMfItems. aBuf must
-// be a pre-allocated scratch buffer that is used for doing I/O.
-nsresult
-ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir, SECOidTag aDigestAlgorithm,
-                /*out*/ nsTHashtable<nsStringHashKey>& aMfItems,
-                ScopedAutoSECItem& aBuf)
-{
-  const char* digestNameToFind = nullptr;
-  switch (aDigestAlgorithm) {
-    case SEC_OID_SHA256:
-      digestNameToFind = "sha256-digest";
-      break;
-    case SEC_OID_SHA1:
-      digestNameToFind = "sha1-digest";
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("bad argument to ParseMF");
-      return NS_ERROR_FAILURE;
-  }
-
-  const char* nextLineStart = aFilebuf;
-  nsresult rv = CheckManifestVersion(nextLineStart,
-                                     NS_LITERAL_CSTRING(JAR_MF_HEADER));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Skip the rest of the header section, which ends with a blank line.
-  {
-    nsAutoCString line;
-    do {
-      rv = ReadLine(nextLineStart, line);
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
-    } while (line.Length() > 0);
-
-    // Manifest containing no file entries is OK, though useless.
-    if (*nextLineStart == '\0') {
-      return NS_OK;
-    }
-  }
-
-  nsAutoString curItemName;
-  nsAutoCString digest;
-
-  for (;;) {
-    nsAutoCString curLine;
-    rv = ReadLine(nextLineStart, curLine);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    if (curLine.Length() == 0) {
-      // end of section (blank line or end-of-file)
-
-      if (curItemName.Length() == 0) {
-        // '...Each section must start with an attribute with the name as
-        // "Name",...', so every section must have a Name attribute.
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      if (digest.IsEmpty()) {
-        // We require every entry to have a digest, since we require every
-        // entry to be signed and we don't allow duplicate entries.
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      if (aMfItems.Contains(curItemName)) {
-        // Duplicate entry
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      // Verify that the file's content digest matches the digest from this
-      // MF section.
-      DigestWithAlgorithm digestWithAlgorithm = { digest, aDigestAlgorithm };
-      rv = VerifyFileContentDigest(aDir, curItemName, digestWithAlgorithm,
-                                   aBuf);
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
-
-      aMfItems.PutEntry(curItemName);
-
-      if (*nextLineStart == '\0') {
-        // end-of-file
-        break;
-      }
-
-      // reset so we know we haven't encountered either of these for the next
-      // item yet.
-      curItemName.Truncate();
-      digest.Truncate();
-
-      continue; // skip the rest of the loop below
-    }
-
-    nsAutoCString attrName;
-    nsAutoCString attrValue;
-    rv = ParseAttribute(curLine, attrName, attrValue);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // Lines to look for:
-
-    // (1) Digest:
-    if (attrName.EqualsIgnoreCase(digestNameToFind)) {
-      if (!digest.IsEmpty()) {
-        // multiple SHA* digests in section
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      rv = Base64Decode(attrValue, digest);
-      if (NS_FAILED(rv)) {
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      continue;
-    }
-
-    // (2) Name: associates this manifest section with a file in the jar.
-    if (attrName.LowerCaseEqualsLiteral("name")) {
-      if (MOZ_UNLIKELY(curItemName.Length() > 0)) {
-        // multiple names in section
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      if (MOZ_UNLIKELY(attrValue.Length() == 0)) {
-        return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-      }
-
-      curItemName = NS_ConvertUTF8toUTF16(attrValue);
-
-      continue;
-    }
-
-    // (3) Magic: the only other must-understand attribute
-    if (attrName.LowerCaseEqualsLiteral("magic")) {
-      // We don't understand any magic, so we can't verify an entry that
-      // requires magic. Since we require every entry to have a valid
-      // signature, we have no choice but to reject the entry.
-      return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-    }
-
-    // unrecognized attributes must be ignored
-  }
-
-  return NS_OK;
-}
-
-// recursively check a directory tree for files not in the list of
-// verified files we found in the manifest. For each file we find
-// Check it against the files found in the manifest. If the file wasn't
-// in the manifest then it's unsigned and we can stop looking. Otherwise
-// remove it from the collection so we can check leftovers later.
-//
-// @param aDir   Directory to check
-// @param aPath  Relative path to that directory (to check against aItems)
-// @param aItems All the files found
-// @param *Filename  signature files that won't be in the manifest
-nsresult
-CheckDirForUnsignedFiles(nsIFile* aDir,
-                         const nsString& aPath,
-                         /* in/out */ nsTHashtable<nsStringHashKey>& aItems,
-                         const nsAString& sigFilename,
-                         const nsAString& sfFilename,
-                         const nsAString& mfFilename)
-{
-  nsCOMPtr<nsISimpleEnumerator> entries;
-  nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries));
-  nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(entries);
-  if (NS_FAILED(rv) || !files) {
-    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
-  }
-
-  bool inMeta = StringBeginsWith(aPath, NS_LITERAL_STRING(JAR_META_DIR));
-
-  while (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsIFile> file;
-    rv = files->GetNextFile(getter_AddRefs(file));
-    if (NS_FAILED(rv) || !file) {
-      break;
-    }
-
-    nsAutoString leafname;
-    rv = file->GetLeafName(leafname);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    nsAutoString curName(aPath + leafname);
-
-    bool isDir;
-    rv = file->IsDirectory(&isDir);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // if it's a directory we need to recurse
-    if (isDir) {
-      curName.AppendLiteral(u"/");
-      rv = CheckDirForUnsignedFiles(file, curName, aItems,
-                                    sigFilename, sfFilename, mfFilename);
-    } else {
-      // The files that comprise the signature mechanism are not covered by the
-      // signature.
-      //
-      // XXX: This is OK for a single signature, but doesn't work for
-      // multiple signatures because the metadata for the other signatures
-      // is not signed either.
-      if (inMeta && ( leafname == sigFilename ||
-                      leafname == sfFilename ||
-                      leafname == mfFilename )) {
-        continue;
-      }
-
-      // make sure the current file was found in the manifest
-      nsStringHashKey* item = aItems.GetEntry(curName);
-      if (!item) {
-        return NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY;
-      }
-
-      // Remove the item so we can check for leftover items later
-      aItems.RemoveEntry(item);
-    }
-  }
-  files->Close();
-  return rv;
-}
-
-/*
- * Verify the signature of a directory structure as if it were a
- * signed JAR file (used for unpacked JARs)
- */
-nsresult
-VerifySignedDirectory(AppTrustedRoot aTrustedRoot,
-                      nsIFile* aDirectory,
-                      /*out, optional */ nsIX509Cert** aSignerCert)
-{
-  NS_ENSURE_ARG_POINTER(aDirectory);
-
-  if (aSignerCert) {
-    *aSignerCert = nullptr;
-  }
-
-  // Make sure there's a META-INF directory
-
-  nsCOMPtr<nsIFile> metaDir;
-  nsresult rv = aDirectory->Clone(getter_AddRefs(metaDir));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  rv = metaDir->Append(NS_LITERAL_STRING(JAR_META_DIR));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  bool exists;
-  rv = metaDir->Exists(&exists);
-  if (NS_FAILED(rv) || !exists) {
-    return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-  bool isDirectory;
-  rv = metaDir->IsDirectory(&isDirectory);
-  if (NS_FAILED(rv) || !isDirectory) {
-    return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-
-  // Find and load the Signature (RSA) file
-
-  nsAutoString sigFilename;
-  rv = FindSignatureFilename(metaDir, sigFilename);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  ScopedAutoSECItem sigBuffer;
-  rv = LoadOneMetafile(metaDir, sigFilename, sigBuffer);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-
-  // Load the signature (SF) file and verify the signature.
-  // The .sf and .rsa files must have the same name apart from the extension.
-
-  nsAutoString sfFilename(Substring(sigFilename, 0, sigFilename.Length() - 3)
-                          + NS_LITERAL_STRING("sf"));
-
-  ScopedAutoSECItem sfBuffer;
-  rv = LoadOneMetafile(metaDir, sfFilename, sfBuffer);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  // Calculate both the SHA-1 and SHA-256 hashes of the signature file - we
-  // don't know what algorithm the PKCS#7 signature used.
-  Digest sfCalculatedSHA1Digest;
-  rv = sfCalculatedSHA1Digest.DigestBuf(SEC_OID_SHA1, sfBuffer.data,
-                                        sfBuffer.len - 1);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  Digest sfCalculatedSHA256Digest;
-  rv = sfCalculatedSHA256Digest.DigestBuf(SEC_OID_SHA256, sfBuffer.data,
-                                          sfBuffer.len - 1);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  sigBuffer.type = siBuffer;
-  UniqueCERTCertList builtChain;
-  SECOidTag digestToUse;
-  rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedSHA1Digest.get(),
-                       sfCalculatedSHA256Digest.get(), digestToUse, builtChain);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  // Get the expected manifest hash from the signed .sf file
-
-  nsAutoCString mfDigest;
-  rv = ParseSF(BitwiseCast<char*, unsigned char*>(sfBuffer.data), digestToUse,
-               mfDigest);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  // Load manifest (MF) file and verify signature
-
-  nsAutoString mfFilename(NS_LITERAL_STRING("manifest.mf"));
-  ScopedAutoSECItem manifestBuffer;
-  Digest mfCalculatedDigest;
-  rv = LoadOneMetafile(metaDir, mfFilename, manifestBuffer, digestToUse,
-                       &mfCalculatedDigest);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  nsDependentCSubstring calculatedDigest(
-    DigestToDependentString(mfCalculatedDigest));
-  if (!mfDigest.Equals(calculatedDigest)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  // Parse manifest and verify signed hash of all listed files
-
-  // Allocate the I/O buffer only once per JAR, instead of once per entry, in
-  // order to minimize malloc/free calls and in order to avoid fragmenting
-  // memory.
-  ScopedAutoSECItem buf(128 * 1024);
-
-  nsTHashtable<nsStringHashKey> items;
-  rv = ParseMFUnpacked(BitwiseCast<char*, unsigned char*>(manifestBuffer.data),
-                       aDirectory, digestToUse, items, buf);
-  if (NS_FAILED(rv)){
-    return rv;
-  }
-
-  // We've checked that everything listed in the manifest exists and is signed
-  // correctly. Now check on disk for extra (unsigned) files.
-  // Deletes found entries from items as it goes.
-  rv = CheckDirForUnsignedFiles(aDirectory, EmptyString(), items,
-                                sigFilename, sfFilename, mfFilename);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // We verified that every entry that we require to be signed is signed. But,
-  // were there any missing entries--that is, entries that are mentioned in the
-  // manifest but missing from the directory tree? (There shouldn't be given
-  // ParseMFUnpacked() checking them all, but it's a cheap sanity check.)
-  if (items.Count() != 0) {
-    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
-  }
-
-  // Return the signer's certificate to the reader if they want it.
-  // XXX: We should return an nsIX509CertList with the whole validated chain.
-  if (aSignerCert) {
-    CERTCertListNode* signerCertNode = CERT_LIST_HEAD(builtChain);
-    if (!signerCertNode || CERT_LIST_END(signerCertNode, builtChain) ||
-        !signerCertNode->cert) {
-      return NS_ERROR_FAILURE;
-    }
-    nsCOMPtr<nsIX509Cert> signerCert =
-      nsNSSCertificate::Create(signerCertNode->cert);
-    NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
-    signerCert.forget(aSignerCert);
-  }
-
-  return NS_OK;
-}
-
-class VerifySignedDirectoryTask final : public CryptoTask
-{
-public:
-  VerifySignedDirectoryTask(AppTrustedRoot aTrustedRoot, nsIFile* aUnpackedJar,
-                            nsIVerifySignedDirectoryCallback* aCallback)
-    : mTrustedRoot(aTrustedRoot)
-    , mDirectory(aUnpackedJar)
-    , mCallback(new nsMainThreadPtrHolder<nsIVerifySignedDirectoryCallback>(
-        "VerifySignedDirectoryTask::mCallback", aCallback))
-  {
-  }
-
-private:
-  virtual nsresult CalculateResult() override
-  {
-    return VerifySignedDirectory(mTrustedRoot,
-                                 mDirectory,
-                                 getter_AddRefs(mSignerCert));
-  }
-
-  virtual void CallCallback(nsresult rv) override
-  {
-    (void) mCallback->VerifySignedDirectoryFinished(rv, mSignerCert);
-  }
-
-  const AppTrustedRoot mTrustedRoot;
-  const nsCOMPtr<nsIFile> mDirectory;
-  nsMainThreadPtrHandle<nsIVerifySignedDirectoryCallback> mCallback;
-  nsCOMPtr<nsIX509Cert> mSignerCert; // out
-};
-
 NS_IMETHODIMP
-nsNSSCertificateDB::VerifySignedDirectoryAsync(
-  AppTrustedRoot aTrustedRoot, nsIFile* aUnpackedJar,
+nsNSSCertificateDB::VerifySignedDirectoryAsync(AppTrustedRoot, nsIFile*,
   nsIVerifySignedDirectoryCallback* aCallback)
 {
-  NS_ENSURE_ARG_POINTER(aUnpackedJar);
   NS_ENSURE_ARG_POINTER(aCallback);
-  RefPtr<VerifySignedDirectoryTask> task(new VerifySignedDirectoryTask(aTrustedRoot,
-                                                                       aUnpackedJar,
-                                                                       aCallback));
-  return task->Dispatch("UnpackedJar");
+  return aCallback->VerifySignedDirectoryFinished(
+    NS_ERROR_SIGNED_JAR_NOT_SIGNED, nullptr);
 }
--- a/security/manager/ssl/nsIX509CertDB.idl
+++ b/security/manager/ssl/nsIX509CertDB.idl
@@ -23,16 +23,18 @@ typedef uint32_t AppTrustedRoot;
 [scriptable, function, uuid(fc2b60e5-9a07-47c2-a2cd-b83b68a660ac)]
 interface nsIOpenSignedAppFileCallback : nsISupports
 {
   void openSignedAppFileFinished(in nsresult rv,
                                  in nsIZipReader aZipReader,
                                  in nsIX509Cert aSignerCert);
 };
 
+// Only relevant while we transition away from legacy add-ons. rv will always be
+// NS_ERROR_SIGNED_JAR_NOT_SIGNED. aSignerCert will always be null.
 [scriptable, function, uuid(d5f97827-622a-488f-be08-d850432ac8ec)]
 interface nsIVerifySignedDirectoryCallback : nsISupports
 {
   void verifySignedDirectoryFinished(in nsresult rv,
                                      in nsIX509Cert aSignerCert);
 };
 
 /**
@@ -252,26 +254,19 @@ interface nsIX509CertDB : nsISupports {
    */
   const AppTrustedRoot DeveloperImportedRoot = 10;
   [must_use]
   void openSignedAppFileAsync(in AppTrustedRoot trustedRoot,
                               in nsIFile aJarFile,
                               in nsIOpenSignedAppFileCallback callback);
 
   /**
-   *  Verifies the signature on a directory representing an unpacked signed
-   *  JAR file. To be considered valid, there must be exactly one signature
-   *  on the directory structure and that signature must have signed every
-   *  entry. Further, the signature must come from a certificate that
-   *  is trusted for code signing.
-   *
-   *  On success NS_OK and the trusted certificate that signed the
-   *  unpacked JAR are returned.
-   *
-   *  On failure, an error code is returned.
+   * Vestigial implementation of verifying signed unpacked add-ons. trustedRoot
+   * and aUnpackedDir are ignored. The callback is always called with
+   * NS_ERROR_SIGNED_JAR_NOT_SIGNED and a null signer cert.
    */
   [must_use]
   void verifySignedDirectoryAsync(in AppTrustedRoot trustedRoot,
                                   in nsIFile aUnpackedDir,
                                   in nsIVerifySignedDirectoryCallback callback);
 
   /*
    * Add a cert to a cert DB from a binary string.
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -91,19 +91,21 @@ private:
   // On the main thread, a channel is set up to perform the request. This gets
   // dispatched to necko. At the same time, a timeout timer is initialized. If
   // the necko request completes, the response data is filled out, mNotifiedDone
   // is set to true, and the monitor is notified. The original thread then wakes
   // up and continues with the results that have been filled out. If the request
   // times out, again the response data is filled out, mNotifiedDone is set to
   // true, and the monitor is notified. The first of these two events wins. That
   // is, if the timeout timer fires but the request completes shortly after, the
-  // caller will see the request as having timed out, and vice-versa. (Also note
-  // that no effort is made to cancel either the request or the timeout timer if
-  // the other event completes first.)
+  // caller will see the request as having timed out.
+  // When the request completes (i.e. OnStreamComplete runs), the timer will be
+  // cancelled. This is how we know the closure in OnTimeout is valid. If the
+  // timer fires before OnStreamComplete runs, it should be safe to not cancel
+  // the request because necko has a strong reference to it.
   Monitor mMonitor;
   bool mNotifiedDone;
   nsCOMPtr<nsIStreamLoader> mLoader;
   const nsCString mAIALocation;
   const OriginAttributes mOriginAttributes;
   const Vector<uint8_t> mPOSTData;
   const TimeDuration mTimeout;
   nsCOMPtr<nsITimer> mTimeoutTimer;
@@ -356,16 +358,19 @@ OCSPRequest::NotifyDone(nsresult rv, Mon
     return NS_ERROR_FAILURE;
   }
 
   if (mNotifiedDone) {
     return mResponseResult;
   }
   mLoader = nullptr;
   mResponseResult = rv;
+  if (mTimeoutTimer) {
+    Unused << mTimeoutTimer->Cancel();
+  }
   mNotifiedDone = true;
   lock.Notify();
   return rv;
 }
 
 NS_IMETHODIMP
 OCSPRequest::OnStreamComplete(nsIStreamLoader* aLoader,
                               nsISupports* aContext,
@@ -425,16 +430,19 @@ OCSPRequest::OnStreamComplete(nsIStreamL
 void
 OCSPRequest::OnTimeout(nsITimer* timer, void* closure)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!NS_IsMainThread()) {
     return;
   }
 
+  // We know the OCSPRequest is still alive because if the request had completed
+  // (i.e. OnStreamComplete ran), the timer would have been cancelled in
+  // NotifyDone.
   OCSPRequest* self = static_cast<OCSPRequest*>(closure);
   MonitorAutoLock lock(self->mMonitor);
   self->mTimeoutTimer = nullptr;
   self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
 }
 
 mozilla::pkix::Result
 DoOCSPRequest(const nsCString& aiaLocation,
--- a/security/manager/ssl/tests/unit/test_signed_dir.js
+++ b/security/manager/ssl/tests/unit/test_signed_dir.js
@@ -1,15 +1,14 @@
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/publicdomain/zero/1.0/
 "use strict";
 
-// Tests that signed extensions extracted/unpacked into a directory work pass
-// verification when non-tampered, and fail verification when tampered via
-// various means.
+// Tests that signed extensions extracted/unpacked into a directory do not pass
+// signature verification, because that's no longer supported.
 
 const { ZipUtils } = ChromeUtils.import("resource://gre/modules/ZipUtils.jsm", {});
 
 do_get_profile(); // must be called before getting nsIX509CertDB
 const certdb = Cc["@mozilla.org/security/x509certdb;1"]
                  .getService(Ci.nsIX509CertDB);
 
 /**
@@ -23,179 +22,47 @@ var gSignedXPI =
 /**
  * The directory that the test extension will be extracted to.
  * @type nsIFile
  */
 var gTarget = FileUtils.getDir("TmpD", ["test_signed_dir"]);
 gTarget.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
 /**
- * Each property below is optional. Defining none of them means "don't tamper".
- *
- * @typedef {TamperInstructions}
- * @type Object
- * @property {String[][]} copy
- *           Format: [[path,newname], [path2,newname2], ...]
- *           Copy the file located at |path| and name it |newname|.
- * @property {String[]} delete
- *           List of paths to files to delete.
- * @property {String[]} corrupt
- *           List of paths to files to corrupt.
- */
-
-/**
  * Extracts the signed XPI into a directory, and tampers the files in that
  * directory if instructed.
  *
- * @param {TamperInstructions} tamper
- *        Instructions on whether to tamper any files, and if so, how.
  * @returns {nsIFile}
  *          The directory where the XPI was extracted to.
  */
-function prepare(tamper) {
+function prepare() {
   ZipUtils.extractFiles(gSignedXPI, gTarget);
-
-  // copy files
-  if (tamper.copy) {
-    tamper.copy.forEach(i => {
-      let f = gTarget.clone();
-      i[0].split("/").forEach(seg => { f.append(seg); });
-      f.copyTo(null, i[1]);
-    });
-  }
-
-  // delete files
-  if (tamper.delete) {
-    tamper.delete.forEach(i => {
-      let f = gTarget.clone();
-      i.split("/").forEach(seg => { f.append(seg); });
-      f.remove(true);
-    });
-  }
-
-  // corrupt files
-  if (tamper.corrupt) {
-    tamper.corrupt.forEach(i => {
-      let f = gTarget.clone();
-      i.split("/").forEach(seg => { f.append(seg); });
-      let s = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY);
-      const str = "Kilroy was here";
-      s.write(str, str.length);
-      s.close();
-    });
-  }
-
   return gTarget;
 }
 
 function checkResult(expectedRv, dir, resolve) {
   return function verifySignedDirCallback(rv, aSignerCert) {
     equal(rv, expectedRv, "Actual and expected return value should match");
     equal(aSignerCert != null, Components.isSuccessCode(expectedRv),
           "expecting certificate:");
     dir.remove(true);
     resolve();
   };
 }
 
-function verifyDirAsync(expectedRv, tamper) {
-  let targetDir = prepare(tamper);
+function verifyDirAsync(expectedRv) {
+  let targetDir = prepare();
   return new Promise((resolve, reject) => {
     certdb.verifySignedDirectoryAsync(
       Ci.nsIX509CertDB.AddonsPublicRoot, targetDir,
       checkResult(expectedRv, targetDir, resolve));
   });
 }
 
-//
-// the tests
-//
-add_task(async function testValid() {
-  await verifyDirAsync(Cr.NS_OK, {} /* no tampering */);
-});
-
-add_task(async function testNoMetaDir() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED,
-                       {delete: ["META-INF"]});
-});
-
-add_task(async function testEmptyMetaDir() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED,
-                       {delete: ["META-INF/mozilla.rsa",
-                                 "META-INF/mozilla.sf",
-                                 "META-INF/manifest.mf"]});
-});
-
-add_task(async function testTwoRSAFiles() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {copy: [["META-INF/mozilla.rsa", "extra.rsa"]]});
-});
-
-add_task(async function testCorruptRSAFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {corrupt: ["META-INF/mozilla.rsa"]});
-});
-
-add_task(async function testMissingSFFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {delete: ["META-INF/mozilla.sf"]});
-});
-
-add_task(async function testCorruptSFFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {corrupt: ["META-INF/mozilla.sf"]});
-});
-
-add_task(async function testExtraInvalidSFFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
-                       {copy: [["META-INF/mozilla.rsa", "extra.sf"]]});
-});
-
-add_task(async function testExtraValidSFFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
-                       {copy: [["META-INF/mozilla.sf", "extra.sf"]]});
-});
-
-add_task(async function testMissingManifest() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {delete: ["META-INF/manifest.mf"]});
-});
-
-add_task(async function testCorruptManifest() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
-                       {corrupt: ["META-INF/manifest.mf"]});
-});
-
-add_task(async function testMissingFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
-                       {delete: ["bootstrap.js"]});
-});
-
-add_task(async function testCorruptFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
-                       {corrupt: ["bootstrap.js"]});
-});
-
-add_task(async function testExtraFile() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
-                       {copy: [["bootstrap.js", "extra"]]});
-});
-
-add_task(async function testMissingFileInDir() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
-                       {delete: ["lib/ui.js"]});
-});
-
-add_task(async function testCorruptFileInDir() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
-                       {corrupt: ["lib/ui.js"]});
-});
-
-add_task(async function testExtraFileInDir() {
-  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
-                       {copy: [["lib/ui.js", "extra"]]});
+add_task(async function testAPIFails() {
+  await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED);
 });
 
 registerCleanupFunction(function() {
   if (gTarget.exists()) {
     gTarget.remove(true);
   }
 });
--- a/services/common/remote-settings.js
+++ b/services/common/remote-settings.js
@@ -120,21 +120,21 @@ async function fetchLatestChanges(url, l
   }
 
   return {changes, currentEtag, serverTimeMillis, backoffSeconds};
 }
 
 
 class RemoteSettingsClient {
 
-  constructor(collectionName, { lastCheckTimePref, bucketName, signerName }) {
+  constructor(collectionName, { bucketName, signerName, lastCheckTimePref }) {
     this.collectionName = collectionName;
-    this.lastCheckTimePref = lastCheckTimePref;
     this.bucketName = bucketName;
     this.signerName = signerName;
+    this._lastCheckTimePref = lastCheckTimePref;
 
     this._callbacks = new Map();
     this._callbacks.set("sync", []);
 
     this._kinto = null;
   }
 
   get identifier() {
@@ -142,16 +142,20 @@ class RemoteSettingsClient {
   }
 
   get filename() {
     // Replace slash by OS specific path separator (eg. Windows)
     const identifier = OS.Path.join(...this.identifier.split("/"));
     return `${identifier}.json`;
   }
 
+  get lastCheckTimePref() {
+    return this._lastCheckTimePref || `services.settings.${this.bucketName}.${this.collectionName}.last_check`;
+  }
+
   on(event, callback) {
     if (!this._callbacks.has(event)) {
       throw new Error(`Unknown event type ${event}`);
     }
     this._callbacks.get(event).push(callback);
   }
 
   /**
@@ -410,22 +414,16 @@ class RemoteSettingsClient {
   }
 
   /**
    * Save last time server was checked in users prefs.
    *
    * @param {Date} serverTime   the current date return by server.
    */
   _updateLastCheck(serverTime) {
-    if (!this.lastCheckTimePref) {
-      // If not set (default), it is not necessary to store the last check timestamp.
-      return;
-    }
-    // Storing the last check time is mainly a matter of retro-compatibility with
-    // the blocklists clients.
     const checkedServerTimeInSeconds = Math.round(serverTime / 1000);
     Services.prefs.setIntPref(this.lastCheckTimePref, checkedServerTimeInSeconds);
   }
 }
 
 
 function remoteSettingsFunction() {
   const _clients = new Map();
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -122,16 +122,19 @@ add_task(async function test_list_is_wri
     const content = await readJSON(profFile.path);
     equal(content.data[0].blockID, testData[testData.length - 1]);
   }
 });
 add_task(clear_state);
 
 add_task(async function test_current_server_time_is_saved_in_pref() {
   for (let {client} of gBlocklistClients) {
+    // The lastCheckTimePref was customized:
+    ok(/services\.blocklist\.(\w+)\.checked/.test(client.lastCheckTimePref), client.lastCheckTimePref);
+
     const serverTime = Date.now();
     await client.maybeSync(2000, serverTime);
     const after = Services.prefs.getIntPref(client.lastCheckTimePref);
     equal(after, Math.round(serverTime / 1000));
   }
 });
 add_task(clear_state);
 
--- a/services/common/tests/unit/test_remote_settings.js
+++ b/services/common/tests/unit/test_remote_settings.js
@@ -74,16 +74,25 @@ add_task(async function test_records_obt
 
   // Open the collection, verify it's been populated:
   // Our test data has a single record; it should be in the local collection
   const list = await client.get();
   equal(list.length, 1);
 });
 add_task(clear_state);
 
+add_task(async function test_current_server_time_is_saved_in_pref() {
+  const serverTime = Date.now();
+  await client.maybeSync(2000, serverTime);
+  equal(client.lastCheckTimePref, "services.settings.main.password-fields.last_check");
+  const after = Services.prefs.getIntPref(client.lastCheckTimePref);
+  equal(after, Math.round(serverTime / 1000));
+});
+add_task(clear_state);
+
 add_task(async function test_records_changes_are_overwritten_by_server_changes() {
   // Create some local conflicting data, and make sure it syncs without error.
   const collection = await client.openCollection();
   await collection.create({
     "website": "",
     "id": "9d500963-d80e-3a91-6e74-66f3811b99cc"
   }, { useRecordId: true });
 
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -10,16 +10,18 @@ treeherder:
         'Fxfn-l-e10s': 'Firefox functional tests (local) with e10s'
         'Fxfn-r': 'Firefox functional tests (remote)'
         'Fxfn-r-e10s': 'Firefox functional tests (remote) with e10s'
         'M': 'Mochitests'
         'M-e10s': 'Mochitests with e10s'
         'M-V': 'Mochitests on Valgrind'
         'R': 'Reftests'
         'R-e10s': 'Reftests with e10s'
+        'Rap': 'Raptor performance tests on Firefox'
+        'Rap-e10s': 'Raptor performance tests on Firefox with e10s'
         'T': 'Talos performance tests'
         'Tsd': 'Talos performance tests with Stylo disabled'
         'Tss': 'Talos performance tests with Stylo sequential'
         'T-e10s': 'Talos performance tests with e10s'
         'Tsd-e10s': 'Talos performance tests with e10s, Stylo disabled'
         'Tss-e10s': 'Talos performance tests with e10s, Stylo sequential'
         'T-P-e10s': 'Talos performance tests with e10s and gecko profiling'
         'tt-c': 'Telemetry client marionette tests'
--- a/taskcluster/ci/docker-image/kind.yml
+++ b/taskcluster/ci/docker-image/kind.yml
@@ -30,16 +30,17 @@ jobs:
       SNAPSHOT: '20171210T214726Z'
     packages:
       - deb7-gdb
       - deb7-git
       - deb7-make
       - deb7-mercurial
       - deb7-python
       - deb7-python3.5
+      - deb7-python3-defaults
       - deb7-xz-utils
   toolchain-build:
     symbol: I(toolchain)
     parent: debian7-base
     packages:
       - deb7-cmake
       - deb7-ninja
   debian7-amd64-build:
--- a/taskcluster/ci/packages/kind.yml
+++ b/taskcluster/ci/packages/kind.yml
@@ -42,16 +42,30 @@ jobs:
     run:
       using: debian-package
       dsc:
         url: http://snapshot.debian.org/archive/debian/20170119T211826Z/pool/main/p/python3.5/python3.5_3.5.3-1.dsc
         sha256: 5259cbb15bb93f7bdfbe9ce03a972ea47f81c86057d5939ef9ce578414b2f1de
       patch: python3.5-wheezy.diff
       pre-build-command: debian/rules control-file
 
+  deb7-python3-defaults:
+    description: "python3-defaults backport for Debian wheezy"
+    treeherder:
+      symbol: Deb7(python3-defaults)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20170120T212942Z/pool/main/p/python3-defaults/python3-defaults_3.5.3-1.dsc
+        sha256: 2bec1dd8a5836d5a19fbbd48d7c49aec40642669036297a34bbfd8b0b2d61439
+      packages:
+        - deb7-python3.5
+      patch: python3-defaults-wheezy.diff
+      pre-build-command: debian/rules control-file
+
   deb7-cmake:
     description: "Cmake backport for Debian wheezy"
     treeherder:
       symbol: Deb7(cmake)
     run:
       using: debian-package
       dsc:
         url: http://snapshot.debian.org/archive/debian/20161204T034107Z/pool/main/c/cmake/cmake_3.7.1-1.dsc
--- a/taskcluster/ci/test/kind.yml
+++ b/taskcluster/ci/test/kind.yml
@@ -21,12 +21,13 @@ transforms:
 
 jobs-from:
     - awsy.yml
     - compiled.yml
     - firefox-ui.yml
     - marionette.yml
     - misc.yml
     - mochitest.yml
+    - raptor.yml
     - reftest.yml
     - talos.yml
     - web-platform.yml
     - xpcshell.yml
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/test/raptor.yml
@@ -0,0 +1,40 @@
+job-defaults:
+    max-run-time: 1800
+    suite: raptor
+    tier:
+        by-test-platform:
+            windows10-64-ccov/.*: 3
+            linux64-ccov/.*: 3
+            default: 3
+    virtualization:
+        by-test-platform:
+            windows10-64-ccov/.*: virtual
+            default: hardware
+    mozharness:
+        script: raptor_script.py
+        no-read-buildbot-config: true
+        config:
+            by-test-platform:
+                macosx.*:
+                    - raptor/mac_config.py
+                windows.*:
+                    - raptor/windows_config.py
+                windows10-64-ccov/debug:
+                    - raptor/windows_vm_config.py
+                linux64-ccov/opt:
+                    - raptor/linux64_config_taskcluster.py
+                default:
+                    - raptor/linux_config.py
+
+raptor-firefox-tp6:
+    description: "Raptor Firefox tp6"
+    try-name: raptor-firefox-tp6
+    treeherder-symbol: Rap(tp6)
+    run-on-projects:
+        by-test-platform:
+            .*-qr/.*: ['try']
+            default: ['try']
+    max-run-time: 1200
+    mozharness:
+        extra-options:
+            - --test=raptor-firefox-tp6
--- a/taskcluster/ci/test/test-platforms.yml
+++ b/taskcluster/ci/test/test-platforms.yml
@@ -237,16 +237,17 @@ macosx64/debug:
 
 macosx64/opt:
     build-platform: macosx64/opt
     test-sets:
         - macosx64-talos
         - macosx64-tests
         - desktop-screenshot-capture
         - awsy
+        - macosx64-raptor
 
 macosx64-nightly/opt:
     build-platform: macosx64-nightly/opt
     test-sets:
         - macosx64-tests
         - macosx64-talos-profiling
         - awsy
 
--- a/taskcluster/ci/test/test-sets.yml
+++ b/taskcluster/ci/test/test-sets.yml
@@ -305,16 +305,19 @@ macosx64-talos-profiling:
     - talos-tp5o-profiling
     - talos-tp6-profiling
     # - talos-tps-profiling # Bug 1453007 times out
 
 macosx64-qr-tests:
     - reftest
     - reftest-fonts
 
+macosx64-raptor:
+    - raptor-firefox-tp6
+
 linux32-tests:
     - cppunit
     - crashtest
     - firefox-ui-functional-local
     - firefox-ui-functional-remote
     - gtest
     - jittest
     - jsreftest
--- a/taskcluster/docker/debian-base/Dockerfile
+++ b/taskcluster/docker/debian-base/Dockerfile
@@ -50,16 +50,17 @@ RUN /usr/local/sbin/setup_packages.sh $D
     echo 'dir::bin::methods::https "/usr/local/sbin/cloud-mirror-workaround.sh";' > /etc/apt/apt.conf.d/99cloud-mirror-workaround && \
     apt-get update && \
     apt-get install \
       git \
       make \
       mercurial \
       python \
       python3.5 \
+      python3-minimal \
       xz-utils
 
 # %include testing/mozharness/external_tools/robustcheckout.py
 COPY topsrcdir/testing/mozharness/external_tools/robustcheckout.py /usr/local/mercurial/robustcheckout.py
 
 # %include taskcluster/docker/recipes/hgrc
 COPY topsrcdir/taskcluster/docker/recipes/hgrc /etc/mercurial/hgrc.d/mozilla.rc
 
--- a/taskcluster/docs/attributes.rst
+++ b/taskcluster/docs/attributes.rst
@@ -96,16 +96,21 @@ unittest_try_name
 This is the name used to refer to a unit test via try syntax.  It
 may not match either of ``unittest_suite`` or ``unittest_flavor``.
 
 talos_try_name
 ==============
 
 This is the name used to refer to a talos job via try syntax.
 
+raptor_try_name
+===============
+
+This is the name used to refer to a raptor job via try syntax.
+
 job_try_name
 ============
 
 This is the name used to refer to a "job" via try syntax (``-j``).  Note that for
 some kinds, ``-j`` also matches against ``build_platform``.
 
 test_chunk
 ==========
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -65,17 +65,18 @@ def filter_beta_release_tasks(task, para
         return False
 
     if platform in (
             'linux', 'linux64',
             'macosx64',
             'win32', 'win64',
             ):
         if task.attributes['build_type'] == 'opt' and \
-           task.attributes.get('unittest_suite') != 'talos':
+           task.attributes.get('unittest_suite') != 'talos' and \
+           task.attributes.get('unittest_suite') != 'raptor':
             return False
 
     # skip l10n, beetmover, balrog
     if task.kind in ignore_kinds:
         return False
 
     # No l10n repacks per push. They may be triggered by kinds which depend
     # on l10n builds/repacks. For instance: "repackage-signing"
@@ -124,16 +125,21 @@ def _try_option_syntax(full_task_graph, 
             task.attributes['task_duplicates'] = options.trigger_tests
             task.attributes['profile'] = False
 
         # If the developer wants test talos jobs to be rebuilt N times we add that value here
         if options.talos_trigger_tests > 1 and task.attributes.get('unittest_suite') == 'talos':
             task.attributes['task_duplicates'] = options.talos_trigger_tests
             task.attributes['profile'] = options.profile
 
+        # If the developer wants test raptor jobs to be rebuilt N times we add that value here
+        if options.raptor_trigger_tests > 1 and task.attributes.get('unittest_suite') == 'raptor':
+            task.attributes['task_duplicates'] = options.raptor_trigger_tests
+            task.attributes['profile'] = options.profile
+
         task.attributes.update(attributes)
 
     # Add notifications here as well
     if options.notifications:
         for task in full_task_graph:
             owner = parameters.get('owner')
             routes = task.task.setdefault('routes', [])
             if options.notifications == 'all':
@@ -190,16 +196,19 @@ def target_tasks_ash(full_task_graph, pa
             return False
         # no non-e10s tests
         if task.attributes.get('unittest_suite'):
             if not task.attributes.get('e10s'):
                 return False
             # don't run talos on ash
             if task.attributes.get('unittest_suite') == 'talos':
                 return False
+            # don't run raptor on ash
+            if task.attributes.get('unittest_suite') == 'raptor':
+                return False
         # don't upload symbols
         if task.attributes['kind'] == 'upload-symbols':
             return False
         return True
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('cedar_tasks')
--- a/taskcluster/taskgraph/test/test_target_tasks.py
+++ b/taskcluster/taskgraph/test/test_target_tasks.py
@@ -15,16 +15,17 @@ from taskgraph.task import Task
 from mozunit import main
 
 
 class FakeTryOptionSyntax(object):
 
     def __init__(self, message, task_graph, graph_config):
         self.trigger_tests = 0
         self.talos_trigger_tests = 0
+        self.raptor_trigger_tests = 0
         self.notifications = None
         self.env = []
         self.profile = False
         self.tag = None
         self.no_retry = False
 
     def task_matches(self, task):
         return 'at-at' in task.attributes
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -484,16 +484,35 @@ def setup_talos(config, tests):
         if config.params.is_try():
             extra_options.append('--branch-name')
             extra_options.append('try')
 
         yield test
 
 
 @transforms.add
+def setup_raptor(config, tests):
+    """Add options that are specific to raptor jobs (identified by suite=raptor)"""
+    for test in tests:
+        if test['suite'] != 'raptor':
+            yield test
+            continue
+
+        extra_options = test.setdefault('mozharness', {}).setdefault('extra-options', [])
+
+        # Per https://bugzilla.mozilla.org/show_bug.cgi?id=1357753#c3, branch
+        # name is only required for try
+        if config.params.is_try():
+            extra_options.append('--branch-name')
+            extra_options.append('try')
+
+        yield test
+
+
+@transforms.add
 def handle_artifact_prefix(config, tests):
     """Handle translating `artifact_prefix` appropriately"""
     for test in tests:
         if test['build-attributes'].get('artifact_prefix'):
             test.setdefault("attributes", {}).setdefault(
                 'artifact_prefix', test['build-attributes']['artifact_prefix']
             )
         yield test
@@ -714,16 +733,20 @@ def enable_code_coverage(config, tests):
                 test['mozharness']['extra-options'].append('--add-option')
                 test['mozharness']['extra-options'].append('--cycles,1')
                 test['mozharness']['extra-options'].append('--add-option')
                 test['mozharness']['extra-options'].append('--tppagecycles,1')
                 test['mozharness']['extra-options'].append('--add-option')
                 test['mozharness']['extra-options'].append('--no-upload-results')
                 test['mozharness']['extra-options'].append('--add-option')
                 test['mozharness']['extra-options'].append('--tptimeout,15000')
+            if 'raptor' in test['test-name']:
+                test['max-run-time'] = 1800
+                if 'linux' in test['build-platform']:
+                    test['docker-image'] = {"in-tree": "desktop1604-test"}
         elif test['build-platform'] == 'linux64-jsdcov/opt':
             # Ensure we don't run on inbound/autoland/beta, but if the test is try only, ignore it
             if 'mozilla-central' in test['run-on-projects'] or \
                     test['run-on-projects'] == 'built-projects':
                 test['run-on-projects'] = ['mozilla-central', 'try']
             test['mozharness'].setdefault('extra-options', []).append('--jsd-code-coverage')
         yield test
 
@@ -752,17 +775,17 @@ def split_e10s(config, tests):
             test['test-name'] += '-e10s'
             test['try-name'] += '-e10s'
             test['e10s'] = True
             test['attributes']['e10s'] = True
             group, symbol = split_symbol(test['treeherder-symbol'])
             if group != '?':
                 group += '-e10s'
             test['treeherder-symbol'] = join_symbol(group, symbol)
-            if test['suite'] == 'talos':
+            if test['suite'] == 'talos' or test['suite'] == 'raptor':
                 for i, option in enumerate(test['mozharness']['extra-options']):
                     if option.startswith('--suite='):
                         test['mozharness']['extra-options'][i] += '-e10s'
             else:
                 test['mozharness']['extra-options'].append('--e10s')
         yield test
 
 
@@ -804,48 +827,48 @@ def split_chunks(config, tests):
 
 def perfile_number_of_chunks(config, type):
     # A rough estimate of how many chunks we need based on simple rules
     # for determining what a test file is.
 
     # TODO: Make this flexible based on coverage vs verify || test type
     tests_per_chunk = 10.0
 
-    if type.startswith('test-verify-wpt'):
-        file_patterns = ['testing/web-platform/tests/**']
-    elif type.startswith('test-verify-gpu'):
-        file_patterns = ['**/*webgl*/**/test_*',
-                         '**/dom/canvas/**/test_*',
-                         '**/gfx/tests/**/test_*',
+    if type.startswith('test-verify-wpt'):
+        file_patterns = ['testing/web-platform/tests/**']
+    elif type.startswith('test-verify-gpu'):
+        file_patterns = ['**/*webgl*/**/test_*',
+                         '**/dom/canvas/**/test_*',
+                         '**/gfx/tests/**/test_*',
                          '**/devtools/canvasdebugger/**/browser_*',
                          '**/reftest*/**']
-    elif type.startswith('test-verify'):
-        file_patterns = ['**/test_*',
-                         '**/browser_*',
-                         '**/crashtest*/**',
-                         'js/src/test/test/',
-                         'js/src/test/non262/',
-                         'js/src/test/test262/']
+    elif type.startswith('test-verify'):
+        file_patterns = ['**/test_*',
+                         '**/browser_*',
+                         '**/crashtest*/**',
+                         'js/src/test/test/',
+                         'js/src/test/non262/',
+                         'js/src/test/test262/']
 
     changed_files = files_changed.get_changed_files(config.params.get('head_repository'),
                                                     config.params.get('head_rev'))
     test_count = 0
-    for pattern in file_patterns:
-        for path in changed_files:
-            if mozpackmatch(path, pattern):
-                gpu = False
-                if type == 'test-verify-e10s':
-                    # file_patterns for test-verify will pick up some gpu tests, lets ignore
-                    # in the case of reftest, we will not have any in the regular case
-                    gpu_dirs = ['dom/canvas', 'gfx/tests', 'devtools/canvasdebugger', 'webgl']
-                    for gdir in gpu_dirs:
-                        if len(path.split(gdir)) > 1:
-                            gpu = True
-
-                if not gpu:
+    for pattern in file_patterns:
+        for path in changed_files:
+            if mozpackmatch(path, pattern):
+                gpu = False
+                if type == 'test-verify-e10s':
+                    # file_patterns for test-verify will pick up some gpu tests, lets ignore
+                    # in the case of reftest, we will not have any in the regular case
+                    gpu_dirs = ['dom/canvas', 'gfx/tests', 'devtools/canvasdebugger', 'webgl']
+                    for gdir in gpu_dirs:
+                        if len(path.split(gdir)) > 1:
+                            gpu = True
+
+                if not gpu:
                     test_count += 1
 
     chunks = test_count/tests_per_chunk
     return int(math.ceil(chunks))
 
 
 @transforms.add
 def allow_software_gl_layers(config, tests):
@@ -993,16 +1016,18 @@ def make_job_description(config, tests):
         if test['chunks'] > 1:
             label += '-{}'.format(test['this-chunk'])
 
         build_label = test['build-label']
 
         try_name = test['try-name']
         if test['suite'] == 'talos':
             attr_try_name = 'talos_try_name'
+        elif test['suite'] == 'raptor':
+            attr_try_name = 'raptor_try_name'
         else:
             attr_try_name = 'unittest_try_name'
 
         attr_build_platform, attr_build_type = test['build-platform'].split('/', 1)
 
         attributes = test.get('attributes', {})
         attributes.update({
             'build_platform': attr_build_platform,
--- a/taskcluster/taskgraph/try_option_syntax.py
+++ b/taskcluster/taskgraph/try_option_syntax.py
@@ -196,25 +196,28 @@ def parse_message(message):
     # Argument parser based on try flag flags
     parser = argparse.ArgumentParser()
     parser.add_argument('-b', '--build', dest='build_types')
     parser.add_argument('-p', '--platform', nargs='?',
                         dest='platforms', const='all', default='all')
     parser.add_argument('-u', '--unittests', nargs='?',
                         dest='unittests', const='all', default='all')
     parser.add_argument('-t', '--talos', nargs='?', dest='talos', const='all', default='none')
+    parser.add_argument('-r', '--raptor', nargs='?', dest='raptor', const='all', default='none')
     parser.add_argument('-i', '--interactive',
                         dest='interactive', action='store_true', default=False)
     parser.add_argument('-e', '--all-emails',
                         dest='notifications', action='store_const', const='all')
     parser.add_argument('-f', '--failure-emails',
                         dest='notifications', action='store_const', const='failure')
     parser.add_argument('-j', '--job', dest='jobs', action='append')
     parser.add_argument('--rebuild-talos', dest='talos_trigger_tests', action='store',
                         type=int, default=1)
+    parser.add_argument('--rebuild-raptor', dest='raptor_trigger_tests', action='store',
+                        type=int, default=1)
     parser.add_argument('--setenv', dest='env', action='append')
     parser.add_argument('--geckoProfile', dest='profile', action='store_true')
     parser.add_argument('--tag', dest='tag', action='store', default=None)
     parser.add_argument('--no-retry', dest='no_retry', action='store_true')
     parser.add_argument('--include-nightly', dest='include_nightly', action='store_true')
 
     # While we are transitioning from BB to TC, we want to push jobs to tc-worker
     # machines but not overload machines with every try push. Therefore, we add
@@ -258,38 +261,42 @@ class TryOptionSyntax(object):
         }
         """
         self.graph_config = graph_config
         self.jobs = []
         self.build_types = []
         self.platforms = []
         self.unittests = []
         self.talos = []
+        self.raptor = []
         self.trigger_tests = 0
         self.interactive = False
         self.notifications = None
         self.talos_trigger_tests = 0
+        self.raptor_trigger_tests = 0
         self.env = []
         self.profile = False
         self.tag = None
         self.no_retry = False
 
         options = parameters['try_options']
         if not options:
             return None
         self.jobs = self.parse_jobs(options['jobs'])
         self.build_types = self.parse_build_types(options['build_types'], full_task_graph)
         self.platforms = self.parse_platforms(options['platforms'], full_task_graph)
         self.unittests = self.parse_test_option(
             "unittest_try_name", options['unittests'], full_task_graph)
         self.talos = self.parse_test_option("talos_try_name", options['talos'], full_task_graph)
+        self.raptor = self.parse_test_option("raptor_try_name", options['raptor'], full_task_graph)
         self.trigger_tests = options['trigger_tests']
         self.interactive = options['interactive']
         self.notifications = options['notifications']
         self.talos_trigger_tests = options['talos_trigger_tests']
+        self.raptor_trigger_tests = options['raptor_trigger_tests']
         self.env = options['env']
         self.profile = options['profile']
         self.tag = options['tag']
         self.no_retry = options['no_retry']
         self.include_nightly = options['include_nightly']
 
     def parse_jobs(self, jobs_arg):
         if not jobs_arg or jobs_arg == ['none']:
@@ -578,17 +585,18 @@ class TryOptionSyntax(object):
 
             # User specified `-j all`
             if self.platforms is not None and attr('build_platform') not in self.platforms:
                 return False  # honor -p for jobs governed by a platform
             # "all" means "everything with `try` in run_on_projects"
             return check_run_on_projects()
         elif attr('kind') == 'test':
             return match_test(self.unittests, 'unittest_try_name') \
-                 or match_test(self.talos, 'talos_try_name')
+                 or match_test(self.talos, 'talos_try_name') \
+                 or match_test(self.raptor, 'raptor_try_name')
         elif attr('kind') in BUILD_KINDS:
             if attr('build_type') not in self.build_types:
                 return False
             elif self.platforms is None:
                 # for "-p all", look for try in the 'run_on_projects' attribute
                 return check_run_on_projects()
             else:
                 if attr('build_platform') not in self.platforms:
@@ -603,18 +611,20 @@ class TryOptionSyntax(object):
                 return '<all>'
             return ', '.join(str(e) for e in list)
 
         return "\n".join([
             "build_types: " + ", ".join(self.build_types),
             "platforms: " + none_for_all(self.platforms),
             "unittests: " + none_for_all(self.unittests),
             "talos: " + none_for_all(self.talos),
+            "raptor" + none_for_all(self.raptor),
             "jobs: " + none_for_all(self.jobs),
             "trigger_tests: " + str(self.trigger_tests),
             "interactive: " + str(self.interactive),
             "notifications: " + str(self.notifications),
             "talos_trigger_tests: " + str(self.talos_trigger_tests),
+            "raptor_trigger_tests: " + str(self.raptor_trigger_tests),
             "env: " + str(self.env),
             "profile: " + str(self.profile),
             "tag: " + str(self.tag),
             "no_retry: " + str(self.no_retry),
         ])
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -45,16 +45,20 @@ class GeckoInstance(object):
         # Do not send Firefox health reports to the production server
         # removed in Firefox 59
         "datareporting.healthreport.about.reportUrl": "http://%(server)s/dummy/abouthealthreport/",
         "datareporting.healthreport.documentServerURI": "http://%(server)s/dummy/healthreport/",
 
         # Do not show datareporting policy notifications which can interfer with tests
         "datareporting.policy.dataSubmissionPolicyBypassNotification": True,
 
+        # Automatically unload beforeunload alerts
+        "dom.disable_beforeunload": True,
+
+        # Disable the ProcessHangMonitor
         "dom.ipc.reportProcessHangs": False,
 
         # No slow script dialogs
         "dom.max_chrome_script_run_time": 0,
         "dom.max_script_run_time": 0,
 
         # Only load extensions from the application and user profile
         # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -165,16 +165,19 @@ const RECOMMENDED_PREFS = new Map([
   ["datareporting.healthreport.logging.consoleEnabled", false],
   ["datareporting.healthreport.service.enabled", false],
   ["datareporting.healthreport.service.firstRun", false],
   ["datareporting.healthreport.uploadEnabled", false],
   ["datareporting.policy.dataSubmissionEnabled", false],
   ["datareporting.policy.dataSubmissionPolicyAccepted", false],
   ["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
 
+  // Automatically unload beforeunload alerts
+  ["dom.disable_beforeunload", true],
+
   // Disable popup-blocker
   ["dom.disable_open_during_load", false],
 
   // Enabling the support for File object creation in the content process
   ["dom.file.createInChild", true],
 
   // Disable the ProcessHangMonitor
   ["dom.ipc.reportProcessHangs", false],
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
@@ -2,16 +2,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/.
 
 from __future__ import absolute_import
 
 import urllib
 
 from marionette_driver import By, errors
+from marionette_driver.marionette import Alert
 
 from marionette_harness import (
     MarionetteTestCase,
     run_if_e10s,
     skip_if_mobile,
     WindowManagerMixin,
 )
 
@@ -375,27 +376,32 @@ class TestClickNavigation(MarionetteTest
         except errors.NoSuchElementException:
             pass
 
     def test_click_link_page_load(self):
         self.marionette.find_element(By.LINK_TEXT, "333333").click()
         self.assertNotEqual(self.marionette.get_url(), self.test_page)
         self.assertEqual(self.marionette.title, "Marionette Test")
 
-    @skip_if_mobile("Bug 1325738 - Modal dialogs block execution of code for Fennec")
-    def test_click_link_page_load_aborted_by_beforeunload(self):
-        page = self.marionette.absolute_url("beforeunload.html")
-        self.marionette.navigate(page)
+    def test_click_link_page_load_dismissed_beforeunload_prompt(self):
+        self.marionette.navigate(inline("""
+          <input type="text"></input>
+          <a href="{}">Click</a>
+          <script>
+            window.addEventListener("beforeunload", function (event) {{
+              event.preventDefault();
+            }});
+          </script>
+        """.format(self.marionette.absolute_url("clicks.html"))))
+        self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
         self.marionette.find_element(By.TAG_NAME, "a").click()
 
-        # click returns immediately when a beforeunload handler is invoked
-        alert = self.marionette.switch_to_alert()
-        alert.dismiss()
-
-        self.assertEqual(self.marionette.get_url(), page)
+        # navigation auto-dismisses beforeunload prompt
+        with self.assertRaises(errors.NoAlertPresentException):
+            Alert(self.marionette).text
 
     def test_click_link_anchor(self):
         self.marionette.find_element(By.ID, "anchor").click()
         self.assertEqual(self.marionette.get_url(), "{}#".format(self.test_page))
 
     def test_click_link_install_addon(self):
         try:
             self.marionette.find_element(By.ID, "install-addon").click()
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
@@ -36,18 +36,16 @@ class TestTabModalAlerts(BaseAlertTestCa
     def setUp(self):
         super(TestTabModalAlerts, self).setUp()
         self.assertTrue(self.marionette.get_pref("prompts.tab_modal.enabled",
                         "Tab modal alerts should be enabled by default."))
 
         self.marionette.navigate(self.marionette.absolute_url("test_tab_modal_dialogs.html"))
 
     def tearDown(self):
-        self.marionette.execute_script("window.onbeforeunload = null;")
-
         # Ensure to close a possible remaining tab modal dialog
         try:
             alert = self.marionette.switch_to_alert()
             alert.dismiss()
 
             self.wait_for_alert_closed()
         except:
             pass
@@ -168,43 +166,16 @@ class TestTabModalAlerts(BaseAlertTestCa
         self.marionette.find_element(By.ID, "tab-modal-prompt").click()
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         alert.send_keys("Some text!")
         alert.dismiss()
         self.wait_for_condition(
             lambda mn: mn.find_element(By.ID, "prompt-result").text == "null")
 
-    def test_onbeforeunload_dismiss(self):
-        start_url = self.marionette.get_url()
-        self.marionette.find_element(By.ID, "onbeforeunload-handler").click()
-        self.wait_for_condition(
-            lambda mn: mn.execute_script("""
-              return window.onbeforeunload !== null;
-            """))
-        self.marionette.navigate("about:blank")
-        self.wait_for_alert()
-        alert = self.marionette.switch_to_alert()
-        self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
-        alert.dismiss()
-        self.assertTrue(self.marionette.get_url().startswith(start_url))
-
-    def test_onbeforeunload_accept(self):
-        self.marionette.find_element(By.ID, "onbeforeunload-handler").click()
-        self.wait_for_condition(
-            lambda mn: mn.execute_script("""
-              return window.onbeforeunload !== null;
-            """))
-        self.marionette.navigate("about:blank")
-        self.wait_for_alert()
-        alert = self.marionette.switch_to_alert()
-        self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
-        alert.accept()
-        self.wait_for_condition(lambda mn: mn.get_url() == "about:blank")
-
     def test_unrelated_command_when_alert_present(self):
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
         self.wait_for_alert()
         with self.assertRaises(errors.UnexpectedAlertOpen):
             self.marionette.find_element(By.ID, "click-result")
 
     def test_modal_is_dismissed_after_unexpected_alert(self):
         self.marionette.find_element(By.ID, "tab-modal-alert").click()
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py
@@ -5,34 +5,37 @@
 from __future__ import absolute_import, print_function
 
 import contextlib
 import os
 import urllib
 
 from marionette_driver import By, errors, expected, Wait
 from marionette_driver.keys import Keys
+from marionette_driver.marionette import Alert
 from marionette_harness import (
     MarionetteTestCase,
     run_if_e10s,
     run_if_manage_instance,
     skip,
     skip_if_mobile,
     WindowManagerMixin,
 )
 
 here = os.path.abspath(os.path.dirname(__file__))
 
 
 BLACK_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==' # noqa
 RED_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=' # noqa
 
+
 def inline(doc):
     return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
 
+
 def inline_image(data):
     return 'data:image/png;base64,%s' % data
 
 
 class BaseNavigationTestCase(WindowManagerMixin, MarionetteTestCase):
 
     def setUp(self):
         super(BaseNavigationTestCase, self).setUp()
@@ -355,64 +358,95 @@ class TestNavigate(BaseNavigationTestCas
             lambda mn: mn.get_url() == "about:addons",
             message="'about:addons' hasn't been loaded")
 
 
 class TestBackForwardNavigation(BaseNavigationTestCase):
 
     def run_bfcache_test(self, test_pages):
         # Helper method to run simple back and forward testcases.
+
+        def check_page_status(page, expected_history_length):
+            if "alert_text" in page:
+                if page["alert_text"] is None:
+                    # navigation auto-dismisses beforeunload prompt
+                    with self.assertRaises(errors.NoAlertPresentException):
+                        Alert(self.marionette).text
+                else:
+                    self.assertEqual(Alert(self.marionette).text, page["alert_text"])
+
+            self.assertEqual(page["url"], self.marionette.get_url())
+            self.assertEqual(self.history_length, expected_history_length)
+
+            if "is_remote" in page:
+                self.assertEqual(page["is_remote"], self.is_remote_tab,
+                                 "'{}' doesn't match expected remoteness state: {}".format(
+                                     page["url"], page["is_remote"]))
+
+            if "callback" in page and callable(page["callback"]):
+                page["callback"]()
+
         for index, page in enumerate(test_pages):
             if "error" in page:
                 with self.assertRaises(page["error"]):
                     self.marionette.navigate(page["url"])
             else:
                 self.marionette.navigate(page["url"])
-            self.assertEqual(page["url"], self.marionette.get_url())
-            self.assertEqual(self.history_length, index + 1)
 
-            if "is_remote" in page:
-                self.assertEqual(page["is_remote"], self.is_remote_tab,
-                                 "'{}' doesn't match expected remoteness state: {}".format(
-                                     page["url"], page["is_remote"]))
+            check_page_status(page, index + 1)
 
         # Now going back in history for all test pages by backward iterating
         # through the list (-1) and skipping the first entry at the end (-2).
         for page in test_pages[-2::-1]:
             if "error" in page:
                 with self.assertRaises(page["error"]):
                     self.marionette.go_back()
             else:
                 self.marionette.go_back()
             self.assertEqual(page["url"], self.marionette.get_url())
 
-        if "is_remote" in page:
-            self.assertEqual(page["is_remote"], self.is_remote_tab,
-                             "'{}' doesn't match expected remoteness state: {}".format(
-                                 page["url"], page["is_remote"]))
+            check_page_status(page, len(test_pages))
 
         # Now going forward in history by skipping the first entry.
         for page in test_pages[1::]:
             if "error" in page:
                 with self.assertRaises(page["error"]):
                     self.marionette.go_forward()
             else:
                 self.marionette.go_forward()
             self.assertEqual(page["url"], self.marionette.get_url())
 
-        if "is_remote" in page:
-            self.assertEqual(page["is_remote"], self.is_remote_tab,
-                             "'{}' doesn't match expected remoteness state: {}".format(
-                                 page["url"], page["is_remote"]))
+            check_page_status(page, len(test_pages))
 
     def test_no_history_items(self):
         # Both methods should not raise a failure if no navigation is possible
         self.marionette.go_back()
         self.marionette.go_forward()
 
+    def test_dismissed_beforeunload_prompt(self):
+        url_beforeunload = inline("""
+          <input type="text">
+          <script>
+            window.addEventListener("beforeunload", function (event) {
+              event.preventDefault();
+            });
+          </script>
+        """)
+
+        def modify_page():
+            self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
+
+        test_pages = [
+            {"url": inline("<p>foobar</p>"), "alert_text": None},
+            {"url": url_beforeunload, "callback": modify_page},
+            {"url": inline("<p>foobar</p>"), "alert_text": None},
+        ]
+
+        self.run_bfcache_test(test_pages)
+
     def test_data_urls(self):
         test_pages = [
             {"url": inline("<p>foobar</p>")},
             {"url": self.test_page_remote},
             {"url": inline("<p>foobar</p>")},
         ]
         self.run_bfcache_test(test_pages)
 
@@ -616,16 +650,32 @@ class TestRefresh(BaseNavigationTestCase
     @skip_if_mobile("Test file is only located on host machine")
     def test_file_url(self):
         self.marionette.navigate(self.test_page_file_url)
         self.assertEqual(self.test_page_file_url, self.marionette.get_url())
 
         self.marionette.refresh()
         self.assertEqual(self.test_page_file_url, self.marionette.get_url())
 
+    def test_dismissed_beforeunload_prompt(self):
+        self.marionette.navigate(inline("""
+          <input type="text">
+          <script>
+            window.addEventListener("beforeunload", function (event) {
+              event.preventDefault();
+            });
+          </script>
+        """))
+        self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
+        self.marionette.refresh()
+
+        # navigation auto-dismisses beforeunload prompt
+        with self.assertRaises(errors.NoAlertPresentException):
+            Alert(self.marionette).text
+
     def test_image(self):
         image = self.marionette.absolute_url('black.png')
 
         self.marionette.navigate(image)
         self.assertEqual(image, self.marionette.get_url())
 
         self.marionette.refresh()
         self.assertEqual(image, self.marionette.get_url())
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
@@ -1,18 +1,25 @@
 # 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/.
 
 from __future__ import absolute_import, print_function
 
+import urllib
+
 from marionette_driver import errors
+from marionette_driver.by import By
 from marionette_harness import MarionetteTestCase, skip
 
 
+def inline(doc):
+    return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
+
+
 class TestServerQuitApplication(MarionetteTestCase):
 
     def tearDown(self):
         if self.marionette.session is None:
             self.marionette.start_session()
 
     def quit(self, flags=None):
         body = None
@@ -280,16 +287,30 @@ class TestQuitRestart(MarionetteTestCase
                 self.marionette.quit(in_app=True, callback=lambda: False)
         finally:
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = timeout
 
     def test_in_app_quit_with_callback_not_callable(self):
         with self.assertRaisesRegexp(ValueError, "is not callable"):
             self.marionette.restart(in_app=True, callback=4)
 
+    def test_in_app_quit_with_dismissed_beforeunload_prompt(self):
+        self.marionette.navigate(inline("""
+          <input type="text">
+          <script>
+            window.addEventListener("beforeunload", function (event) {
+              event.preventDefault();
+            });
+          </script>
+        """))
+
+        self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
+        self.marionette.quit(in_app=True)
+        self.marionette.start_session()
+
     @skip("Bug 1363368 - Wrong window handles after in_app restarts")
     def test_reset_context_after_quit_by_set_context(self):
         if self.marionette.session_capabilities["platformName"] != "windows_nt":
             skip("Bug 1363368 - Wrong window handles after in_app restarts")
 
         # Check that we are in content context which is used by default in
         # Marionette
         self.assertNotIn("chrome://", self.marionette.get_url(),
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
@@ -1,17 +1,24 @@
 # 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/.
 
 from __future__ import absolute_import
 
+import urllib
+
+from marionette_driver.by import By
 from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
 
 
+def inline(doc):
+    return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
+
+
 class TestCloseWindow(WindowManagerMixin, MarionetteTestCase):
 
     def tearDown(self):
         self.close_all_windows()
         self.close_all_tabs()
 
         super(TestCloseWindow, self).tearDown()
 
@@ -59,16 +66,33 @@ class TestCloseWindow(WindowManagerMixin
     def test_close_window_for_browser_tab(self):
         tab = self.open_tab()
         self.marionette.switch_to_window(tab)
 
         window_handles = self.marionette.close()
         self.assertNotIn(tab, window_handles)
         self.assertListEqual(self.start_tabs, window_handles)
 
+    @skip_if_mobile("Needs application independent method to open a new tab")
+    def test_close_window_with_dismissed_beforeunload_prompt(self):
+        tab = self.open_tab()
+        self.marionette.switch_to_window(tab)
+
+        self.marionette.navigate(inline("""
+          <input type="text">
+          <script>
+            window.addEventListener("beforeunload", function (event) {
+              event.preventDefault();
+            });
+          </script>
+        """))
+
+        self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
+        self.marionette.close()
+
     @skip_if_mobile("Interacting with chrome windows not available for Fennec")
     def test_close_window_for_browser_window_with_single_tab(self):
         win = self.open_window()
         self.marionette.switch_to_window(win)
 
         self.assertEqual(len(self.start_tabs) + 1, len(self.marionette.window_handles))
         window_handles = self.marionette.close()
         self.assertNotIn(win, window_handles)
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/www/beforeunload.html
+++ /dev/null
@@ -1,21 +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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Marionette Test</title>
-  <script type="text/javascript">
-    function unload() {
-      window.onbeforeunload = null;
-      return "asdf";
-    }
-
-    window.onbeforeunload = unload;
-  </script>
-</head>
-<body>
-   <a href="empty.html">Click</a> to leave the page.<br/>
-</body>
-</html>
--- a/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html
+++ b/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html
@@ -15,25 +15,20 @@
       var alertAccepted = window.confirm('Marionette confirm');
       document.getElementById('confirm-result').innerHTML = alertAccepted;
     }
 
     function handlePrompt () {
       var promptText = window.prompt('Marionette prompt');
       document.getElementById('prompt-result').innerHTML = promptText === null ? 'null' : promptText;
     }
-
-    function onBeforeUnload () {
-      window.onbeforeunload = function () { return "Are you sure?"; }
-    }
   </script>
 </head>
 <body>
    <a href="#" id="tab-modal-alert" onclick="handleAlert()">Open an alert dialog.</a>
    <a href="#" id="tab-modal-confirm" onclick="handleConfirm()">Open a confirm dialog.</a>
    <a href="#" id="tab-modal-prompt" onclick="handlePrompt()">Open a prompt dialog.</a>
-   <a href="#" id="onbeforeunload-handler" onclick="onBeforeUnload()">Add an onbeforeunload handler.</a>
    <a href="#" id="click-handler" onclick="document.getElementById('click-result').innerHTML='result';">Make text appear.</a>
    <div id="confirm-result"></div>
    <div id="prompt-result"></div>
    <div id="click-result"></div>
 </body>
 </html>
--- a/testing/moz.build
+++ b/testing/moz.build
@@ -114,8 +114,13 @@ with Files("tools/websocketprocessbridge
 with Files("tools/fileid/**"):
     BUG_COMPONENT = ("Toolkit", "Crash Reporting")
 
 with Files("tools/minidumpwriter/**"):
     BUG_COMPONENT = ("Toolkit", "Crash Reporting")
 
 with Files("remote*"):
     BUG_COMPONENT = ("Firefox for Android", "Testing")
+
+with Files("raptor/**"):
+    BUG_COMPONENT = ("Testing", "Raptor")
+    SCHEDULES.exclusive = ['raptor']
+
--- a/testing/mozharness/mozharness/mozilla/testing/raptor.py
+++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py
@@ -158,34 +158,37 @@ class Raptor(TestingMixin, MercurialScri
         if not binary_path:
             self.fatal("Raptor requires a path to the binary.  You can specify binary_path or add download-and-extract to your action list.")
         # raptor options
         if binary_path.endswith('.exe'):
             binary_path = binary_path[:-4]
         options = []
         kw_options = {'binary': binary_path}
         # options overwritten from **kw
-        if 'suite' in self.config:
-            kw_options['suite'] = self.config['suite']
+        if 'test' in self.config:
+            kw_options['test'] = self.config['test']
         if self.config.get('branch'):
             kw_options['branchName'] = self.config['branch']
         if self.symbols_path:
             kw_options['symbolsPath'] = self.symbols_path
         kw_options.update(kw)
         # configure profiling options
         options.extend(self.query_gecko_profile_options())
         # extra arguments
         if args is not None:
             options += args
         if 'raptor_extra_options' in self.config:
             options += self.config['raptor_extra_options']
         if self.config.get('code_coverage', False):
             options.extend(['--code-coverage'])
         for key, value in kw_options.items():
-            options.extend(['--%s' % key, value])
+            if key == "test":
+                options.extend([value])
+            else:
+                options.extend(['--%s' % key, value])
         return options
 
     def populate_webroot(self):
         """Populate the production test slaves' webroots"""
         self.raptor_path = os.path.join(
             self.query_abs_dirs()['abs_test_install_dir'], 'raptor'
         )
 
@@ -315,18 +318,19 @@ class Raptor(TestingMixin, MercurialScri
             self.mkdir_p(env['MOZ_UPLOAD_DIR'])
         env = self.query_env(partial_env=env, log_level=INFO)
         # adjust PYTHONPATH to be able to use raptor as a python package
         if 'PYTHONPATH' in env:
             env['PYTHONPATH'] = self.raptor_path + os.pathsep + env['PYTHONPATH']
         else:
             env['PYTHONPATH'] = self.raptor_path
 
-        # mitmproxy needs path to mozharness when installing the cert
+        # mitmproxy needs path to mozharness when installing the cert, and tooltool
         env['SCRIPTSPATH'] = scripts_path
+        env['EXTERNALTOOLSPATH'] = external_tools_path
 
         if self.repo_path is not None:
             env['MOZ_DEVELOPER_REPO_DIR'] = self.repo_path
         if self.obj_path is not None:
             env['MOZ_DEVELOPER_OBJ_DIR'] = self.obj_path
 
         # sets a timeout for how long raptor should run without output
         output_timeout = self.config.get('raptor_output_timeout', 3600)
--- a/testing/raptor/MANIFEST.in
+++ b/testing/raptor/MANIFEST.in
@@ -1,3 +1,1 @@
-include raptor/preferences/*.json
-include raptor/tests/*.ini
-include requirements.txt
+recursive-include raptor *
\ No newline at end of file
--- a/testing/raptor/raptor/cmdline.py
+++ b/testing/raptor/raptor/cmdline.py
@@ -14,17 +14,20 @@ def create_parser(mach_interface=False):
     add_arg = parser.add_argument
 
     if not mach_interface:
         add_arg('--app', default='firefox', dest='app',
                 help="name of the application we are testing (default: firefox)",
                 choices=['firefox', 'chrome'])
         add_arg('-b', '--binary', required=True, dest='binary',
                 help="path to the browser executable that we are testing")
-
+        add_arg('--branchName', dest="branch_name", default='',
+                help="Name of the branch we are testing on")
+        add_arg('--symbolsPath', dest='symbols_path',
+                help="Path to the symbols for the build we are testing")
     # remaining arg is test name
     add_arg("test",
             nargs="*",
             help="name of raptor test to run")
 
     add_logging_group(parser)
     return parser
 
--- a/testing/raptor/raptor/gen_test_config.py
+++ b/testing/raptor/raptor/gen_test_config.py
@@ -13,20 +13,22 @@ webext_dir = os.path.join(os.path.dirnam
 LOG = get_proxy_logger(component="gen_test_url")
 
 
 def gen_test_config(browser, test, cs_port):
     LOG.info("writing test settings url background js, so webext can get it")
 
     data = """// this file is auto-generated by raptor, do not edit directly
 function getTestConfig() {
-    return {"browser": "%s", "test_settings_url": "http://localhost:%d/%s.json"};
+    return {"browser": "%s",
+            "cs_port": "%d",
+            "test_settings_url": "http://localhost:%d/%s.json"};
 }
 
-""" % (browser, cs_port, test)
+""" % (browser, cs_port, cs_port, test)
 
     webext_background_script = (os.path.join(webext_dir, "auto_gen_test_config.js"))
 
     file = open(webext_background_script, "w")
     file.write(data)
     file.close()
 
     LOG.info("finished writing test config into webext")
--- a/testing/raptor/raptor/playback/mitmproxy.py
+++ b/testing/raptor/raptor/playback/mitmproxy.py
@@ -19,17 +19,24 @@ from mozprocess import ProcessHandler
 from .base import Playback
 
 here = os.path.dirname(os.path.realpath(__file__))
 LOG = get_proxy_logger(component='mitmproxy')
 
 mozharness_dir = os.path.join(here, '../../../mozharness')
 sys.path.insert(0, mozharness_dir)
 
-TOOLTOOL_PATH = os.path.join(mozharness_dir, 'external_tools', 'tooltool.py')
+external_tools_path = os.environ.get('EXTERNALTOOLSPATH', None)
+
+if external_tools_path is not None:
+    # running in production via mozharness
+    TOOLTOOL_PATH = os.path.join(external_tools_path, 'tooltool.py')
+else:
+    # running locally via mach
+    TOOLTOOL_PATH = os.path.join(mozharness_dir, 'external_tools', 'tooltool.py')
 
 # path for mitmproxy certificate, generated auto after mitmdump is started
 # on local machine it is 'HOME', however it is different on production machines
 try:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOME'),
                                      '.mitmproxy', 'mitmproxy-ca-cert.cer')
 except Exception:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'),
--- a/testing/raptor/webext/raptor/runner.js
+++ b/testing/raptor/webext/raptor/runner.js
@@ -12,16 +12,17 @@
 // repo) or 'webkit/PerformanceTests' dir (for benchmarks) first run:
 // 'python -m SimpleHTTPServer 8081'
 // to serve out the pages that we want to prototype with. Also
 // update the manifest content 'matches' accordingly
 
 var browserName;
 var ext;
 var settingsURL = null;
+var cs_port = null;
 var testType;
 var pageCycles = 0;
 var pageCycle = 0;
 var pageCycleDelay = 1000;
 var testURL;
 var testTabID = 0;
 var results = {"page": "", "measurements": {}};
 var getHero = false;
@@ -281,17 +282,17 @@ function verifyResults() {
                   + x + " but only have " + count);
     }
   }
   postToControlServer("results", results);
 }
 
 function postToControlServer(msgType, msgData) {
   // requires 'control server' running at port 8000 to receive results
-  var url = "http://127.0.0.1:8000/";
+  var url = "http://127.0.0.1:" + cs_port + "/";
   var client = new XMLHttpRequest();
   client.onreadystatechange = function() {
     if (client.readyState == XMLHttpRequest.DONE && client.status == 200) {
       console.log("post success");
     }
   };
 
   client.open("POST", url, true);
@@ -327,16 +328,17 @@ function cleanUp() {
   if (browserName === "firefox")
     window.dump("\n__raptor_shutdownBrowser\n");
 
 }
 
 function runner() {
   let config = getTestConfig();
   settingsURL = config.test_settings_url;
+  cs_port = config.cs_port;
   browserName = config.browser;
   getBrowserInfo().then(function() {
     getTestSettings().then(function() {
       if (testType == "benchmark") {
         // webkit benchmark type of test
         console.log("benchmark test start");
       } else if (testType == "pageload") {
         // standard pageload test
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -113,16 +113,17 @@ stage-all: stage-cppunittests
 endif
 
 TEST_PKGS_ZIP := \
   common \
   cppunittest \
   mochitest \
   reftest \
   talos \
+  raptor \
   awsy \
   xpcshell \
   $(NULL)
 
 TEST_PKGS_TARGZ := \
   web-platform \
   $(NULL)
 
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -126944,16 +126944,112 @@
       [
        "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-shapes/shape-outside/shape-image/shape-image-000.html": [
     [
      "/css/css-shapes/shape-outside/shape-image/shape-image-000.html",
      [
       [
        "/css/css-shapes/shape-outside/shape-image/reference/shape-image-000-ref.html",
        "=="
       ]
@@ -298159,16 +298255,21 @@
      {}
     ]
    ],
    "webdriver/tests/delete_cookie/__init__.py": [
     [
      {}
     ]
    ],
+   "webdriver/tests/delete_session/__init__.py": [
+    [
+     {}
+    ]
+   ],
    "webdriver/tests/dismiss_alert/__init__.py": [
     [
      {}
     ]
    ],
    "webdriver/tests/element_clear/__init__.py": [
     [
      {}
@@ -397177,33 +397278,37 @@
     [
      "/webdriver/tests/close_window/close.py",
      {}
     ]
    ],
    "webdriver/tests/close_window/user_prompts.py": [
     [
      "/webdriver/tests/close_window/user_prompts.py",
-     {
-      "timeout": "long"
-     }
+     {}
     ]
    ],
    "webdriver/tests/delete_cookie/delete.py": [
     [
      "/webdriver/tests/delete_cookie/delete.py",
      {}
     ]
    ],
    "webdriver/tests/delete_cookie/user_prompts.py": [
     [
      "/webdriver/tests/delete_cookie/user_prompts.py",
      {}
     ]
    ],
+   "webdriver/tests/delete_session/delete.py": [
+    [
+     "/webdriver/tests/delete_session/delete.py",
+     {}
+    ]
+   ],
    "webdriver/tests/dismiss_alert/dismiss.py": [
     [
      "/webdriver/tests/dismiss_alert/dismiss.py",
      {}
     ]
    ],
    "webdriver/tests/element_clear/clear.py": [
     [
@@ -515629,16 +515734,48 @@
   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-007.html": [
    "c1093645f439fc86272e7e5f71e62daf37240a3f",
    "reftest"
   ],
   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-008.html": [
    "2f2b95904fad670919fae32cb94284118a45566c",
    "reftest"
   ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html": [
+   "2226228acb7badb0145118891235733b62bd5504",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html": [
+   "8bcee868c33ce352ff4435584b01b91a867e2699",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html": [
+   "a8f9bd56d4fe6f508c4251f97ff32b0555c3b8ac",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html": [
+   "f4e6edd54826da5374c63651af925bcb4dc2f7d3",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html": [
+   "764980f1beaedaf608096161525ee1f4326bee18",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html": [
+   "42305d67e0f88ed75bee44edc992c0e92a761597",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html": [
+   "b8294d4201dd68a5c91c6f4da7acb9a352ba0cbc",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html": [
+   "18d2fe95bf79efe975a07b332aad3e0fd0e0f298",
+   "reftest"
+  ],
   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-001.html": [
    "b13df2df3be12ac74a7933794d91558c416b412c",
    "testharness"
   ],
   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-002.html": [
    "dbe8bd280e7f65fc5a1b43f4a211ca8e08a20d5e",
    "testharness"
   ],
@@ -611534,17 +611671,17 @@
    "29891e121def1917c47c70efd19b40ed5f2ea61d",
    "wdspec"
   ],
   "webdriver/tests/close_window/__init__.py": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
   "webdriver/tests/close_window/close.py": [
-   "a98fdaa5d8afe6ddca892e8857c134ba24b0e43a",
+   "8c22860607cb0f3d610888c9816bf2384e2c5445",
    "wdspec"
   ],
   "webdriver/tests/close_window/user_prompts.py": [
    "7b1255736f8772f5790b9bf1e46cbf1c5b1c2dee",
    "wdspec"
   ],
   "webdriver/tests/conftest.py": [
    "c812269d034c9ca1b8c4f136dd5d0cea52f4d0f0",
@@ -611557,16 +611694,24 @@
   "webdriver/tests/delete_cookie/delete.py": [
    "1f0d6b861be1ed682fd87a402908cee186a3987c",
    "wdspec"
   ],
   "webdriver/tests/delete_cookie/user_prompts.py": [
    "65b753bd80a06c3c20b0330f624a4d395fdb7ab2",
    "wdspec"
   ],
+  "webdriver/tests/delete_session/__init__.py": [
+   "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+   "support"
+  ],
+  "webdriver/tests/delete_session/delete.py": [
+   "6cbfd4c20b548e668d6251df9d0a26b0824e6ae1",
+   "wdspec"
+  ],
   "webdriver/tests/dismiss_alert/__init__.py": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
   "webdriver/tests/dismiss_alert/dismiss.py": [
    "e213f1939ff5cc2fbdebb2bd8e9445e284803a60",
    "wdspec"
   ],
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient under vertical-rl and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 50%, transparent 50%);
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 50%, transparent 50%);
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient under vertical-lr and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 50%, transparent 50%);
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 50%, transparent 50%);
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-rl."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-lr."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: sideways-rl</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under sideways-rl."/>
+    <style type="text/css">
+    .container {
+      writing-mode: sideways-rl;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: sideways-lr</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under sideways-lr."/>
+    <style type="text/css">
+    .container {
+      writing-mode: sideways-lr;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the bottom. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the top. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-rl and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-lr and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
--- a/testing/web-platform/tests/tools/webdriver/webdriver/client.py
+++ b/testing/web-platform/tests/tools/webdriver/webdriver/client.py
@@ -347,17 +347,18 @@ class Session(object):
                  host,
                  port,
                  url_prefix="/",
                  capabilities=None,
                  timeout=None,
                  extension=None):
         self.transport = transport.HTTPWireProtocol(
             host, port, url_prefix, timeout=timeout)
-        self.capabilities = capabilities
+        self.requested_capabilities = capabilities
+        self.capabilities = None
         self.session_id = None
         self.timeouts = None
         self.window = None
         self.find = None
         self._element_cache = {}
         self.extension = None
         self.extension_cls = extension
 
@@ -385,18 +386,18 @@ class Session(object):
         self.end()
 
     def start(self):
         if self.session_id is not None:
             return
 
         body = {}
 
-        if self.capabilities is not None:
-            body["capabilities"] = self.capabilities
+        if self.requested_capabilities is not None:
+            body["capabilities"] = self.requested_capabilities
 
         value = self.send_command("POST", "session", body=body)
         self.session_id = value["sessionId"]
         self.capabilities = value["capabilities"]
 
         if self.extension_cls:
             self.extension = self.extension_cls(self)
 
@@ -430,17 +431,23 @@ class Session(object):
             an error.
         """
         response = self.transport.send(
             method, url, body,
             encoder=protocol.Encoder, decoder=protocol.Decoder,
             session=self)
 
         if response.status != 200:
-            raise error.from_response(response)
+            err = error.from_response(response)
+
+            if isinstance(err, error.SessionNotCreatedException):
+                # The driver could have already been deleted the session.
+                self.session_id = None
+
+            raise err
 
         if "value" in response.body:
             value = response.body["value"]
             """
             Edge does not yet return the w3c session ID.
             We want the tests to run in Edge anyway to help with REC.
             In order to run the tests in Edge, we need to hack around
             bug:
--- a/testing/web-platform/tests/webdriver/tests/close_window/close.py
+++ b/testing/web-platform/tests/webdriver/tests/close_window/close.py
@@ -1,9 +1,13 @@
+import pytest
+from webdriver import error
+
 from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
 
 
 def close(session):
     return session.transport.send(
         "DELETE", "session/{session_id}/window".format(**vars(session)))
 
 
 def test_no_browsing_context(session, create_window):
@@ -13,25 +17,52 @@ def test_no_browsing_context(session, cr
     session.close()
     assert new_handle not in session.handles
 
     response = close(session)
     assert_error(response, "no such window")
 
 
 def test_close_browsing_context(session, create_window):
-    handles = session.handles
+    original_handles = session.handles
 
     new_handle = create_window()
     session.window_handle = new_handle
 
     response = close(session)
-    value = assert_success(response, handles)
-    assert session.handles == handles
-    assert new_handle not in value
+    handles = assert_success(response, original_handles)
+    assert session.han