merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 09 Jun 2017 12:58:49 +0200
changeset 411287 1742b1bdadd13a02df95ca690bea9cc42ff40c91
parent 411237 7c9d96bbc400aa77f5310486162abf6b61344b74 (current diff)
parent 411286 35b9efa24066bdf59d333dc357f7c19a71a60f10 (diff)
child 411311 b996f14177a63f5f27d5222e8f1f86e9155e98da
child 411321 7457b240847db66b78493ed3a6d03663173bd745
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.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-inbound to mozilla-central a=merge
devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value.js
devtools/shared/tests/mochitest/test_dom_matrix_2d.html
dom/html/nsTextEditorState.cpp
toolkit/components/extensions/test/mochitest/mochitest-common.ini
toolkit/components/telemetry/Histograms.json
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -211,16 +211,17 @@ static int do_main(int argc, char* argv[
     // no -app flag so we use the compiled-in app data
     config.appData = &sAppData;
     config.appDataPath = kDesktopFolder;
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   sandbox::BrokerServices* brokerServices =
     sandboxing::GetInitializedBrokerServices();
+  sandboxing::NetworkDriveCheck();
   sandboxing::PermissionsService* permissionsService =
     sandboxing::GetPermissionsService();
 #if defined(MOZ_CONTENT_SANDBOX)
   if (!brokerServices) {
     Output("Couldn't initialize the broker services.\n");
     return 255;
   }
 #endif
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -48,17 +48,18 @@ var gPluginHandler = {
         this.showClickToPlayNotification(msg.target, msg.data.plugins, msg.data.showNow,
                                          msg.principal, msg.data.location);
         break;
       case "PluginContent:RemoveNotification":
         this.removeNotification(msg.target, msg.data.name);
         break;
       case "PluginContent:UpdateHiddenPluginUI":
         this.updateHiddenPluginUI(msg.target, msg.data.haveInsecure, msg.data.actions,
-                                  msg.principal, msg.data.location);
+                                  msg.principal, msg.data.location)
+          .catch(Cu.reportError);
         break;
       case "PluginContent:HideNotificationBar":
         this.hideNotificationBar(msg.target, msg.data.name);
         break;
       case "PluginContent:InstallSinglePlugin":
         this.installSinglePlugin(msg.data.pluginInfo);
         break;
       case "PluginContent:ShowPluginCrashedNotification":
@@ -299,20 +300,36 @@ var gPluginHandler = {
 
   hideNotificationBar(browser, name) {
     let notificationBox = gBrowser.getNotificationBox(browser);
     let notification = notificationBox.getNotificationWithValue(name);
     if (notification)
       notificationBox.removeNotification(notification, true);
   },
 
-  updateHiddenPluginUI(browser, haveInsecure, actions,
+  infobarBlockedForURI(uri) {
+    return new Promise((resolve, reject) => {
+      let tableName = Services.prefs.getStringPref("urlclassifier.flashInfobarTable", "");
+      if (!tableName) {
+        resolve(false);
+      }
+      let classifier = Cc["@mozilla.org/url-classifier/dbservice;1"]
+        .getService(Ci.nsIURIClassifier);
+      classifier.asyncClassifyLocalWithTables(uri, tableName, (c, list) => {
+        resolve(list.length > 0);
+      });
+    });
+  },
+
+  async updateHiddenPluginUI(browser, haveInsecure, actions,
                                  principal, location) {
     let origin = principal.originNoSuffix;
 
+    let shouldShowNotification = !(await this.infobarBlockedForURI(browser.documentURI));
+
     // It is possible that we've received a message from the frame script to show
     // the hidden plugin notification for a principal that no longer matches the one
     // that the browser's content now has assigned (ie, the browser has browsed away
     // after the message was sent, but before the message was received). In that case,
     // we should just ignore the message.
     if (!principal.equals(browser.contentPrincipal)) {
       return;
     }
@@ -437,25 +454,27 @@ var gPluginHandler = {
                            notificationBox.PRIORITY_INFO_HIGH, buttons,
                            notificationCallback);
       if (haveInsecure) {
         n.classList.add("pluginVulnerable");
       }
     }
 
     if (actions.length == 0) {
-      hideNotification();
+      shouldShowNotification = false;
+    }
+    if (shouldShowNotification &&
+        Services.perms.testPermissionFromPrincipal(principal, "plugin-hidden-notification") ==
+        Ci.nsIPermissionManager.DENY_ACTION) {
+      shouldShowNotification = false;
+    }
+    if (shouldShowNotification) {
+      showNotification();
     } else {
-      let notificationPermission = Services.perms.testPermissionFromPrincipal(
-        principal, "plugin-hidden-notification");
-      if (notificationPermission == Ci.nsIPermissionManager.DENY_ACTION) {
-        hideNotification();
-      } else {
-        showNotification();
-      }
+      hideNotification();
     }
   },
 
   contextMenuCommand(browser, plugin, command) {
     browser.messageManager.sendAsyncMessage("BrowserPlugins:ContextMenuCommand",
       { command }, { plugin });
   },
 
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -24,16 +24,18 @@ FormAutofillUtils.defineLazyLogGetter(th
 
 /**
  * Handles profile autofill for a DOM Form element.
  * @param {FormLike} form Form that need to be auto filled
  */
 function FormAutofillHandler(form) {
   this.form = form;
   this.fieldDetails = [];
+  this.winUtils = this.form.rootElement.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
+    .getInterface(Ci.nsIDOMWindowUtils);
 }
 
 FormAutofillHandler.prototype = {
   /**
    * DOM Form element to which this object is attached.
    */
   form: null,
 
@@ -53,16 +55,33 @@ FormAutofillHandler.prototype = {
   fieldDetails: null,
 
   /**
    * String of the filled profile's guid.
    */
   filledProfileGUID: null,
 
   /**
+   * A WindowUtils reference of which Window the form belongs
+   */
+  winUtils: null,
+
+  /**
+   * Enum for form autofill MANUALLY_MANAGED_STATES values
+   */
+  fieldStateEnum: {
+    // not themed
+    NORMAL: null,
+    // highlighted
+    AUTO_FILLED: "-moz-autofill",
+    // highlighted && grey color text
+    PREVIEW: "-moz-autofill-preview",
+  },
+
+  /**
    * Set fieldDetails from the form about fields that can be autofilled.
    */
   collectFormFields() {
     let fieldDetails = FormAutofillHeuristics.getFormInfo(this.form);
     this.fieldDetails = fieldDetails ? fieldDetails : [];
     log.debug("Collected details on", this.fieldDetails.length, "fields");
   },
 
@@ -82,81 +101,180 @@ FormAutofillHandler.prototype = {
     for (let fieldDetail of this.fieldDetails) {
       // Avoid filling field value in the following cases:
       // 1. the focused input which is filled in FormFillController.
       // 2. a non-empty input field
       // 3. the invalid value set
       // 4. value already chosen in select element
 
       let element = fieldDetail.elementWeakRef.get();
-      if (!element || element === focusedInput) {
+      if (!element) {
         continue;
       }
 
       let value = profile[fieldDetail.fieldName];
-      if (element instanceof Ci.nsIDOMHTMLInputElement && value) {
-        if (element.value) {
-          continue;
+      if (element instanceof Ci.nsIDOMHTMLInputElement && !element.value && value) {
+        if (element !== focusedInput) {
+          element.setUserInput(value);
         }
-        element.setUserInput(value);
+        this.changeFieldState(fieldDetail, "AUTO_FILLED");
       } else if (element instanceof Ci.nsIDOMHTMLSelectElement) {
         for (let option of element.options) {
           if (value === option.textContent || value === option.value) {
             // Do not change value if the option is already selected.
             // Use case for multiple select is not considered here.
             if (option.selected) {
               break;
             }
             // TODO: Using dispatchEvent does not 100% simulate select change.
             //       Should investigate further in Bug 1365895.
             option.selected = true;
             element.dispatchEvent(new Event("input", {"bubbles": true}));
             element.dispatchEvent(new Event("change", {"bubbles": true}));
+            this.changeFieldState(fieldDetail, "AUTO_FILLED");
             break;
           }
         }
       }
+
+      // Unlike using setUserInput directly, FormFillController dispatches an
+      // asynchronous "DOMAutoComplete" event with an "input" event follows right
+      // after. So, we need to suppress the first "input" event fired off from
+      // focused input to make sure the latter change handler won't be affected
+      // by auto filling.
+      if (element === focusedInput) {
+        const suppressFirstInputHandler = e => {
+          if (e.isTrusted) {
+            e.stopPropagation();
+            element.removeEventListener("input", suppressFirstInputHandler);
+          }
+        };
+
+        element.addEventListener("input", suppressFirstInputHandler);
+      }
+      element.previewValue = "";
     }
+
+    // Handle the highlight style resetting caused by user's correction afterward.
+    log.debug("register change handler for filled form:", this.form);
+    const onChangeHandler = e => {
+      let hasFilledFields;
+
+      if (!e.isTrusted) {
+        return;
+      }
+
+      for (let fieldDetail of this.fieldDetails) {
+        let element = fieldDetail.elementWeakRef.get();
+
+        if (!element) {
+          return;
+        }
+
+        if (e.target == element || (e.target == element.form && e.type == "reset")) {
+          this.changeFieldState(fieldDetail, "NORMAL");
+        }
+
+        hasFilledFields |= (fieldDetail.state == "AUTO_FILLED");
+      }
+
+      // Unregister listeners once no field is in AUTO_FILLED state.
+      if (!hasFilledFields) {
+        this.form.rootElement.removeEventListener("input", onChangeHandler);
+        this.form.rootElement.removeEventListener("reset", onChangeHandler);
+      }
+    };
+
+    this.form.rootElement.addEventListener("input", onChangeHandler);
+    this.form.rootElement.addEventListener("reset", onChangeHandler);
   },
 
   /**
    * Populates result to the preview layers with given profile.
    *
    * @param {Object} profile
    *        A profile to be previewed with
    */
   previewFormFields(profile) {
     log.debug("preview profile in autofillFormFields:", profile);
-    /*
+
     for (let fieldDetail of this.fieldDetails) {
+      let element = fieldDetail.elementWeakRef.get();
       let value = profile[fieldDetail.fieldName] || "";
 
-      // Skip the fields that already has text entered
-      if (fieldDetail.element.value) {
+      // Skip the field that is null or already has text entered
+      if (!element || element.value) {
+        continue;
+      }
+
+      element.previewValue = value;
+      this.changeFieldState(fieldDetail, value ? "PREVIEW" : "NORMAL");
+    }
+  },
+
+  /**
+   * Clear preview text and background highlight of all fields.
+   */
+  clearPreviewedFormFields() {
+    log.debug("clear previewed fields in:", this.form);
+
+    for (let fieldDetail of this.fieldDetails) {
+      let element = fieldDetail.elementWeakRef.get();
+      if (!element) {
+        log.warn(fieldDetail.fieldName, "is unreachable");
+        continue;
+      }
+
+      element.previewValue = "";
+
+      // We keep the state if this field has
+      // already been auto-filled.
+      if (fieldDetail.state === "AUTO_FILLED") {
         continue;
       }
 
-      // TODO: Set highlight style and preview text.
+      this.changeFieldState(fieldDetail, "NORMAL");
     }
-    */
   },
 
-  clearPreviewedFormFields() {
-    log.debug("clear previewed fields in:", this.form);
-    /*
-    for (let fieldDetail of this.fieldDetails) {
-      // TODO: Clear preview text
+  /**
+   * Change the state of a field to correspond with different presentations.
+   *
+   * @param {Object} fieldDetail
+   *        A fieldDetail of which its element is about to update the state.
+   * @param {string} nextState
+   *        Used to determine the next state
+   */
+  changeFieldState(fieldDetail, nextState) {
+    let element = fieldDetail.elementWeakRef.get();
 
-      // We keep the highlight of all fields if this form has
-      // already been auto-filled with a profile.
-      if (this.filledProfileGUID == null) {
-        // TODO: Remove highlight style
+    if (!element) {
+      log.warn(fieldDetail.fieldName, "is unreachable while changing state");
+      return;
+    }
+    if (!(nextState in this.fieldStateEnum)) {
+      log.warn(fieldDetail.fieldName, "is trying to change to an invalid state");
+      return;
+    }
+
+    for (let [state, mmStateValue] of Object.entries(this.fieldStateEnum)) {
+      // The NORMAL state is simply the absence of other manually
+      // managed states so we never need to add or remove it.
+      if (!mmStateValue) {
+        continue;
+      }
+
+      if (state == nextState) {
+        this.winUtils.addManuallyManagedState(element, mmStateValue);
+      } else {
+        this.winUtils.removeManuallyManagedState(element, mmStateValue);
       }
     }
-    */
+
+    fieldDetail.state = nextState;
   },
 
   /**
    * Return the profile that is converted from fieldDetails and only non-empty fields
    * are included.
    *
    * @returns {Object} The new profile that convert from details with trimmed result.
    */
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -22,16 +22,22 @@
         </div>
         <div class="profile-comment-col profile-item-col">
           <span anonid="profile-comment" class="profile-comment"></span>
         </div>
       </div>
     </xbl:content>
 
     <implementation implements="nsIDOMXULSelectControlItemElement">
+      <!-- For form autofill, we want to unify the selection no matter by
+      keyboard navigation or mouseover in order not to confuse user which
+      profile preview is being shown. This field is set to true to indicate
+      that selectedIndex of popup should be changed while mouseover item -->
+      <field name="selectedByMouseOver">true</field>
+
       <constructor>
         <![CDATA[
           this._itemBox = document.getAnonymousElementByAttribute(
             this, "anonid", "profile-item-box"
           );
           this._label = document.getAnonymousElementByAttribute(
             this, "anonid", "profile-label"
           );
--- a/browser/extensions/formautofill/skin/shared/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/shared/autocomplete-item.css
@@ -30,16 +30,17 @@ xul|richlistitem[originaltype="autofill-
   border-bottom: 1px solid rgba(38,38,38,.15);
   padding: var(--item-padding-vertical) 0;
   padding-inline-start: var(--item-padding-horizontal);
   padding-inline-end: var(--item-padding-horizontal);
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
   align-items: center;
+  background-color: #FFFFFF;
   color: -moz-FieldText
 }
 
 .profile-item-box:last-child {
   border-bottom: 0;
 }
 
 .profile-item-box > .profile-item-col {
--- a/browser/extensions/formautofill/test/mochitest/formautofill_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -12,17 +12,20 @@ function setInput(selector, value) {
   input.focus();
 
   // "identifyAutofillFields" is invoked asynchronously in "focusin" event. We
   // should make sure fields are ready for popup before doing tests.
   //
   // TODO: "setTimeout" is used here temporarily because there's no event to
   //       notify us of the state of "identifyAutofillFields" for now. We should
   //       figure out a better way after the heuristics land.
-  return new Promise(resolve => setTimeout(resolve));
+  SimpleTest.requestFlakyTimeout("Guarantee asynchronous identifyAutofillFields is invoked");
+  return new Promise(resolve => setTimeout(() => {
+    resolve(input);
+  }, 500));
 }
 
 function checkMenuEntries(expectedValues) {
   let actualValues = getMenuEntries();
 
   is(actualValues.length, expectedValues.length, " Checking length of expected menu");
   for (let i = 0; i < expectedValues.length; i++) {
     is(actualValues[i], expectedValues[i], " Checking menu entry #" + i);
--- a/browser/extensions/formautofill/test/mochitest/mochitest.ini
+++ b/browser/extensions/formautofill/test/mochitest/mochitest.ini
@@ -2,8 +2,9 @@
 support-files =
   ../../../../../toolkit/components/satchel/test/satchel_common.js
   ../../../../../toolkit/components/satchel/test/parent_utils.js
   formautofill_common.js
   formautofill_parent_utils.js
 
 [test_autofocus_form.html]
 [test_basic_autocomplete_form.html]
+[test_formautofill_preview_highlight.html]
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/mochitest/test_formautofill_preview_highlight.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test form autofill - preview and highlight</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="formautofill_common.js"></script>
+  <script type="text/javascript" src="satchel_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Form autofill test: preview and highlight
+
+<script>
+/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */
+/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
+/* import-globals-from formautofill_common.js */
+
+"use strict";
+
+let expectingPopup = null;
+let defaultTextColor;
+const MOCK_STORAGE = [{
+  organization: "Sesame Street",
+  "street-address": "123 Sesame Street.",
+  tel: "1-345-345-3456",
+}, {
+  organization: "Mozilla",
+  "street-address": "331 E. Evelyn Avenue",
+}, {
+  organization: "Tel org",
+  tel: "2-222-333-444",
+}];
+
+function expectPopup() {
+  info("expecting a popup");
+  return new Promise(resolve => {
+    expectingPopup = resolve;
+  });
+}
+
+function popupShownListener() {
+  info("popup shown for test ");
+  if (expectingPopup) {
+    expectingPopup();
+    expectingPopup = null;
+  }
+}
+
+// We could not get ManuallyManagedState of element now, so directly check if
+// filter and text color style are applied.
+function checkFieldPreview(elem, expectedText) {
+  const computedStyle = window.getComputedStyle(elem);
+  const isStyleApplied = computedStyle.getPropertyValue("filter") !== "none" &&
+                         computedStyle.getPropertyValue("color") !== defaultTextColor;
+
+  is(SpecialPowers.wrap(elem).previewValue, expectedText, `Checking #${elem.id} previewValue`);
+  is(isStyleApplied, !!expectedText, `Checking #${elem.id} preview style`);
+}
+
+function checkFilledFieldHighlight(elem, expectedValue) {
+  const computedStyle = window.getComputedStyle(elem);
+  const isStyleApplied = computedStyle.getPropertyValue("filter") !== "none" &&
+                         computedStyle.getPropertyValue("color") === defaultTextColor;
+
+  is(SpecialPowers.wrap(elem).previewValue, "", `Checking #${elem.id} filled previewValue`);
+  is(expectedValue, isStyleApplied, `Checking #${elem.id} filled style`);
+}
+
+function checkFormPreviewFields(previewingAddress) {
+  const inputs = document.querySelectorAll("input");
+
+  for (const input of inputs) {
+    const previewValue = previewingAddress && previewingAddress[input.id] || "";
+
+    checkFieldPreview(input, previewValue);
+  }
+}
+
+function checkFormFilledFields(address) {
+  const inputs = document.querySelectorAll("input");
+
+  for (const input of inputs) {
+    const isFilledByAutofill = !!address[input.id];
+
+    checkFilledFieldHighlight(input, isFilledByAutofill);
+  }
+}
+
+function confirmAllFieldsFilled(address) {
+  const pendingPromises = [];
+
+  for (const prop in address) {
+    const element = document.getElementById(prop);
+
+    pendingPromises.push(new Promise(resolve => {
+      element.addEventListener("change", resolve, {once: true});
+    }));
+  }
+
+  return Promise.all(pendingPromises);
+}
+
+add_task(async function setup_storage() {
+  defaultTextColor = window.getComputedStyle(document.querySelector("input")).getPropertyValue("color");
+
+  await addAddress(MOCK_STORAGE[0]);
+  await addAddress(MOCK_STORAGE[1]);
+  await addAddress(MOCK_STORAGE[2]);
+});
+
+add_task(async function check_preview() {
+  const focusedInput = await setInput("#organization", "");
+
+  doKey("down");
+  await expectPopup();
+  checkFormPreviewFields();
+
+  for (let i = 0; i < MOCK_STORAGE.length; i++) {
+    doKey("down");
+    await notifySelectedIndex(i);
+    checkFormPreviewFields(MOCK_STORAGE[i]);
+  }
+
+  doKey("down");
+  await notifySelectedIndex(-1);
+  checkFormPreviewFields();
+
+  focusedInput.blur();
+});
+
+add_task(async function check_filled_highlight() {
+  const focusedInput = await setInput("#organization", "");
+
+  doKey("down");
+  await expectPopup();
+
+  doKey("down");
+  await notifySelectedIndex(0);
+  const waitForFilled = confirmAllFieldsFilled(MOCK_STORAGE[0]);
+
+  // filled 1st address
+  doKey("return");
+  // blur to fire off change event from focusedInput
+  focusedInput.blur();
+  await waitForFilled;
+  checkFormFilledFields(MOCK_STORAGE[0]);
+});
+
+registerPopupShownListener(popupShownListener);
+
+</script>
+
+<p id="display"></p>
+
+<div id="content">
+
+  <form id="form1">
+    <p>This is a basic form.</p>
+    <p><label>organization: <input id="organization" autocomplete="organization"></label></p>
+    <p><label>streetAddress: <input id="street-address" autocomplete="street-address"></label></p>
+    <p><label>tel: <input id="tel" autocomplete="tel"></label></p>
+    <p><label>country: <input id="country" autocomplete="country"></label></p>
+  </form>
+
+</div>
+
+<pre id="test"></pre>
+</body>
+</html>
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -8,16 +8,17 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/FormLikeFactory.jsm");
 Cu.import("resource://testing-common/MockDocument.jsm");
 Cu.import("resource://testing-common/TestUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
                                   "resource://gre/modules/DownloadPaths.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 
@@ -111,17 +112,16 @@ async function initProfileStorage(fileNa
     do_check_true(profileStorage.addresses.add(record));
     await onChanged;
   }
   await profileStorage._saveImmediately();
   return profileStorage;
 }
 
 function runHeuristicsTest(patterns, fixturePathPrefix) {
-  Cu.import("resource://gre/modules/FormLikeFactory.jsm");
   Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
   Cu.import("resource://formautofill/FormAutofillUtils.jsm");
 
   patterns.forEach(testPattern => {
     add_task(function* () {
       do_print("Starting test fixture: " + testPattern.fixturePath);
       let file = do_get_file(fixturePathPrefix + testPattern.fixturePath);
       let doc = MockDocument.createTestDocumentFromFile("http://localhost:8080/test/", file);
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -255,17 +255,18 @@ function do_test(testcases, testFn) {
     (function() {
       let testcase = tc;
       add_task(async function() {
         do_print("Starting testcase: " + testcase.description);
 
         let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                   testcase.document);
         let form = doc.querySelector("form");
-        let handler = new FormAutofillHandler(form);
+        let formLike = FormLikeFactory.createFromForm(form);
+        let handler = new FormAutofillHandler(formLike);
         let promises = [];
 
         handler.fieldDetails = testcase.fieldDetails;
         handler.fieldDetails.forEach((field, index) => {
           let element = doc.querySelectorAll("input, select")[index];
           field.elementWeakRef = Cu.getWeakReference(element);
           if (!testcase.profileData[field.fieldName]) {
             // Avoid waiting for `change` event of a input with a blank value to
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -86,27 +86,28 @@ for (let tc of TESTCASES) {
   (function() {
     let testcase = tc;
     add_task(function* () {
       do_print("Starting testcase: " + testcase.description);
 
       let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                 testcase.document);
       let form = doc.querySelector("form");
+      let formLike = FormLikeFactory.createFromForm(form);
 
       testcase.fieldDetails.forEach((detail, index) => {
         let elementRef;
         if (testcase.ids && testcase.ids[index]) {
           elementRef = doc.getElementById(testcase.ids[index]);
         } else {
           elementRef = doc.querySelector("*[autocomplete*='" + detail.fieldName + "']");
         }
         detail.elementWeakRef = Cu.getWeakReference(elementRef);
       });
-      let handler = new FormAutofillHandler(form);
+      let handler = new FormAutofillHandler(formLike);
 
       handler.collectFormFields();
 
       handler.fieldDetails.forEach((detail, index) => {
         Assert.equal(detail.section, testcase.fieldDetails[index].section);
         Assert.equal(detail.addressType, testcase.fieldDetails[index].addressType);
         Assert.equal(detail.contactType, testcase.fieldDetails[index].contactType);
         Assert.equal(detail.fieldName, testcase.fieldDetails[index].fieldName);
--- a/db/sqlite3/src/sqlite3.c
+++ b/db/sqlite3/src/sqlite3.c
@@ -1,11 +1,11 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.19.2.  By combining all the individual C code files into this
+** version 3.19.3.  By combining all the individual C code files into this
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
 ** of 5% or more are commonly seen when SQLite is compiled as a single
 ** translation unit.
 **
 ** This file is all you need to compile SQLite.  To use SQLite in other
 ** programs, you need this file and the "sqlite3.h" header file that defines
@@ -393,19 +393,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and a SHA1
 ** or SHA3-256 hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.19.2"
-#define SQLITE_VERSION_NUMBER 3019002
-#define SQLITE_SOURCE_ID      "2017-05-25 16:50:27 edb4e819b0c058c7d74d27ebd14cc5ceb2bad6a6144a486a970182b7afe3f8b9"
+#define SQLITE_VERSION        "3.19.3"
+#define SQLITE_VERSION_NUMBER 3019003
+#define SQLITE_SOURCE_ID      "2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
@@ -67203,22 +67203,28 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
     if( rc ){
       goto end_insert;
     }
     oldCell = findCell(pPage, idx);
     if( !pPage->leaf ){
       memcpy(newCell, oldCell, 4);
     }
     rc = clearCell(pPage, oldCell, &info);
-    if( info.nSize==szNew && info.nLocal==info.nPayload ){
+    if( info.nSize==szNew && info.nLocal==info.nPayload 
+     && (!ISAUTOVACUUM || szNew<pPage->minLocal)
+    ){
       /* Overwrite the old cell with the new if they are the same size.
       ** We could also try to do this if the old cell is smaller, then add
       ** the leftover space to the free list.  But experiments show that
       ** doing that is no faster then skipping this optimization and just
-      ** calling dropCell() and insertCell(). */
+      ** calling dropCell() and insertCell(). 
+      **
+      ** This optimization cannot be used on an autovacuum database if the
+      ** new entry uses overflow pages, as the insertCell() call below is
+      ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry.  */
       assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
       if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
       memcpy(oldCell, newCell, szNew);
       return SQLITE_OK;
     }
     dropCell(pPage, idx, info.nSize, &rc);
     if( rc ) goto end_insert;
   }else if( loc<0 && pPage->nCell>0 ){
@@ -199051,17 +199057,17 @@ static void fts5Fts5Func(
 */
 static void fts5SourceIdFunc(
   sqlite3_context *pCtx,          /* Function call context */
   int nArg,                       /* Number of args */
   sqlite3_value **apUnused        /* Function arguments */
 ){
   assert( nArg==0 );
   UNUSED_PARAM2(nArg, apUnused);
-  sqlite3_result_text(pCtx, "fts5: 2017-05-25 16:50:27 edb4e819b0c058c7d74d27ebd14cc5ceb2bad6a6144a486a970182b7afe3f8b9", -1, SQLITE_TRANSIENT);
+  sqlite3_result_text(pCtx, "fts5: 2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b", -1, SQLITE_TRANSIENT);
 }
 
 static int fts5Init(sqlite3 *db){
   static const sqlite3_module fts5Mod = {
     /* iVersion      */ 2,
     /* xCreate       */ fts5CreateMethod,
     /* xConnect      */ fts5ConnectMethod,
     /* xBestIndex    */ fts5BestIndexMethod,
--- a/db/sqlite3/src/sqlite3.h
+++ b/db/sqlite3/src/sqlite3.h
@@ -116,19 +116,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and a SHA1
 ** or SHA3-256 hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.19.2"
-#define SQLITE_VERSION_NUMBER 3019002
-#define SQLITE_SOURCE_ID      "2017-05-25 16:50:27 edb4e819b0c058c7d74d27ebd14cc5ceb2bad6a6144a486a970182b7afe3f8b9"
+#define SQLITE_VERSION        "3.19.3"
+#define SQLITE_VERSION_NUMBER 3019003
+#define SQLITE_SOURCE_ID      "2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
--- a/devtools/client/debugger/test/mochitest/browser2.ini
+++ b/devtools/client/debugger/test/mochitest/browser2.ini
@@ -355,17 +355,19 @@ skip-if = e10s && debug
 [browser_dbg_variables-view-edit-cancel.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-click.js]
 skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
 [browser_dbg_variables-view-edit-getset-01.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-getset-02.js]
 skip-if = e10s && debug
-[browser_dbg_variables-view-edit-value.js]
+[browser_dbg_variables-view-edit-value-01.js]
+skip-if = e10s && debug
+[browser_dbg_variables-view-edit-value-02.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-watch.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-01.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-02.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-03.js]
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-08.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-08.js
@@ -11,17 +11,17 @@ const TAB_URL = EXAMPLE_URL + "doc_white
 
 var test = Task.async(function* () {
   let options = {
     source: TAB_URL,
     line: 1
   };
   var dbg = initDebugger(TAB_URL, options);
   const [tab,, panel] = yield dbg;
-  const debuggerLineNumber = 24;
+  const debuggerLineNumber = 26;
   const scopes = waitForCaretAndScopes(panel, debuggerLineNumber);
   callInTab(tab, "doPause");
   yield scopes;
 
   const variables = panel.panelWin.DebuggerView.Variables;
   ok(variables, "Should get the variables view.");
 
   const scope = [...variables][0];
@@ -35,17 +35,17 @@ var test = Task.async(function* () {
   }
   ok(obj, "Should have found the 'obj' variable");
 
   info("Expanding variable 'obj'");
   let expanded = once(variables, "fetched");
   obj.expand();
   yield expanded;
 
-  let values = ["", " ", "\r", "\n", "\t", "\f", "\uFEFF", "\xA0"];
+  let values = ["", " ", "\r", "\n", "\t", "\f", "\uFEFF", "\xA0", "\u2028", "\u2029"];
   let count = values.length;
 
   for (let [property, value] of obj) {
     let index = values.indexOf(property);
     if (index >= 0) {
       --count;
       is(value._nameString, property,
          "The _nameString is different than the property name");
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value-01.js
@@ -0,0 +1,91 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the editing variables or properties values works properly.
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
+
+var gTab, gPanel, gDebugger;
+var gVars;
+
+function test() {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
+    gTab = aTab;
+    gPanel = aPanel;
+    gDebugger = gPanel.panelWin;
+    gVars = gDebugger.DebuggerView.Variables;
+
+    waitForCaretAndScopes(gPanel, 24)
+      .then(() => initialChecks())
+      .then(() => testModification("a", "1"))
+      .then(() => testModification("{ a: 1 }", "Object"))
+      .then(() => testModification("[a]", "Array[1]"))
+      .then(() => testModification("b", "Object"))
+      .then(() => testModification("b.a", "1"))
+      .then(() => testModification("c.a", "1"))
+      .then(() => testModification("Infinity", "Infinity"))
+      .then(() => testModification("NaN", "NaN"))
+      .then(() => testModification("new Function", "anonymous()"))
+      .then(() => testModification("+0", "0"))
+      .then(() => testModification("-0", "-0"))
+      .then(() => testModification("Object.keys({})", "Array[0]"))
+      .then(() => testModification("document.title", '"Debugger test page"'))
+      .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
+      .then(null, aError => {
+        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+      });
+
+    generateMouseClickInTab(gTab, "content.document.querySelector('button')");
+  });
+}
+
+function initialChecks() {
+  let localScope = gVars.getScopeAtIndex(0);
+  let aVar = localScope.get("a");
+
+  is(aVar.target.querySelector(".name").getAttribute("value"), "a",
+    "Should have the right name for 'a'.");
+  is(aVar.target.querySelector(".value").getAttribute("value"), "1",
+    "Should have the right initial value for 'a'.");
+}
+
+function testModification(aNewValue, aNewResult) {
+  let localScope = gVars.getScopeAtIndex(0);
+  let aVar = localScope.get("a");
+
+  // Allow the target variable to get painted, so that clicking on
+  // its value would scroll the new textbox node into view.
+  executeSoon(() => {
+    let varValue = aVar.target.querySelector(".title > .value");
+    EventUtils.sendMouseEvent({ type: "mousedown" }, varValue, gDebugger);
+
+    let varInput = aVar.target.querySelector(".title > .element-value-input");
+    setText(varInput, aNewValue);
+    EventUtils.sendKey("RETURN", gDebugger);
+  });
+
+  return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
+    let localScope = gVars.getScopeAtIndex(0);
+    let aVar = localScope.get("a");
+
+    is(aVar.target.querySelector(".name").getAttribute("value"), "a",
+      "Should have the right name for 'a'.");
+    is(aVar.target.querySelector(".value").getAttribute("value"), aNewResult,
+      "Should have the right new value for 'a'.");
+  });
+}
+
+registerCleanupFunction(function () {
+  gTab = null;
+  gPanel = null;
+  gDebugger = null;
+  gVars = null;
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value-02.js
@@ -0,0 +1,76 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the editing variables or properties values works properly.
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_whitespace-property-names.html";
+
+var gDebugger, gVars;
+
+function test() {
+  let options = {
+    source: TAB_URL,
+    line: 1
+  };
+  initDebugger(TAB_URL, options).then(([tab,, panel]) => {
+    gDebugger = panel.panelWin;
+    gVars = gDebugger.DebuggerView.Variables;
+
+    let scopes = waitForCaretAndScopes(panel, 26);
+    callInTab(tab, "doPause");
+    scopes.then(() => {
+      let obj = getObjectScope();
+      ok(obj, "Should have found the 'obj' variable");
+      info("Expanding variable 'obj'");
+      let expanded = once(gVars, "fetched");
+      obj.expand();
+      return expanded;
+    }).then(() => initialCheck("\u2028", "\\u2028", "8"))
+      .then(() => initialCheck("\u2029", "\\u2029", "9"))
+      .then(() => testModification("\u2028", "\\u2028", "123", "123"))
+      .then(() => testModification("\u2029", "\\u2029", "456", "456"))
+      .then(() => resumeDebuggerThenCloseAndFinish(panel))
+      .then(null, aError => {
+        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+      });
+  });
+}
+
+function getObjectScope() {
+  return gVars.getScopeAtIndex(0).get("obj");
+}
+
+function initialCheck(aProp, aPropReadable, aValue) {
+  let aVar = getObjectScope().get(aProp);
+  is(aVar.target.querySelector(".value").getAttribute("value"), aValue,
+    "Should have the right initial value for '" + aPropReadable + "'.");
+}
+
+function testModification(aProp, aPropReadable, aNewValue, aNewResult) {
+  let aVar = getObjectScope().get(aProp);
+
+  // Allow the target variable to get painted, so that clicking on
+  // its value would scroll the new textbox node into view.
+  executeSoon(() => {
+    let varValue = aVar.target.querySelector(".title > .value");
+    EventUtils.sendMouseEvent({ type: "mousedown" }, varValue, gDebugger);
+
+    let varInput = aVar.target.querySelector(".title > .element-value-input");
+    setText(varInput, aNewValue);
+    EventUtils.sendKey("RETURN", gDebugger);
+  });
+
+  return once(gVars, "fetched").then(() => {
+    let aVar = getObjectScope().get(aProp);
+    is(aVar.target.querySelector(".value").getAttribute("value"), aNewResult,
+        "Should have the right new value for '" + aPropReadable + "'.");
+  });
+}
+
+registerCleanupFunction(function () {
+  gDebugger = gVars = null;
+});
deleted file mode 100644
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-edit-value.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Make sure that the editing variables or properties values works properly.
- */
-
-const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
-
-var gTab, gPanel, gDebugger;
-var gVars;
-
-function test() {
-  let options = {
-    source: TAB_URL,
-    line: 1
-  };
-  initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
-    gTab = aTab;
-    gPanel = aPanel;
-    gDebugger = gPanel.panelWin;
-    gVars = gDebugger.DebuggerView.Variables;
-
-    waitForCaretAndScopes(gPanel, 24)
-      .then(() => initialChecks())
-      .then(() => testModification("a", "1"))
-      .then(() => testModification("{ a: 1 }", "Object"))
-      .then(() => testModification("[a]", "Array[1]"))
-      .then(() => testModification("b", "Object"))
-      .then(() => testModification("b.a", "1"))
-      .then(() => testModification("c.a", "1"))
-      .then(() => testModification("Infinity", "Infinity"))
-      .then(() => testModification("NaN", "NaN"))
-      .then(() => testModification("new Function", "anonymous()"))
-      .then(() => testModification("+0", "0"))
-      .then(() => testModification("-0", "-0"))
-      .then(() => testModification("Object.keys({})", "Array[0]"))
-      .then(() => testModification("document.title", '"Debugger test page"'))
-      .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
-      .then(null, aError => {
-        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
-      });
-
-    generateMouseClickInTab(gTab, "content.document.querySelector('button')");
-  });
-}
-
-function initialChecks() {
-  let localScope = gVars.getScopeAtIndex(0);
-  let aVar = localScope.get("a");
-
-  is(aVar.target.querySelector(".name").getAttribute("value"), "a",
-    "Should have the right name for 'a'.");
-  is(aVar.target.querySelector(".value").getAttribute("value"), "1",
-    "Should have the right initial value for 'a'.");
-}
-
-function testModification(aNewValue, aNewResult) {
-  let localScope = gVars.getScopeAtIndex(0);
-  let aVar = localScope.get("a");
-
-  // Allow the target variable to get painted, so that clicking on
-  // its value would scroll the new textbox node into view.
-  executeSoon(() => {
-    let varValue = aVar.target.querySelector(".title > .value");
-    EventUtils.sendMouseEvent({ type: "mousedown" }, varValue, gDebugger);
-
-    let varInput = aVar.target.querySelector(".title > .element-value-input");
-    setText(varInput, aNewValue);
-    EventUtils.sendKey("RETURN", gDebugger);
-  });
-
-  return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
-    let localScope = gVars.getScopeAtIndex(0);
-    let aVar = localScope.get("a");
-
-    is(aVar.target.querySelector(".name").getAttribute("value"), "a",
-      "Should have the right name for 'a'.");
-    is(aVar.target.querySelector(".value").getAttribute("value"), aNewResult,
-      "Should have the right new value for 'a'.");
-  });
-}
-
-registerCleanupFunction(function () {
-  gTab = null;
-  gPanel = null;
-  gDebugger = null;
-  gVars = null;
-});
--- a/devtools/client/debugger/test/mochitest/doc_whitespace-property-names.html
+++ b/devtools/client/debugger/test/mochitest/doc_whitespace-property-names.html
@@ -14,16 +14,18 @@
       var obj = {
         "": 0,
         " ": 1,
         "\r": 2,
         "\n": 3,
         "\t": 4,
         "\f": 5,
         "\uFEFF": 6,
-        "\xA0": 7
+        "\xA0": 7,
+        "\u2028": 8,
+        "\u2029": 9,
       };
       debugger;
     };
     </script>
   </body>
 
 </html>
--- a/devtools/client/inspector/grids/components/GridOutline.js
+++ b/devtools/client/inspector/grids/components/GridOutline.js
@@ -124,44 +124,50 @@ module.exports = createClass({
       return VIEWPORT_MAX_HEIGHT;
     } else if (height <= VIEWPORT_MIN_HEIGHT) {
       return VIEWPORT_MIN_HEIGHT;
     }
 
     return height;
   },
 
-  highlightCell(e) {
+  onHighlightCell({ target, type }) {
     // Debounce the highlighting of cells.
     // This way we don't end up sending many requests to the server for highlighting when
     // cells get hovered in a rapid succession We only send a request if the user settles
     // on a cell for some time.
     if (this.highlightTimeout) {
       clearTimeout(this.highlightTimeout);
     }
 
     this.highlightTimeout = setTimeout(() => {
-      this.doHighlightCell(e);
+      this.doHighlightCell(target, type === "mouseleave");
       this.highlightTimeout = null;
     }, GRID_HIGHLIGHTING_DEBOUNCE);
   },
 
-  doHighlightCell({ target }) {
+  doHighlightCell(target, hide) {
     const {
       grids,
       onShowGridAreaHighlight,
       onShowGridCellHighlight,
     } = this.props;
     const name = target.dataset.gridAreaName;
     const id = target.dataset.gridId;
     const fragmentIndex = target.dataset.gridFragmentIndex;
     const color = target.closest(".grid-cell-group").dataset.gridLineColor;
     const rowNumber = target.dataset.gridRow;
     const columnNumber = target.dataset.gridColumn;
 
+    if (hide) {
+      onShowGridAreaHighlight(grids[id].nodeFront, null, color);
+      onShowGridCellHighlight(grids[id].nodeFront, color);
+      return;
+    }
+
     if (name) {
       onShowGridAreaHighlight(grids[id].nodeFront, name, color);
     }
 
     if (fragmentIndex && rowNumber && columnNumber) {
       onShowGridCellHighlight(grids[id].nodeFront, color, fragmentIndex,
         rowNumber, columnNumber);
     }
@@ -275,18 +281,18 @@ module.exports = createClass({
         "data-grid-id": id,
         "data-grid-row": rowNumber,
         "data-grid-column": columnNumber,
         x,
         y,
         width,
         height,
         fill: "none",
-        onMouseOver: this.onMouseOverCell,
-        onMouseOut: this.onMouseLeaveCell,
+        onMouseEnter: this.onHighlightCell,
+        onMouseLeave: this.onHighlightCell,
       }
     );
   },
 
   renderGridOutline(grid) {
     let { color } = grid;
 
     return dom.g(
@@ -307,34 +313,16 @@ module.exports = createClass({
         x: 1,
         y: 1,
         width: borderWidth,
         height: borderHeight
       }
     );
   },
 
-  onMouseLeaveCell({ target }) {
-    const {
-      grids,
-      onShowGridAreaHighlight,
-      onShowGridCellHighlight,
-    } = this.props;
-    const id = target.dataset.gridId;
-    const color = target.closest(".grid-cell-group").dataset.gridLineColor;
-
-    onShowGridAreaHighlight(grids[id].nodeFront, null, color);
-    onShowGridCellHighlight(grids[id].nodeFront, color);
-  },
-
-  onMouseOverCell(event) {
-    event.persist();
-    this.highlightCell(event);
-  },
-
   renderOutline() {
     const {
       height,
       selectedGrid,
       showOutline,
       width,
     } = this.state;
 
--- a/devtools/client/shared/widgets/VariablesView.jsm
+++ b/devtools/client/shared/widgets/VariablesView.jsm
@@ -3896,24 +3896,32 @@ VariablesView.getClass = function (aGrip
 var generateId = (function () {
   let count = 0;
   return function (aName = "") {
     return aName.toLowerCase().trim().replace(/\s+/g, "-") + (++count);
   };
 })();
 
 /**
- * Serialize a string to JSON. The result can be inserted in a string evaluated by `eval`.
+ * Quote and escape a string. The result will be another string containing an
+ * ECMAScript StringLiteral which will produce the original one when evaluated
+ * by `eval` or similar.
  *
  * @param string aString
- *       The string to be escaped. If undefined, the function returns the empty string.
+ *       An optional string to be escaped. If no string is passed, the function
+ *       returns an empty string.
  * @return string
  */
 function escapeString(aString) {
-  return JSON.stringify(aString) || "";
+  if (typeof aString !== "string") {
+    return "";
+  }
+  // U+2028 and U+2029 are allowed in JSON but not in ECMAScript string literals.
+  return JSON.stringify(aString).replace(/\u2028/g, '\\u2028')
+                                .replace(/\u2029/g, '\\u2029');
 }
 
 /**
  * Escape some HTML special characters. We do not need full HTML serialization
  * here, we just want to make strings safe to display in HTML attributes, for
  * the stringifiers.
  *
  * @param string aString
--- a/devtools/server/actors/frame.js
+++ b/devtools/server/actors/frame.js
@@ -44,39 +44,55 @@ let FrameActor = ActorClassWithSpec(fram
    * Finalization handler that is called when the actor is being evicted from
    * the pool.
    */
   destroy: function () {
     this.conn.removeActorPool(this._frameLifetimePool);
     this._frameLifetimePool = null;
   },
 
+  getEnvironment: function () {
+    if (!this.frame.environment) {
+      return {};
+    }
+
+    let envActor = this.threadActor.createEnvironmentActor(
+      this.frame.environment,
+      this.frameLifetimePool
+    );
+
+    return envActor.form();
+  },
+
   /**
    * Returns a frame form for use in a protocol message.
    */
   form: function () {
     let threadActor = this.threadActor;
     let form = { actor: this.actorID,
                  type: this.frame.type };
     if (this.frame.type === "call") {
       form.callee = createValueGrip(this.frame.callee, threadActor._pausePool,
         threadActor.objectGrip);
     }
 
-    if (this.frame.environment) {
-      let envActor = threadActor.createEnvironmentActor(
-        this.frame.environment,
-        this.frameLifetimePool
-      );
-      form.environment = envActor.form();
+    // NOTE: ignoreFrameEnvironment lets the client explicitly avoid
+    // populating form environments on pause.
+    if (
+      !this.threadActor._options.ignoreFrameEnvironment &&
+      this.frame.environment
+    ) {
+      form.environment = this.getEnvironment();
     }
+
     if (this.frame.type != "wasmcall") {
       form.this = createValueGrip(this.frame.this, threadActor._pausePool,
         threadActor.objectGrip);
     }
+
     form.arguments = this._args();
     if (this.frame.script) {
       let generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
       form.where = {
         source: generatedLocation.generatedSourceActor.form(),
         line: generatedLocation.generatedLine,
         column: generatedLocation.generatedColumn
       };
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -12,27 +12,26 @@ const {
   createNode,
   createSVGNode,
   moveInfobar,
 } = require("./utils/markup");
 const {
   getCurrentZoom,
   getDisplayPixelRatio,
   setIgnoreLayoutChanges,
-  getNodeBounds,
   getViewportDimensions,
 } = require("devtools/shared/layout/utils");
 const {
   identity,
   apply,
   translate,
   multiply,
   scale,
+  isIdentity,
   getNodeTransformationMatrix,
-  getNodeTransformOrigin
 } = require("devtools/shared/layout/dom-matrix-2d");
 const { stringifyGridFragments } = require("devtools/server/actors/utils/css-grid-utils");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
 const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
 
 const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
@@ -1042,51 +1041,41 @@ CssGridHighlighter.prototype = extend(Au
    *   5. Any CSS transformation applied directly to the element (only 2D
    *      transformation; the 3D transformation are flattened, see `dom-matrix-2d` module
    *      for further details.)
    *
    *  The transformations of the element's ancestors are not currently computed (see
    *  bug 1355675).
    */
   updateCurrentMatrix() {
-    let origin = getNodeTransformOrigin(this.currentNode);
-    let bounds = getNodeBounds(this.win, this.currentNode);
-    let nodeMatrix = getNodeTransformationMatrix(this.currentNode);
     let computedStyle = this.currentNode.ownerGlobal.getComputedStyle(this.currentNode);
 
     let paddingTop = parseFloat(computedStyle.paddingTop);
     let paddingLeft = parseFloat(computedStyle.paddingLeft);
     let borderTop = parseFloat(computedStyle.borderTopWidth);
     let borderLeft = parseFloat(computedStyle.borderLeftWidth);
 
-    // Subtract padding and border values to compensate for top/left being moved by
-    // padding and / or borders.
-    let ox = origin[0] - paddingLeft - borderLeft;
-    let oy = origin[1] - paddingTop - borderTop;
+    let nodeMatrix = getNodeTransformationMatrix(this.currentNode,
+      this.win.document.documentElement);
 
     let m = identity();
 
-    // First, we scale based on the display's current pixel ratio.
-    m = multiply(m, scale(getDisplayPixelRatio(this.win)));
-    // Then we translate the origin to the node's top left corner.
-    m = multiply(m, translate(bounds.p1.x, bounds.p1.y));
-    // And scale based on the current zoom factor.
-    m = multiply(m, scale(getCurrentZoom(this.win)));
-    // Then translate the origin based on the node's padding and border values.
+    // First, we scale based on the device pixel ratio.
+    m = multiply(m, scale(this.win.devicePixelRatio));
+    // Then, we apply the current node's transformation matrix, relative to the
+    // inspected window's root element, but only if it's not a identity matrix.
+    if (isIdentity(nodeMatrix)) {
+      this.hasNodeTransformations = false;
+    } else {
+      m = multiply(m, nodeMatrix);
+      this.hasNodeTransformations = true;
+    }
+
+    // Finally, we translate the origin based on the node's padding and border values.
     m = multiply(m, translate(paddingLeft + borderLeft, paddingTop + borderTop));
-    // Finally, we can apply the current node's transformation matrix, taking in account
-    // the `transform-origin` property and the node's top and left padding.
-    if (nodeMatrix) {
-      m = multiply(m, translate(ox, oy));
-      m = multiply(m, nodeMatrix);
-      m = multiply(m, translate(-ox, -oy));
-      this.hasNodeTransformations = true;
-    } else {
-      this.hasNodeTransformations = false;
-    }
 
     this.currentMatrix = m;
   },
 
   getFirstRowLinePos(fragment) {
     return fragment.rows.lines[0].start;
   },
 
--- a/devtools/shared/layout/dom-matrix-2d.js
+++ b/devtools/shared/layout/dom-matrix-2d.js
@@ -100,59 +100,44 @@ exports.multiply = multiply;
  */
 const apply = (M, P) => [
   M[0] * P[0] + M[1] * P[1] + M[2],
   M[3] * P[0] + M[4] * P[1] + M[5],
 ];
 exports.apply = apply;
 
 /**
- * Returns the transformation origin point for the given node.
+ * Returns `true` if the given matrix is a identity matrix.
  *
- * @param {DOMNode} node
- *        The node.
- * @return {Array}
- *        The transformation origin point.
+ * @param {Array} M
+ *        The matrix to check
+ * @return {Boolean}
+ *        `true` if the matrix passed is a identity matrix, `false` otherwise.
  */
-function getNodeTransformOrigin(node) {
-  let origin = node.ownerGlobal.getComputedStyle(node).transformOrigin;
-
-  return origin.split(/ /).map(parseFloat);
-}
-exports.getNodeTransformOrigin = getNodeTransformOrigin;
+const isIdentity = (M) =>
+  M[0] === 1 && M[1] === 0 && M[2] === 0 &&
+  M[3] === 0 && M[4] === 1 && M[5] === 0 &&
+  M[6] === 0 && M[7] === 0 && M[8] === 1;
+exports.isIdentity = isIdentity;
 
 /**
- * Returns the transformation matrix for the given node.
+ * Returns the transformation matrix for the given node, relative to the ancestor passed
+ * as second argument.
+ * If no ancestor is specified, it will returns the transformation matrix relative to the
+ * node's parent element.
  *
  * @param {DOMNode} node
  *        The node.
- * @return {Array}
+ * @param {DOMNode} ancestor
+ *        The ancestor of the node given.
+ ** @return {Array}
  *        The transformation matrix.
  */
-function getNodeTransformationMatrix(node) {
-  let t = node.ownerGlobal.getComputedStyle(node).transform;
-
-  if (t === "none") {
-    return null;
-  }
-
-  // We're assuming is a 2d matrix.
-  let m = t.substring(t.indexOf("(") + 1, t.length - 1).split(/,\s*/).map(Number);
-  let [a, b, c, d, e, f] = m;
-
-  // If the length is 16, it's a 3d matrix: in that case we'll extrapolate only the values
-  // we need for the 2D transformation; this cover the scenario where 3D CSS properties
-  // are used only for HW acceleration on 2D transformation.
-  if (m.length === 16) {
-    c = m[4];
-    d = m[5];
-    e = m[12];
-    f = m[13];
-  }
+function getNodeTransformationMatrix(node, ancestor = node.parentElement) {
+  let { a, b, c, d, e, f } = node.getTransformToAncestor(ancestor);
 
   return [
     a, c, e,
     b, d, f,
     0, 0, 1
   ];
 }
-
 exports.getNodeTransformationMatrix = getNodeTransformationMatrix;
--- a/devtools/shared/specs/frame.js
+++ b/devtools/shared/specs/frame.js
@@ -1,14 +1,18 @@
 /* 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 {generateActorSpec} = require("devtools/shared/protocol");
+const {generateActorSpec, RetVal} = require("devtools/shared/protocol");
 
 const frameSpec = generateActorSpec({
   typeName: "frame",
 
-  methods: {},
+  methods: {
+    getEnvironment: {
+      response: RetVal("json")
+    }
+  },
 });
 
 exports.frameSpec = frameSpec;
--- a/devtools/shared/tests/mochitest/chrome.ini
+++ b/devtools/shared/tests/mochitest/chrome.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 tags = devtools
 skip-if = os == 'android'
 
 [test_css-logic-getCssPath.html]
-[test_dom_matrix_2d.html]
 [test_eventemitter_basic.html]
 skip-if = os == 'linux' && debug # Bug 1205739
deleted file mode 100644
--- a/devtools/shared/tests/mochitest/test_dom_matrix_2d.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE html>
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-
-<html>
-  <!--
-  https://bugzilla.mozilla.org/show_bug.cgi?id=1297072
-  -->
-  <head>
-    <meta charset="utf8">
-    <title>Testing 2d matrix utility functions for DOM</title>
-
-    <script type="application/javascript"
-            src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-    <link rel="stylesheet" type="text/css"
-          href="chrome://mochikit/content/tests/SimpleTest/test.css">
-    <style>
-      #element {
-        position: absolute;
-        top: 20px;
-        left: 10px;
-        width: 320px;
-        height: 200px;
-        background: salmon;
-      }
-    </style>
-  </head>
-
-  <body>
-    <div id="element"></div>
-
-    <script type="application/javascript">
-      "use strict";
-
-      const { utils: Cu } = Components;
-      const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
-      const {
-        getNodeTransformationMatrix,
-        getNodeTransformOrigin
-      } = require("devtools/shared/layout/dom-matrix-2d");
-
-      let element = document.getElementById("element");
-
-      testNodeTransformOrigin(element);
-      testNodeTransformationMatrix(element);
-
-      function testNodeTransformOrigin(node) {
-        isDeeply(getNodeTransformOrigin(node), [160, 100],
-          "Default Transform Origin is correct.");
-
-        node.style.transformOrigin = "left 10%";
-        isDeeply(getNodeTransformOrigin(node), [0, 20],
-          "Transform Origin is properly computed.");
-
-        node.style.transformOrigin = "invalid";
-        isDeeply(getNodeTransformOrigin(node), [0, 20],
-          "Invalid values are ignored.");
-
-        node.style.transformOrigin = "left 5px -3px";
-        isDeeply(getNodeTransformOrigin(node), [0, 5, -3],
-          "3D coordinates and negative numbers are properly computed.");
-      }
-
-      function testNodeTransformationMatrix(node) {
-        is(getNodeTransformationMatrix(node), null,
-          "Default Transformation Matrix is `null`");
-
-        node.style.transform = "translate(10%, 20px)";
-        isDeeply(getNodeTransformationMatrix(node), [ 1, 0, 32, 0, 1, 20, 0, 0, 1 ],
-          "Transformation Matrix properly computed with translation.");
-
-        node.style.transform = "translate(10%, 20px) scale(2)";
-        isDeeply(getNodeTransformationMatrix(node), [ 2, 0, 32, 0, 2, 20, 0, 0, 1 ],
-          "Transformation Matrix properly translated and scaled.");
-
-        node.style.transform = "scale(2) translate(10%, 20px)";
-        isDeeply(getNodeTransformationMatrix(node), [ 2, 0, 64, 0, 2, 40, 0, 0, 1 ],
-          "Transformation Matrix properly scaled and translated.");
-
-        node.style.transform = "translate3d(12px, 50%, 3em)";
-        isDeeply(getNodeTransformationMatrix(node), [ 1, 0, 12, 0, 1, 100, 0, 0, 1 ],
-          "3D Transformation Matrix are handled for 2D values.");
-      }
-    </script>
-  </body>
-</html>
--- a/dom/animation/test/chrome/test_animation_observers_sync.html
+++ b/dom/animation/test/chrome/test_animation_observers_sync.html
@@ -72,17 +72,18 @@ function assert_equals_records(actual, e
     assert_record_list(actual[i].removedAnimations,
                        expected[i].removed, desc, i, "removedAnimations");
   }
 }
 
 // Create a pseudo element
 function createPseudo(test, element, type) {
   addStyle(test, { '@keyframes anim': '',
-                   ['.pseudo::' + type]: 'animation: anim 10s;' });
+                   ['.pseudo::' + type]: 'animation: anim 10s; ' +
+                                         'content: \'\';'  });
   element.classList.add('pseudo');
   var anims = document.getAnimations();
   assert_true(anims.length >= 1);
   var anim = anims[anims.length - 1];
   assert_equals(anim.effect.target.parentElement, element);
   assert_equals(anim.effect.target.type, '::' + type);
   anim.cancel();
   return anim.effect.target;
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -419,18 +419,16 @@ TimeoutManager::SetTimeout(nsITimeoutHan
 
   timeout->mWindow = &mWindow;
 
   TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
   timeout->SetWhenOrTimeRemaining(TimeStamp::Now(), delta);
 
   // If we're not suspended, then set the timer.
   if (!mWindow.IsSuspended()) {
-    MOZ_ASSERT(!timeout->When().IsNull());
-
     nsresult rv = mExecutor->MaybeSchedule(timeout->When());
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   if (!aIsInterval) {
     timeout->mNestingLevel = nestingLevel;
@@ -486,69 +484,77 @@ TimeoutManager::SetTimeout(nsITimeoutHan
 }
 
 void
 TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
 {
   uint32_t timerId = (uint32_t)aTimerId;
 
   bool firstTimeout = true;
+  bool deferredDeletion = false;
 
   ForEachUnorderedTimeoutAbortable([&](Timeout* aTimeout) {
     MOZ_LOG(gLog, LogLevel::Debug,
             ("Clear%s(TimeoutManager=%p, timeout=%p, aTimerId=%u, ID=%u, tracking=%d)\n", aTimeout->mIsInterval ? "Interval" : "Timeout",
              this, aTimeout, timerId, aTimeout->mTimeoutId,
              int(aTimeout->mIsTracking)));
 
     if (aTimeout->mTimeoutId == timerId && aTimeout->mReason == aReason) {
       if (aTimeout->mRunning) {
         /* We're running from inside the aTimeout. Mark this
            aTimeout for deferred deletion by the code in
            RunTimeout() */
         aTimeout->mIsInterval = false;
+        deferredDeletion = true;
       }
       else {
         /* Delete the aTimeout from the pending aTimeout list */
         aTimeout->remove();
       }
       return true; // abort!
     }
 
     firstTimeout = false;
 
     return false;
   });
 
-  if (!firstTimeout) {
+  // We don't need to reschedule the executor if any of the following are true:
+  //  * If the we weren't cancelling the first timeout, then the executor's
+  //    state doesn't need to change.  It will only reflect the next soonest
+  //    Timeout.
+  //  * If we did cancel the first Timeout, but its currently running, then
+  //    RunTimeout() will handle rescheduling the executor.
+  //  * If the window has become suspended then we should not start executing
+  //    Timeouts.
+  if (!firstTimeout || deferredDeletion || mWindow.IsSuspended()) {
     return;
   }
 
-  // If the first timeout was cancelled we need to stop the executor and
-  // restart at the next soonest deadline.
+  // Stop the executor and restart it at the next soonest deadline.
   mExecutor->Cancel();
 
   OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
   Timeout* nextTimeout = iter.Next();
   if (nextTimeout) {
     MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextTimeout->When()));
   }
 }
 
 void
 TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline)
 {
   MOZ_DIAGNOSTIC_ASSERT(!aNow.IsNull());
   MOZ_DIAGNOSTIC_ASSERT(!aTargetDeadline.IsNull());
 
+  MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended());
   if (mWindow.IsSuspended()) {
     return;
   }
 
-  NS_ASSERTION(!mWindow.IsFrozen(), "Timeout running on a window in the bfcache!");
-
   // Limit the overall time spent in RunTimeout() to reduce jank.
   uint32_t totalTimeLimitMS = std::max(1u, gMaxConsecutiveCallbacksMilliseconds);
   const TimeDuration totalTimeLimit = TimeDuration::FromMilliseconds(totalTimeLimitMS);
 
   // Allow up to 25% of our total time budget to be used figuring out which
   // timers need to run.  This is the initial loop in this method.
   const TimeDuration initalTimeLimit =
     TimeDuration::FromMilliseconds(totalTimeLimit.ToMilliseconds() / 4);
@@ -638,16 +644,20 @@ TimeoutManager::RunTimeout(const TimeSta
   now = TimeStamp::Now();
 
   // Wherever we stopped in the timer list, schedule the executor to
   // run for the next unexpired deadline.  Note, this *must* be done
   // before we start executing any content script handlers.  If one
   // of them spins the event loop the executor must already be scheduled
   // in order for timeouts to fire properly.
   if (!nextDeadline.IsNull()) {
+    // Note, we verified the window is not suspended at the top of
+    // method and the window should not have been suspended while
+    // executing the loop above since it doesn't call out to js.
+    MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended());
     MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextDeadline));
   }
 
   // Maybe the timeout that the event was fired for has been deleted
   // and there are no others timeouts with deadlines that make them
   // eligible for execution yet. Go away.
   if (!numTimersToRun) {
     return;
@@ -756,20 +766,24 @@ TimeoutManager::RunTimeout(const TimeSta
         }
       }
 
       // Check to see if we have run out of time to execute timeout handlers.
       // If we've exceeded our time budget then terminate the loop immediately.
       TimeDuration elapsed = now - start;
       if (elapsed >= totalTimeLimit) {
         // We ran out of time.  Make sure to schedule the executor to
-        // run immediately for the next timer, if it exists.
-        RefPtr<Timeout> timeout = runIter.Next();
-        if (timeout) {
-          MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When()));
+        // run immediately for the next timer, if it exists.  Its possible,
+        // however, that the last timeout handler suspended the window.  If
+        // that happened then we must skip this step.
+        if (!mWindow.IsSuspended()) {
+          RefPtr<Timeout> timeout = runIter.Next();
+          if (timeout) {
+            MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When()));
+          }
         }
         break;
       }
     }
   }
 }
 
 bool
@@ -816,30 +830,28 @@ TimeoutManager::ResetTimersForThrottleRe
   return ResetTimersForThrottleReduction(gMinBackgroundTimeoutValue);
 }
 
 nsresult
 TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS)
 {
   MOZ_ASSERT(aPreviousThrottleDelayMS > 0);
 
-  if (mWindow.IsFrozen() || mWindow.IsSuspended()) {
+  MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended());
+  if (mWindow.IsSuspended()) {
     return NS_OK;
   }
 
-  Timeouts::SortBy sortBy = mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
-                                               : Timeouts::SortBy::TimeWhen;
-
   nsresult rv = mNormalTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
                                                                 *this,
-                                                                sortBy);
+                                                                Timeouts::SortBy::TimeWhen);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mTrackingTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
                                                          *this,
-                                                         sortBy);
+                                                         Timeouts::SortBy::TimeWhen);
   NS_ENSURE_SUCCESS(rv, rv);
 
   OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
   Timeout* firstTimeout = iter.Next();
   if (firstTimeout) {
     rv = mExecutor->MaybeSchedule(firstTimeout->When());
     NS_ENSURE_SUCCESS(rv, rv);
   }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1154,16 +1154,21 @@ DOMInterfaces = {
     'headerFile': 'WebGLExtensions.h'
 },
 
 'WEBGL_compressed_texture_s3tc': {
     'nativeType': 'mozilla::WebGLExtensionCompressedTextureS3TC',
     'headerFile': 'WebGLExtensions.h'
 },
 
+'WEBGL_compressed_texture_s3tc_srgb': {
+    'nativeType': 'mozilla::WebGLExtensionCompressedTextureS3TC_SRGB',
+    'headerFile': 'WebGLExtensions.h'
+},
+
 'WEBGL_depth_texture': {
     'nativeType': 'mozilla::WebGLExtensionDepthTexture',
     'headerFile': 'WebGLExtensions.h'
 },
 
 'WEBGL_debug_renderer_info': {
     'nativeType': 'mozilla::WebGLExtensionDebugRendererInfo',
     'headerFile': 'WebGLExtensions.h'
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -305,16 +305,17 @@ class WebGLContext
     friend class WebGL2Context;
     friend class WebGLContextUserData;
     friend class WebGLExtensionCompressedTextureASTC;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTextureES3;
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionCompressedTextureS3TC;
+    friend class WebGLExtensionCompressedTextureS3TC_SRGB;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDisjointTimerQuery;
     friend class WebGLExtensionDrawBuffers;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionVertexArray;
     friend class WebGLMemoryTracker;
     friend struct webgl::UniformBlockInfo;
 
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -50,16 +50,17 @@ WebGLContext::GetExtensionString(WebGLEx
         WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_astc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_atc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
+        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc_srgb)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_draw_buffers)
         WEBGL_EXTENSION_IDENTIFIER(WEBGL_lose_context)
 
 #undef WEBGL_EXTENSION_IDENTIFIER
     }
@@ -134,23 +135,20 @@ WebGLContext::IsExtensionSupported(WebGL
         return gl->IsSupported(gl::GLFeature::ES3_compatibility) &&
                !gl->IsANGLE();
     case WebGLExtensionID::WEBGL_compressed_texture_etc1:
         return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture) &&
                !gl->IsANGLE();
     case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
         return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
     case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
-        if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
-            return true;
-
-        return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
-               gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
-               gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);
-
+        return WebGLExtensionCompressedTextureS3TC::IsSupported(this);
+    case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
+        return WebGLExtensionCompressedTextureS3TC::IsSupported(this) &&
+               gl->IsExtensionSupported(gl::GLContext::EXT_texture_sRGB);
     case WebGLExtensionID::WEBGL_debug_renderer_info:
         return Preferences::GetBool("webgl.enable-debug-renderer-info", false);
 
     case WebGLExtensionID::WEBGL_lose_context:
         // We always support this extension.
         return true;
 
     default:
@@ -425,16 +423,19 @@ WebGLContext::EnableExtension(WebGLExten
         obj = new WebGLExtensionCompressedTextureETC1(this);
         break;
     case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
         obj = new WebGLExtensionCompressedTexturePVRTC(this);
         break;
     case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
         obj = new WebGLExtensionCompressedTextureS3TC(this);
         break;
+    case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
+        obj = new WebGLExtensionCompressedTextureS3TC_SRGB(this);
+        break;
     case WebGLExtensionID::WEBGL_debug_renderer_info:
         obj = new WebGLExtensionDebugRendererInfo(this);
         break;
     case WebGLExtensionID::WEBGL_debug_shaders:
         obj = new WebGLExtensionDebugShaders(this);
         break;
     case WebGLExtensionID::WEBGL_depth_texture:
         obj = new WebGLExtensionDepthTexture(this);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -635,16 +635,20 @@ WebGLContext::ErrorInvalidEnumArg(const 
 bool
 IsCompressedTextureFormat(GLenum format)
 {
     switch (format) {
     case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case LOCAL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+    case LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
     case LOCAL_GL_ATC_RGB:
     case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
     case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
     case LOCAL_GL_ETC1_RGB8_OES:
--- a/dom/canvas/WebGLExtensionCompressedTextureS3TC.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTextureS3TC.cpp
@@ -37,11 +37,23 @@ WebGLExtensionCompressedTextureS3TC::Web
 
 #undef FOO
 }
 
 WebGLExtensionCompressedTextureS3TC::~WebGLExtensionCompressedTextureS3TC()
 {
 }
 
+bool
+WebGLExtensionCompressedTextureS3TC::IsSupported(const WebGLContext* webgl)
+{
+   gl::GLContext* gl = webgl->GL();
+   if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
+      return true;
+
+   return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
+          gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
+          gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);
+}
+
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureS3TC, WEBGL_compressed_texture_s3tc)
 
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLExtensionCompressedTextureS3TC_SRGB.cpp
@@ -0,0 +1,47 @@
+/* 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 "WebGLExtensions.h"
+
+#include "GLContext.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "WebGLContext.h"
+
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
+namespace mozilla {
+
+WebGLExtensionCompressedTextureS3TC_SRGB::WebGLExtensionCompressedTextureS3TC_SRGB(WebGLContext* webgl)
+    : WebGLExtensionBase(webgl)
+{
+    RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
+    const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+        auto& fua = webgl_->mFormatUsage;
+
+        auto usage = fua->EditUsage(effFormat);
+        usage->isFilterable = true;
+        fua->AllowSizedTexFormat(sizedFormat, usage);
+
+        webgl_->mCompressedTextureFormats.AppendElement(sizedFormat);
+    };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+    fnAdd(FOO(COMPRESSED_SRGB_S3TC_DXT1_EXT));
+    fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT));
+    fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT));
+    fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT));
+
+#undef FOO
+}
+
+WebGLExtensionCompressedTextureS3TC_SRGB::~WebGLExtensionCompressedTextureS3TC_SRGB()
+{
+}
+
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureS3TC_SRGB, WEBGL_compressed_texture_s3tc_srgb)
+
+} // namespace mozilla
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -121,16 +121,28 @@ public:
 
 class WebGLExtensionCompressedTextureS3TC
     : public WebGLExtensionBase
 {
 public:
     explicit WebGLExtensionCompressedTextureS3TC(WebGLContext*);
     virtual ~WebGLExtensionCompressedTextureS3TC();
 
+    static bool IsSupported(const WebGLContext*);
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
+class WebGLExtensionCompressedTextureS3TC_SRGB
+    : public WebGLExtensionBase
+{
+public:
+    explicit WebGLExtensionCompressedTextureS3TC_SRGB(WebGLContext*);
+    virtual ~WebGLExtensionCompressedTextureS3TC_SRGB();
+
     DECL_WEBGL_EXTENSION_GOOP
 };
 
 class WebGLExtensionDebugRendererInfo
     : public WebGLExtensionBase
 {
 public:
     explicit WebGLExtensionDebugRendererInfo(WebGLContext*);
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -108,16 +108,22 @@ InitCompressedFormatInfo()
     AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD, 128, 4, 4, CompressionFamily::ATC);
 
     // EXT_texture_compression_s3tc
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1_EXT ,  64, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1_EXT,  64, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);
 
+    // EXT_texture_compression_s3tc_srgb
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT ,       64, 4, 4, CompressionFamily::S3TC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,  64, 4, 4, CompressionFamily::S3TC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
+    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);
+
     // KHR_texture_compression_astc_ldr
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_4x4_KHR          , 128,  4,  4, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x4_KHR          , 128,  5,  4, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x5_KHR          , 128,  5,  5, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x5_KHR          , 128,  6,  5, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x6_KHR          , 128,  6,  6, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x5_KHR          , 128,  8,  5, CompressionFamily::ASTC);
     AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x6_KHR          , 128,  8,  6, CompressionFamily::ASTC);
@@ -318,16 +324,22 @@ InitFormatInfo()
     AddFormatInfo(FOO(ATC_RGBA_INTERPOLATED_ALPHA_AMD), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
 
     // EXT_texture_compression_s3tc
     AddFormatInfo(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
 
+    // EXT_texture_compression_s3tc_srgb
+    AddFormatInfo(FOO(COMPRESSED_SRGB_S3TC_DXT1_EXT ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , true, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);
+    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);
+
     // KHR_texture_compression_astc_ldr
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
     AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -114,16 +114,22 @@ enum class EffectiveFormat : EffectiveFo
     ATC_RGBA_INTERPOLATED_ALPHA_AMD,
 
     // EXT_texture_compression_s3tc
     COMPRESSED_RGB_S3TC_DXT1_EXT,
     COMPRESSED_RGBA_S3TC_DXT1_EXT,
     COMPRESSED_RGBA_S3TC_DXT3_EXT,
     COMPRESSED_RGBA_S3TC_DXT5_EXT,
 
+    // EXT_texture_sRGB
+    COMPRESSED_SRGB_S3TC_DXT1_EXT,
+    COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
+    COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
+    COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
+
     // KHR_texture_compression_astc_ldr
     COMPRESSED_RGBA_ASTC_4x4_KHR,
     COMPRESSED_RGBA_ASTC_5x4_KHR,
     COMPRESSED_RGBA_ASTC_5x5_KHR,
     COMPRESSED_RGBA_ASTC_6x5_KHR,
     COMPRESSED_RGBA_ASTC_6x6_KHR,
     COMPRESSED_RGBA_ASTC_8x5_KHR,
     COMPRESSED_RGBA_ASTC_8x6_KHR,
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -342,16 +342,20 @@ STRONG_GLENUM_BEGIN(TexInternalFormat)
     STRONG_GLENUM_VALUE(RG16I),
     STRONG_GLENUM_VALUE(RG16UI),
     STRONG_GLENUM_VALUE(RG32I),
     STRONG_GLENUM_VALUE(RG32UI),
     STRONG_GLENUM_VALUE(COMPRESSED_RGB_S3TC_DXT1_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT1_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT3_EXT),
     STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT5_EXT),
+    STRONG_GLENUM_VALUE(COMPRESSED_SRGB_S3TC_DXT1_EXT),
+    STRONG_GLENUM_VALUE(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT),
+    STRONG_GLENUM_VALUE(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT),
+    STRONG_GLENUM_VALUE(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT),
     STRONG_GLENUM_VALUE(DEPTH_STENCIL),
     STRONG_GLENUM_VALUE(ATC_RGBA_INTERPOLATED_ALPHA),
     STRONG_GLENUM_VALUE(RGBA32F),
     STRONG_GLENUM_VALUE(RGB32F),
     STRONG_GLENUM_VALUE(ALPHA32F_EXT),
     STRONG_GLENUM_VALUE(LUMINANCE32F_EXT),
     STRONG_GLENUM_VALUE(LUMINANCE_ALPHA32F_EXT),
     STRONG_GLENUM_VALUE(RGBA16F),
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -159,16 +159,17 @@ enum class WebGLExtensionID : uint8_t {
     OES_vertex_array_object,
     WEBGL_color_buffer_float,
     WEBGL_compressed_texture_astc,
     WEBGL_compressed_texture_atc,
     WEBGL_compressed_texture_etc,
     WEBGL_compressed_texture_etc1,
     WEBGL_compressed_texture_pvrtc,
     WEBGL_compressed_texture_s3tc,
+    WEBGL_compressed_texture_s3tc_srgb,
     WEBGL_debug_renderer_info,
     WEBGL_debug_shaders,
     WEBGL_depth_texture,
     WEBGL_draw_buffers,
     WEBGL_lose_context,
     Max,
     Unknown
 };
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -130,16 +130,17 @@ UNIFIED_SOURCES += [
     'WebGLExtensionColorBufferFloat.cpp',
     'WebGLExtensionColorBufferHalfFloat.cpp',
     'WebGLExtensionCompressedTextureASTC.cpp',
     'WebGLExtensionCompressedTextureATC.cpp',
     'WebGLExtensionCompressedTextureES3.cpp',
     'WebGLExtensionCompressedTextureETC1.cpp',
     'WebGLExtensionCompressedTexturePVRTC.cpp',
     'WebGLExtensionCompressedTextureS3TC.cpp',
+    'WebGLExtensionCompressedTextureS3TC_SRGB.cpp',
     'WebGLExtensionDebugRendererInfo.cpp',
     'WebGLExtensionDebugShaders.cpp',
     'WebGLExtensionDepthTexture.cpp',
     'WebGLExtensionDisjointTimerQuery.cpp',
     'WebGLExtensionDrawBuffers.cpp',
     'WebGLExtensionElementIndexUint.cpp',
     'WebGLExtensionEXTColorBufferFloat.cpp',
     'WebGLExtensionFragDepth.cpp',
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -2807,19 +2807,16 @@ nsTextEditorState::UpdatePlaceholderText
   nsContentUtils::RemoveNewlines(placeholderValue);
   NS_ASSERTION(mPlaceholderDiv->GetFirstChild(), "placeholder div has no child");
   mPlaceholderDiv->GetFirstChild()->SetText(placeholderValue, aNotify);
 }
 
 void
 nsTextEditorState::SetPreviewText(const nsAString& aValue, bool aNotify)
 {
-  MOZ_ASSERT(mPreviewDiv, "This function should not be called if "
-                            "mPreviewDiv isn't set");
-
   // If we don't have a preview div, there's nothing to do.
   if (!mPreviewDiv)
     return;
 
   nsAutoString previewValue(aValue);
 
   nsContentUtils::RemoveNewlines(previewValue);
   MOZ_ASSERT(mPreviewDiv->GetFirstChild(), "preview div has no child");
--- a/dom/tests/browser/browser_noopener.js
+++ b/dom/tests/browser/browser_noopener.js
@@ -56,24 +56,24 @@ async function doTests(private, containe
     if (test.newWindow || alwaysNewWindow) {
       let window = await waitFor;
       is(PrivateBrowsingUtils.isWindowPrivate(window), private, "Private status should match for " + testid);
       tab = window.gBrowser.selectedTab;
     } else {
       tab = await waitFor;
     }
 
-    if (container) {
-      is(tab.linkedBrowser.getAttribute("usercontextid"), 1, "Should have usercontextid set for " + testid);
-    } else {
-      ok(!tab.linkedBrowser.hasAttribute("usercontextid"), "Should have usercontextid set for " + testid);
-    }
+    // Check that the name matches.
+    await ContentTask.spawn(tab.linkedBrowser, [test, container, testid], async ([test, container, testid]) => {
+      if (container) {
+        is(content.document.nodePrincipal.originAttributes.userContextId, 1);
+      } else {
+        is(content.document.nodePrincipal.originAttributes.userContextId, 0);
+      }
 
-    // Check that the name matches.
-    await ContentTask.spawn(tab.linkedBrowser, [test, testid], async ([test, testid]) => {
       is(content.window.name, test.name, "Name should match for " + testid);
       if (test.opener) {
         ok(content.window.opener, "Opener should have been set for " + testid);
       } else {
         ok(!content.window.opener, "Opener should not have been set for " + testid);
       }
     });
 
@@ -117,12 +117,8 @@ add_task(async function newwindow_samepr
   await doAllTests();
 });
 
 add_task(async function newwindow_newproc() {
   await SpecialPowers.pushPrefEnv({set: [[OPEN_NEWWINDOW_PREF, OPEN_NEWWINDOW],
                                          [NOOPENER_NEWPROC_PREF, true]]});
   await doAllTests();
 });
-
-// add_task(async function() {
-//   await doTests(false, true);
-// })
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -815,16 +815,25 @@ interface WEBGL_compressed_texture_s3tc
 {
     const GLenum COMPRESSED_RGB_S3TC_DXT1_EXT  = 0x83F0;
     const GLenum COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
     const GLenum COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
     const GLenum COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
 };
 
 [NoInterfaceObject]
+interface WEBGL_compressed_texture_s3tc_srgb {
+    /* Compressed Texture Formats */
+    const GLenum COMPRESSED_SRGB_S3TC_DXT1_EXT        = 0x8C4C;
+    const GLenum COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT  = 0x8C4D;
+    const GLenum COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT  = 0x8C4E;
+    const GLenum COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT  = 0x8C4F;
+};
+
+[NoInterfaceObject]
 interface WEBGL_compressed_texture_astc {
     /* Compressed Texture Format */
     const GLenum COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
     const GLenum COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1;
     const GLenum COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2;
     const GLenum COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3;
     const GLenum COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4;
     const GLenum COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5;
--- a/editor/libeditor/SelectionState.h
+++ b/editor/libeditor/SelectionState.h
@@ -62,17 +62,17 @@ public:
 
   void SaveSelection(dom::Selection *aSel);
   nsresult RestoreSelection(dom::Selection* aSel);
   bool IsCollapsed();
   bool IsEqual(SelectionState *aSelState);
   void MakeEmpty();
   bool IsEmpty();
 private:
-  nsTArray<RefPtr<RangeItem>> mArray;
+  AutoTArray<RefPtr<RangeItem>, 1> mArray;
 
   friend class RangeUpdater;
   friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
                                           SelectionState&,
                                           const char*,
                                           uint32_t);
   friend void ImplCycleCollectionUnlink(SelectionState&);
 };
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -38,23 +38,23 @@ parent:
   async ReleaseCompositable(CompositableHandle compositable);
 
   // Creates a set of mappings between TextureReadLocks and an associated
   // ReadLockHandle that can be used in Update, and persist until the
   // next Update call.
   async InitReadLocks(ReadLockInit[] locks);
 
   sync Create(IntSize aSize);
-  sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
-                SurfaceFormat aFormat, ByteBuffer aBytes);
+  async AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
+                 SurfaceFormat aFormat, ByteBuffer aBytes);
   async AddBlobImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
                      SurfaceFormat aFormat, ByteBuffer aBytes);
-  sync UpdateImage(ImageKey aImageKey, IntSize aSize,
+  async UpdateImage(ImageKey aImageKey, IntSize aSize,
                    SurfaceFormat aFormat, ByteBuffer aBytes);
-  sync DeleteImage(ImageKey aImageKey);
+  async DeleteImage(ImageKey aImageKey);
   async DeleteCompositorAnimations(uint64_t[] aIds);
   async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
   async DeleteFont(FontKey aFontKey);
   async DPBegin(IntSize aSize);
   async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
               WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc,
               WebRenderScrollData aScrollData);
   sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -1029,22 +1029,16 @@ description = bug 1350634
 [PUiCompositorController::Pause]
 description =
 [PUiCompositorController::Resume]
 description =
 [PUiCompositorController::ResumeAndResize]
 description =
 [PWebRenderBridge::Create]
 description =
-[PWebRenderBridge::AddImage]
-description =
-[PWebRenderBridge::UpdateImage]
-description =
-[PWebRenderBridge::DeleteImage]
-description =
 [PWebRenderBridge::DPSyncEnd]
 description =
 [PWebRenderBridge::DPGetSnapshot]
 description =
 [PWebRenderBridge::SetAsyncScrollOffset]
 description = test only
 [PWebRenderBridge::SetAsyncZoom]
 description = test only
--- a/ipc/mscom/EnsureMTA.h
+++ b/ipc/mscom/EnsureMTA.h
@@ -11,78 +11,128 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Unused.h"
 #include "mozilla/mscom/COMApartmentRegion.h"
 #include "mozilla/mscom/Utils.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
+#include "nsWindowsHelpers.h"
 
 #include <windows.h>
 
 namespace mozilla {
 namespace mscom {
+namespace detail {
+
+// Forward declarations
+template <typename T>
+struct MTADelete;
+
+template <typename T>
+struct MTARelease;
+
+template <typename T>
+struct MTAReleaseInChildProcess;
+
+}
 
 // This class is OK to use as a temporary on the stack.
-class MOZ_STACK_CLASS EnsureMTA
+class MOZ_STACK_CLASS EnsureMTA final
 {
 public:
   /**
    * This constructor just ensures that the MTA thread is up and running.
    */
   EnsureMTA()
   {
     MOZ_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsIThread> thread = GetMTAThread();
     MOZ_ASSERT(thread);
     Unused << thread;
   }
 
   template <typename FuncT>
   explicit EnsureMTA(const FuncT& aClosure)
   {
-    MOZ_ASSERT(NS_IsMainThread());
     if (IsCurrentThreadMTA()) {
       // We're already on the MTA, we can run aClosure directly
       aClosure();
       return;
     }
 
+    MOZ_ASSERT(NS_IsMainThread());
+
     // In this case we need to run aClosure on a background thread in the MTA
     nsCOMPtr<nsIThread> thread = GetMTAThread();
     MOZ_ASSERT(thread);
+    if (!thread) {
+      return;
+    }
 
-    HANDLE event = ::CreateEventW(nullptr, FALSE, FALSE, nullptr);
+    static nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
     if (!event) {
       return;
     }
 
-    auto eventSetter = [&]() -> void {
+    HANDLE eventHandle = event.get();
+
+    auto eventSetter = [&aClosure, eventHandle]() -> void {
       aClosure();
-      ::SetEvent(event);
+      ::SetEvent(eventHandle);
     };
 
     nsresult rv =
       thread->Dispatch(NS_NewRunnableFunction(eventSetter), NS_DISPATCH_NORMAL);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ::CloseHandle(event);
+    if (NS_FAILED(rv)) {
       return;
     }
 
     DWORD waitResult;
     while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, TRUE)) ==
            WAIT_IO_COMPLETION) {
     }
     MOZ_ASSERT(waitResult == WAIT_OBJECT_0);
-    ::CloseHandle(event);
   }
 
 private:
   static nsCOMPtr<nsIThread> GetMTAThread();
+
+  // The following function is private in order to force any consumers to be
+  // declared as friends of EnsureMTA. The intention is to prevent
+  // AsyncOperation from becoming some kind of free-for-all mechanism for
+  // asynchronously executing work on a background thread.
+  template <typename FuncT>
+  static void AsyncOperation(const FuncT& aClosure)
+  {
+    if (IsCurrentThreadMTA()) {
+      aClosure();
+      return;
+    }
+
+    nsCOMPtr<nsIThread> thread(GetMTAThread());
+    MOZ_ASSERT(thread);
+    if (!thread) {
+      return;
+    }
+
+    DebugOnly<nsresult> rv = thread->Dispatch(
+        NS_NewRunnableFunction(aClosure), NS_DISPATCH_NORMAL);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+  }
+
+  template <typename T>
+  friend struct mozilla::mscom::detail::MTADelete;
+
+  template <typename T>
+  friend struct mozilla::mscom::detail::MTARelease;
+
+  template <typename T>
+  friend struct mozilla::mscom::detail::MTAReleaseInChildProcess;
 };
 
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_EnsureMTA_h
 
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -21,16 +21,17 @@
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsRefPtrHashtable.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 namespace mozilla {
 namespace mscom {
+namespace detail {
 
 class LiveSet final
 {
 public:
   LiveSet()
     : mMutex("mozilla::mscom::LiveSet::mMutex")
   {
   }
@@ -60,55 +61,96 @@ public:
   }
 
   void Remove(IUnknown* aKey)
   {
     mMutex.AssertCurrentThreadOwns();
     mLiveSet.Remove(aKey);
   }
 
-  typedef BaseAutoLock<LiveSet> AutoLock;
-
 private:
   Mutex mMutex;
   nsRefPtrHashtable<nsPtrHashKey<IUnknown>, IWeakReference> mLiveSet;
 };
 
-static LiveSet&
+/**
+ * We don't use the normal XPCOM BaseAutoLock because we need the ability
+ * to explicitly Unlock.
+ */
+class MOZ_RAII LiveSetAutoLock final
+{
+public:
+  explicit LiveSetAutoLock(LiveSet& aLiveSet)
+    : mLiveSet(&aLiveSet)
+  {
+    aLiveSet.Lock();
+  }
+
+  ~LiveSetAutoLock()
+  {
+    if (mLiveSet) {
+      mLiveSet->Unlock();
+    }
+  }
+
+  void Unlock()
+  {
+    MOZ_ASSERT(mLiveSet);
+    mLiveSet->Unlock();
+    mLiveSet = nullptr;
+  }
+
+  LiveSetAutoLock(const LiveSetAutoLock& aOther) = delete;
+  LiveSetAutoLock(LiveSetAutoLock&& aOther) = delete;
+  LiveSetAutoLock& operator=(const LiveSetAutoLock& aOther) = delete;
+  LiveSetAutoLock& operator=(LiveSetAutoLock&& aOther) = delete;
+
+private:
+  LiveSet*  mLiveSet;
+};
+
+} // namespace detail
+
+static detail::LiveSet&
 GetLiveSet()
 {
-  static LiveSet sLiveSet;
+  static detail::LiveSet sLiveSet;
   return sLiveSet;
 }
 
 /* static */ HRESULT
 Interceptor::Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
                     REFIID aInitialIid, void** aOutInterface)
 {
   MOZ_ASSERT(aOutInterface && aTarget && aSink);
   if (!aOutInterface) {
     return E_INVALIDARG;
   }
 
-  LiveSet::AutoLock lock(GetLiveSet());
+  detail::LiveSetAutoLock lock(GetLiveSet());
 
-  RefPtr<IWeakReference> existingInterceptor(Move(GetLiveSet().Get(aTarget.get())));
-  if (existingInterceptor &&
-      SUCCEEDED(existingInterceptor->Resolve(aInitialIid, aOutInterface))) {
-    return S_OK;
+  RefPtr<IWeakReference> existingWeak(Move(GetLiveSet().Get(aTarget.get())));
+  if (existingWeak) {
+    RefPtr<IWeakReferenceSource> existingStrong;
+    if (SUCCEEDED(existingWeak->ToStrongRef(getter_AddRefs(existingStrong)))) {
+      // QI on existingStrong may touch other threads. Since we now hold a
+      // strong ref on the interceptor, we may now release the lock.
+      lock.Unlock();
+      return existingStrong->QueryInterface(aInitialIid, aOutInterface);
+    }
   }
 
   *aOutInterface = nullptr;
 
   if (!aTarget || !aSink) {
     return E_INVALIDARG;
   }
 
   RefPtr<Interceptor> intcpt(new Interceptor(aSink));
-  return intcpt->GetInitialInterceptorForIID(aInitialIid, Move(aTarget),
+  return intcpt->GetInitialInterceptorForIID(lock, aInitialIid, Move(aTarget),
                                              aOutInterface);
 }
 
 Interceptor::Interceptor(IInterceptorSink* aSink)
   : WeakReferenceSupport(WeakReferenceSupport::Flags::eDestroyOnMainThread)
   , mEventSink(aSink)
   , mMutex("mozilla::mscom::Interceptor::mMutex")
   , mStdMarshal(nullptr)
@@ -118,17 +160,17 @@ Interceptor::Interceptor(IInterceptorSin
   if (SUCCEEDED(GetWeakReference(getter_AddRefs(weakRef)))) {
     aSink->SetInterceptor(weakRef);
   }
 }
 
 Interceptor::~Interceptor()
 {
   { // Scope for lock
-    LiveSet::AutoLock lock(GetLiveSet());
+    detail::LiveSetAutoLock lock(GetLiveSet());
     GetLiveSet().Remove(mTarget.get());
   }
 
   // This needs to run on the main thread because it releases target interface
   // reference counts which may not be thread-safe.
   MOZ_ASSERT(NS_IsMainThread());
   for (uint32_t index = 0, len = mInterceptorMap.Length(); index < len; ++index) {
     MapEntry& entry = mInterceptorMap[index];
@@ -318,17 +360,18 @@ Interceptor::CreateInterceptor(REFIID aI
   // If this assert fires then the interceptor doesn't like something about
   // the format of the typelib. One thing in particular that it doesn't like
   // is complex types that contain unions.
   MOZ_ASSERT(SUCCEEDED(hr));
   return hr;
 }
 
 HRESULT
-Interceptor::GetInitialInterceptorForIID(REFIID aTargetIid,
+Interceptor::GetInitialInterceptorForIID(detail::LiveSetAutoLock& aLock,
+                                         REFIID aTargetIid,
                                          STAUniquePtr<IUnknown> aTarget,
                                          void** aOutInterceptor)
 {
   MOZ_ASSERT(aOutInterceptor);
   MOZ_ASSERT(aTargetIid != IID_IUnknown && aTargetIid != IID_IMarshal);
   MOZ_ASSERT(!IsProxy(aTarget.get()));
 
   // Raise the refcount for stabilization purposes during aggregation
@@ -361,16 +404,20 @@ Interceptor::GetInitialInterceptorForIID
   }
 
   // mTarget is a weak reference to aTarget. This is safe because we transfer
   // ownership of aTarget into mInterceptorMap which remains live for the
   // lifetime of this Interceptor.
   mTarget = ToInterceptorTargetPtr(aTarget);
   GetLiveSet().Put(mTarget.get(), weakRef.forget());
 
+  // Release the live set lock because GetInterceptorForIID will post work to
+  // the main thread, creating potential for deadlocks.
+  aLock.Unlock();
+
   // Now we transfer aTarget's ownership into mInterceptorMap.
   mInterceptorMap.AppendElement(MapEntry(aTargetIid,
                                          unkInterceptor,
                                          aTarget.release()));
 
   if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
     return unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
   }
--- a/ipc/mscom/Interceptor.h
+++ b/ipc/mscom/Interceptor.h
@@ -15,16 +15,21 @@
 #include "mozilla/mscom/WeakRef.h"
 #include "mozilla/RefPtr.h"
 
 #include <objidl.h>
 #include <callobj.h>
 
 namespace mozilla {
 namespace mscom {
+namespace detail {
+
+class LiveSetAutoLock;
+
+} // namespace detail
 
 // {8831EB53-A937-42BC-9921-B3E1121FDF86}
 DEFINE_GUID(IID_IInterceptorSink,
 0x8831eb53, 0xa937, 0x42bc, 0x99, 0x21, 0xb3, 0xe1, 0x12, 0x1f, 0xdf, 0x86);
 
 struct IInterceptorSink : public ICallFrameEvents
                         , public HandlerProvider
 {
@@ -110,17 +115,18 @@ private:
     IID               mIID;
     RefPtr<IUnknown>  mInterceptor;
     IUnknown*         mTargetInterface;
   };
 
 private:
   explicit Interceptor(IInterceptorSink* aSink);
   ~Interceptor();
-  HRESULT GetInitialInterceptorForIID(REFIID aTargetIid,
+  HRESULT GetInitialInterceptorForIID(detail::LiveSetAutoLock& aLock,
+                                      REFIID aTargetIid,
                                       STAUniquePtr<IUnknown> aTarget,
                                       void** aOutInterface);
   MapEntry* Lookup(REFIID aIid);
   HRESULT QueryInterfaceTarget(REFIID aIid, void** aOutput);
   HRESULT ThreadSafeQueryInterface(REFIID aIid,
                                    IUnknown** aOutInterface) override;
   HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
 
--- a/ipc/mscom/Ptr.h
+++ b/ipc/mscom/Ptr.h
@@ -43,46 +43,68 @@ struct MainThreadRelease
     DebugOnly<nsresult> rv =
       NS_DispatchToMainThread(NewNonOwningRunnableMethod(aPtr,
                                                          &T::Release));
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 };
 
 template <typename T>
+struct MTADelete
+{
+  void operator()(T* aPtr)
+  {
+    if (!aPtr) {
+      return;
+    }
+
+    EnsureMTA::AsyncOperation([aPtr]() -> void {
+      delete aPtr;
+    });
+  }
+};
+
+template <typename T>
 struct MTARelease
 {
   void operator()(T* aPtr)
   {
     if (!aPtr) {
       return;
     }
-    EnsureMTA([&]() -> void
-    {
-      aPtr->Release();
+
+    // Static analysis doesn't recognize that, even though aPtr escapes the
+    // current scope, we are in effect moving our strong ref into the lambda.
+    void* ptr = aPtr;
+    EnsureMTA::AsyncOperation([ptr]() -> void {
+      reinterpret_cast<T*>(ptr)->Release();
     });
   }
 };
 
 template <typename T>
 struct MTAReleaseInChildProcess
 {
   void operator()(T* aPtr)
   {
     if (!aPtr) {
       return;
     }
+
     if (XRE_IsParentProcess()) {
       MOZ_ASSERT(NS_IsMainThread());
       aPtr->Release();
       return;
     }
-    EnsureMTA([&]() -> void
-    {
-      aPtr->Release();
+
+    // Static analysis doesn't recognize that, even though aPtr escapes the
+    // current scope, we are in effect moving our strong ref into the lambda.
+    void* ptr = aPtr;
+    EnsureMTA::AsyncOperation([ptr]() -> void {
+      reinterpret_cast<T*>(ptr)->Release();
     });
   }
 };
 
 struct InterceptorTargetDeleter
 {
   void operator()(IUnknown* aPtr)
   {
@@ -94,16 +116,19 @@ struct InterceptorTargetDeleter
 
 template <typename T>
 using STAUniquePtr = mozilla::UniquePtr<T, detail::MainThreadRelease<T>>;
 
 template <typename T>
 using MTAUniquePtr = mozilla::UniquePtr<T, detail::MTARelease<T>>;
 
 template <typename T>
+using MTADeletePtr = mozilla::UniquePtr<T, detail::MTADelete<T>>;
+
+template <typename T>
 using ProxyUniquePtr = mozilla::UniquePtr<T, detail::MTAReleaseInChildProcess<T>>;
 
 template <typename T>
 using InterceptorTargetPtr =
   mozilla::UniquePtr<T, detail::InterceptorTargetDeleter>;
 
 namespace detail {
 
--- a/ipc/mscom/WeakRef.cpp
+++ b/ipc/mscom/WeakRef.cpp
@@ -47,16 +47,33 @@ SharedRef::Lock()
 
 void
 SharedRef::Unlock()
 {
   ::LeaveCriticalSection(&mCS);
 }
 
 HRESULT
+SharedRef::ToStrongRef(IWeakReferenceSource** aOutStrongReference)
+{
+  RefPtr<IWeakReferenceSource> strongRef;
+
+  { // Scope for lock
+    AutoCriticalSection lock(&mCS);
+    if (!mSupport) {
+      return E_POINTER;
+    }
+    strongRef = mSupport;
+  }
+
+  strongRef.forget(aOutStrongReference);
+  return S_OK;
+}
+
+HRESULT
 SharedRef::Resolve(REFIID aIid, void** aOutStrongReference)
 {
   RefPtr<WeakReferenceSupport> strongRef;
 
   { // Scope for lock
     AutoCriticalSection lock(&mCS);
     if (!mSupport) {
       return E_POINTER;
@@ -211,16 +228,22 @@ WeakRef::Release()
   NS_LOG_RELEASE(this, newRefCnt, "mscom::WeakRef");
   if (newRefCnt == 0) {
     delete this;
   }
   return newRefCnt;
 }
 
 HRESULT
+WeakRef::ToStrongRef(IWeakReferenceSource** aOutStrongReference)
+{
+  return mSharedRef->ToStrongRef(aOutStrongReference);
+}
+
+HRESULT
 WeakRef::Resolve(REFIID aIid, void** aOutStrongReference)
 {
   return mSharedRef->Resolve(aIid, aOutStrongReference);
 }
 
 } // namespace mscom
 } // namespace mozilla
 
--- a/ipc/mscom/WeakRef.h
+++ b/ipc/mscom/WeakRef.h
@@ -18,27 +18,29 @@
 /**
  * Thread-safe weak references for COM that works pre-Windows 8 and do not
  * require WinRT.
  */
 
 namespace mozilla {
 namespace mscom {
 
+struct IWeakReferenceSource;
 class WeakReferenceSupport;
 
 namespace detail {
 
 class SharedRef final
 {
 public:
   explicit SharedRef(WeakReferenceSupport* aSupport);
   void Lock();
   void Unlock();
 
+  HRESULT ToStrongRef(IWeakReferenceSource** aOutStringReference);
   HRESULT Resolve(REFIID aIid, void** aOutStrongReference);
   void Clear();
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedRef)
 
   SharedRef(const SharedRef&) = delete;
   SharedRef(SharedRef&&) = delete;
   SharedRef& operator=(const SharedRef&) = delete;
@@ -55,16 +57,17 @@ private:
 } // namespace detail
 
 // {F841AEFA-064C-49A4-B73D-EBD14A90F012}
 DEFINE_GUID(IID_IWeakReference,
 0xf841aefa, 0x64c, 0x49a4, 0xb7, 0x3d, 0xeb, 0xd1, 0x4a, 0x90, 0xf0, 0x12);
 
 struct IWeakReference : public IUnknown
 {
+  virtual STDMETHODIMP ToStrongRef(IWeakReferenceSource** aOutStrongReference) = 0;
   virtual STDMETHODIMP Resolve(REFIID aIid, void** aOutStrongReference) = 0;
 };
 
 // {87611F0C-9BBB-4F78-9D43-CAC5AD432CA1}
 DEFINE_GUID(IID_IWeakReferenceSource,
 0x87611f0c, 0x9bbb, 0x4f78, 0x9d, 0x43, 0xca, 0xc5, 0xad, 0x43, 0x2c, 0xa1);
 
 struct IWeakReferenceSource : public IUnknown
@@ -109,16 +112,17 @@ class WeakRef final : public IWeakRefere
 {
 public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
 
   // IWeakReference
+  STDMETHODIMP ToStrongRef(IWeakReferenceSource** aOutStrongReference) override;
   STDMETHODIMP Resolve(REFIID aIid, void** aOutStrongReference) override;
 
   explicit WeakRef(RefPtr<detail::SharedRef>& aSharedRef);
 
 private:
   ~WeakRef() = default;
 
   Atomic<ULONG>             mRefCnt;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -14,31 +14,33 @@
  * syntax trees, see Parser.h).  After tree construction, it rewrites trees to
  * fold constants and evaluate compile-time expressions.
  *
  * This parser attempts no error recovery.
  */
 
 #include "frontend/Parser.h"
 
+#include "mozilla/Range.h"
 #include "mozilla/Sprintf.h"
 
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jstypes.h"
 
 #include "builtin/ModuleObject.h"
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/TokenStream.h"
+#include "irregexp/RegExpParser.h"
 #include "vm/RegExpObject.h"
 #include "wasm/AsmJS.h"
 
 #include "jsatominlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/ParseNode-inl.h"
 #include "vm/EnvironmentObject-inl.h"
@@ -9382,35 +9384,54 @@ typename ParseHandler<CharT>::Node
 Parser<ParseHandler, CharT>::noSubstitutionUntaggedTemplate()
 {
     if (!tokenStream.checkForInvalidTemplateEscapeError())
         return null();
 
     return handler.newTemplateStringLiteral(tokenStream.currentToken().atom(), pos());
 }
 
-template <template <typename CharT> class ParseHandler, typename CharT>
-typename ParseHandler<CharT>::Node
-Parser<ParseHandler, CharT>::newRegExp()
+template <>
+ParseNode*
+Parser<FullParseHandler, char16_t>::newRegExp()
 {
     MOZ_ASSERT(!options().selfHostingMode);
-    // Create the regexp even when doing a syntax parse, to check the regexp's syntax.
+
+    // Create the regexp and check its syntax.
     const char16_t* chars = tokenStream.getTokenbuf().begin();
     size_t length = tokenStream.getTokenbuf().length();
     RegExpFlag flags = tokenStream.currentToken().regExpFlags();
 
     Rooted<RegExpObject*> reobj(context);
     reobj = RegExpObject::create(context, chars, length, flags, nullptr, &tokenStream, alloc,
                                  TenuredObject);
     if (!reobj)
         return null();
 
     return handler.newRegExp(reobj, pos(), *this);
 }
 
+template <>
+SyntaxParseHandlerBase::Node
+Parser<SyntaxParseHandler, char16_t>::newRegExp()
+{
+    MOZ_ASSERT(!options().selfHostingMode);
+
+    // Only check the regexp's syntax, but don't create a regexp object.
+    const char16_t* chars = tokenStream.getTokenbuf().begin();
+    size_t length = tokenStream.getTokenbuf().length();
+    RegExpFlag flags = tokenStream.currentToken().regExpFlags();
+
+    mozilla::Range<const char16_t> source(chars, length);
+    if (!js::irregexp::ParsePatternSyntax(tokenStream, alloc, source, flags & UnicodeFlag))
+        return null();
+
+    return handler.newRegExp(SyntaxParseHandlerBase::NodeGeneric, pos(), *this);
+}
+
 template <template <typename CharT> class ParseHandler, typename CharT>
 void
 Parser<ParseHandler, CharT>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
                                                                 PossibleError* possibleError)
 {
     // Return early if a pending destructuring error is already present.
     if (possibleError->hasPendingDestructuringError())
         return;
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -221,17 +221,17 @@ class SyntaxParseHandlerBase
 
     void addToCallSiteObject(Node callSiteObj, Node rawNode, Node cookedNode) {}
 
     Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; }
     Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; }
     Node newRawUndefinedLiteral(const TokenPos& pos) { return NodeGeneric; }
 
     template <class Boxer>
-    Node newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; }
+    Node newRegExp(Node reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; }
 
     Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; }
 
     Node newElision() { return NodeGeneric; }
 
     Node newDelete(uint32_t begin, Node expr) {
         return NodeUnparenthesizedUnary;
     }
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -1961,8 +1961,15 @@ bool
 irregexp::ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
                              bool unicode)
 {
     JS::AutoCheckCannotGC nogc;
     return str->hasLatin1Chars()
            ? ::ParsePatternSyntax(ts, alloc, str->latin1Chars(nogc), str->length(), unicode)
            : ::ParsePatternSyntax(ts, alloc, str->twoByteChars(nogc), str->length(), unicode);
 }
+
+bool
+irregexp::ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc,
+                             const mozilla::Range<const char16_t> chars, bool unicode)
+{
+    return ::ParsePatternSyntax(ts, alloc, chars.begin().get(), chars.length(), unicode);
+}
--- a/js/src/irregexp/RegExpParser.h
+++ b/js/src/irregexp/RegExpParser.h
@@ -26,16 +26,18 @@
 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (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 V8_PARSER_H_
 #define V8_PARSER_H_
 
+#include "mozilla/Range.h"
+
 #include <stdarg.h>
 
 #include "irregexp/RegExpAST.h"
 
 namespace js {
 
 namespace frontend {
     class TokenStream;
@@ -47,16 +49,20 @@ bool
 ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
              bool multiline, bool match_only, bool unicode, bool ignore_case,
              bool global, bool sticky, RegExpCompileData* data);
 
 bool
 ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str,
                    bool unicode);
 
+bool
+ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc,
+                   const mozilla::Range<const char16_t> chars, bool unicode);
+
 // A BufferedVector is an automatically growing list, just like (and backed
 // by) a Vector, that is optimized for the case of adding and removing
 // a single element. The last element added is stored outside the backing list,
 // and if no more than one element is ever added, the ZoneList isn't even
 // allocated.
 // Elements must not be nullptr pointers.
 template <typename T, int initial_size>
 class BufferedVector
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -188,17 +188,19 @@ class Simulator
     // Special case of set_register and get_register to access the raw PC value.
     void set_pc(int32_t value);
     int32_t get_pc() const;
 
     template <typename T>
     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
 
     void trigger_wasm_interrupt() {
-        MOZ_ASSERT(!wasm_interrupt_);
+        // This can be called several times if a single interrupt isn't caught
+        // and handled by the simulator, but this is fine; once the current
+        // instruction is done executing, the interrupt will be handled anyhow.
         wasm_interrupt_ = true;
     }
 
     void enable_single_stepping(SingleStepCallback cb, void* arg);
     void disable_single_stepping();
 
     uintptr_t stackLimit() const;
     bool overRecursed(uintptr_t newsp = 0) const;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1625,86 +1625,41 @@ FirstCharMatcherUnrolled(const TextChar*
         t += 8;
     }
     return nullptr;
 }
 
 static const char*
 FirstCharMatcher8bit(const char* text, uint32_t n, const char pat)
 {
-#if  defined(__clang__)
-    return FirstCharMatcherUnrolled<char, char>(text, n, pat);
-#else
     return reinterpret_cast<const char*>(memchr(text, pat, n));
-#endif
-}
-
-static const char16_t*
-FirstCharMatcher16bit(const char16_t* text, uint32_t n, const char16_t pat)
-{
-#if defined(XP_DARWIN) || defined(XP_WIN)
-    /*
-     * Performance of memchr is horrible in OSX. Windows is better,
-     * but it is still better to use UnrolledMatcher.
-     */
-    return FirstCharMatcherUnrolled<char16_t, char16_t>(text, n, pat);
-#else
-    /*
-     * For linux the best performance is obtained by slightly hacking memchr.
-     * memchr works only on 8bit char but char16_t is 16bit. So we treat char16_t
-     * in blocks of 8bit and use memchr.
-     */
-
-    const char* text8 = (const char*) text;
-    const char* pat8 = reinterpret_cast<const char*>(&pat);
-
-    MOZ_ASSERT(n < UINT32_MAX/2);
-    n *= 2;
-
-    uint32_t i = 0;
-    while (i < n) {
-        /* Find the first 8 bits of 16bit character in text. */
-        const char* pos8 = FirstCharMatcher8bit(text8 + i, n - i, pat8[0]);
-        if (pos8 == nullptr)
-            return nullptr;
-        i = static_cast<uint32_t>(pos8 - text8);
-
-        /* Incorrect match if it matches the last 8 bits of 16bit char. */
-        if (i % 2 != 0) {
-            i++;
-            continue;
-        }
-
-        /* Test if last 8 bits match last 8 bits of 16bit char. */
-        if (pat8[1] == text8[i + 1])
-            return (text + (i/2));
-
-        i += 2;
-    }
-    return nullptr;
-#endif
 }
 
 template <class InnerMatch, typename TextChar, typename PatChar>
 static int
 Matcher(const TextChar* text, uint32_t textlen, const PatChar* pat, uint32_t patlen)
 {
+    MOZ_ASSERT(patlen > 0);
+
+    if (sizeof(TextChar) == 1 && sizeof(PatChar) > 1 && pat[0] > 0xff)
+        return -1;
+
     const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen);
 
     uint32_t i = 0;
     uint32_t n = textlen - patlen + 1;
     while (i < n) {
         const TextChar* pos;
 
-        if (sizeof(TextChar) == 2 && sizeof(PatChar) == 2)
-            pos = (TextChar*) FirstCharMatcher16bit((char16_t*)text + i, n - i, pat[0]);
-        else if (sizeof(TextChar) == 1 && sizeof(PatChar) == 1)
+        if (sizeof(TextChar) == 1) {
+            MOZ_ASSERT(pat[0] <= 0xff);
             pos = (TextChar*) FirstCharMatcher8bit((char*) text + i, n - i, pat[0]);
-        else
-            pos = (TextChar*) FirstCharMatcherUnrolled<TextChar, PatChar>(text + i, n - i, pat[0]);
+        } else {
+            pos = FirstCharMatcherUnrolled(text + i, n - i, char16_t(pat[0]));
+        }
 
         if (pos == nullptr)
             return -1;
 
         i = static_cast<uint32_t>(pos - text);
         if (InnerMatch::match(pat + 1, text + i + 1, extent))
             return i;
 
@@ -1795,17 +1750,17 @@ StringMatch(JSLinearString* text, JSLine
             match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
         else
             match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
     }
 
     return (match == -1) ? -1 : start + match;
 }
 
-static const size_t sRopeMatchThresholdRatioLog2 = 5;
+static const size_t sRopeMatchThresholdRatioLog2 = 4;
 
 bool
 js::StringHasPattern(JSLinearString* text, const char16_t* pat, uint32_t patLen)
 {
     AutoCheckCannotGC nogc;
     return text->hasLatin1Chars()
            ? StringMatch(text->latin1Chars(nogc), text->length(), pat, patLen) != -1
            : StringMatch(text->twoByteChars(nogc), text->length(), pat, patLen) != -1;
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -6,18 +6,18 @@
 # This is fuzzy temporarily until bug 1044702 makes it possible to use source
 # clipping on Windows. (Any other fix would have a significant perf cost.)
 fuzzy-if(winWidget,1,1) == multicolor-image-2.html multicolor-image-2-ref.html
 == multicolor-image-3.html multicolor-image-3-ref.html
 == multicolor-image-4.html multicolor-image-4-ref.html
 == multicolor-image-5.html multicolor-image-5-ref.html
 == transparent-image-1.html transparent-image-1-ref.html
 != repeat-image-1.html repeat-image-1-ref.html
-fuzzy-if(webrender,15-15,950-1000) == 470250-1.html 470250-1-ref.html
-fuzzy-if(webrender,15-15,950-1000) == 470250-2.html 470250-2-ref.html
+fuzzy-if(webrender,15-15,975-975) == 470250-1.html 470250-1-ref.html
+fuzzy-if(webrender,15-15,975-975) == 470250-2.html 470250-2-ref.html
 != different-h-v-1.html different-h-v-ref.html
 != different-h-v-2.html different-h-v-ref.html
 != different-h-v-1.html different-h-v-2.html
 == center-scaling-1.html center-scaling-1-ref.html
 fails-if(Android) fails-if(usesRepeatResampling) == center-scaling-2.html center-scaling-2-ref.html # Android: very different scaling (blurriness) on some sides
 fails-if(Android) fails-if(usesRepeatResampling) == center-scaling-3.html center-scaling-3-ref.html # Android: very different scaling (blurriness) on some sides
 == center-scaling-4t.html center-scaling-4t-ref.html
 == center-scaling-4r.html center-scaling-4r-ref.html
@@ -63,17 +63,17 @@ fuzzy(1,46) fuzzy-if(OSX,2,4472) == bord
 fuzzy(1,105) == border-image-radial-gradient-slice-fill-1.html border-image-radial-gradient-slice-fill-1-ref.html
 fuzzy(1,139) fuzzy-if(OSX,2,4478) fuzzy-if(skiaContent,2,120) == border-image-radial-gradient-slice-fill-2.html border-image-radial-gradient-slice-fill-2-ref.html
 fuzzy-if(skiaContent,1,2) == border-image-radial-gradient-width.html border-image-radial-gradient-width-ref.html
 fuzzy(1,9000) == border-image-radial-gradient-slice-width.html border-image-radial-gradient-slice-width-ref.html
 
 # OS X failures tracked in bug 957025
 == border-image-repeating-linear-gradient.html border-image-repeating-linear-gradient-ref.html
 fuzzy(1,5608) fails-if(OSX) fuzzy-if(skiaContent,3,3157) == border-image-repeating-linear-gradient-slice-fill-2.html border-image-repeating-linear-gradient-slice-fill-2-ref.html
-fuzzy(1,19200) fails-if(OSX) fuzzy-if(skiaContent,3,20000) fuzzy-if(webrender,3-3,20600-21000) == border-image-repeating-linear-gradient-repeat-round-2.html border-image-repeating-linear-gradient-repeat-round-2-ref.html
+fuzzy(1,19200) fails-if(OSX) fuzzy-if(skiaContent,3,20000) fuzzy-if(webrender,3-3,20675-20675) == border-image-repeating-linear-gradient-repeat-round-2.html border-image-repeating-linear-gradient-repeat-round-2-ref.html
 
 fuzzy(1,657) == border-image-repeating-radial-gradient.html border-image-repeating-radial-gradient-ref.html
 fuzzy(1,510) fuzzy-if(skiaContent,3,362) == border-image-repeating-radial-gradient-slice-1.html border-image-repeating-radial-gradient-slice-1-ref.html
 fuzzy(1,438) fuzzy-if(skiaContent,3,437) == border-image-repeating-radial-gradient-slice-2.html border-image-repeating-radial-gradient-slice-2-ref.html
 fuzzy(1,1357) fuzzy-if(skiaContent,3,964) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
 fuzzy(1,1058) fails-if(OSX) fuzzy-if(skiaContent,3,887) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
 fuzzy(1,602) == border-image-repeating-radial-gradient-width.html border-image-repeating-radial-gradient-width-ref.html
 fuzzy(3,18000) fails-if(OSX) fuzzy-if(skiaContent,4,16462) == border-image-repeating-radial-gradient-slice-width.html border-image-repeating-radial-gradient-slice-width-ref.html
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -24,17 +24,17 @@ fuzzy-if(skiaContent,1,343) == percent-3
 
 # more serious tests, using SVG reference
 fuzzy-if(skiaContent,17,58) fuzzy-if(webrender,16,59) == border-circle-2.html border-circle-2-ref.xhtml
 fuzzy-if(gtkWidget,14,280) fuzzy-if(cocoaWidget,4,582) fuzzy-if(Android,36,264) fuzzy-if(d2d,51,323) fuzzy-if(winWidget&&!d2d,16,377) fuzzy-if(skiaContent,63,398) == curved-stripe-border.html curved-stripe-border-ref.svg # bug 459945
 
 # Corners
 fuzzy-if(skiaContent,17,47) == corner-1.html corner-1-ref.svg # bottom corners different radius than top corners
 fuzzy-if(gtkWidget,23,5) fuzzy-if(winWidget&&!d2d,23,5) fuzzy-if(d2d,32,8) fuzzy-if(Android,10,8) fuzzy-if(skiaContent,18,49) == corner-2.html corner-2-ref.svg # right corners different radius than left corners; see bug 500804
-fuzzy-if(gtkWidget,3,10) fuzzy-if(winWidget&&!d2d,3,10) fuzzy-if(d2d,15,32) fuzzy-if(Android,3,15) fuzzy-if(skiaContent,18,90) fuzzy-if(webrender,18-18,90-100) == corner-3.html corner-3-ref.svg
+fuzzy-if(gtkWidget,3,10) fuzzy-if(winWidget&&!d2d,3,10) fuzzy-if(d2d,15,32) fuzzy-if(Android,3,15) fuzzy-if(skiaContent,18,90) fuzzy-if(webrender,18-18,91-91) == corner-3.html corner-3-ref.svg
 fuzzy-if(skiaContent,12,83) == corner-4.html corner-4-ref.svg
 
 # Test that radii too long are reduced
 == border-reduce-height.html border-reduce-height-ref.html
 skip-if(!webrender) pref(layers.advanced.border-layers,1) == border-reduce-height.html border-reduce-height-ref.html
 
 # Tests for border clipping
 fails-if(!styloVsGecko) == clipping-1.html clipping-1-ref.html # background color should completely fill box; bug 466572
@@ -47,17 +47,17 @@ fuzzy-if(skiaContent,17,62) == clipping-
 fuzzy-if(true,1,20) fuzzy-if(d2d,64,196) fuzzy-if(cocoaWidget,1,180) fuzzy-if(Android,140,237) == clipping-4-canvas.html clipping-4-ref.html # bug 732535
 fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,172) == clipping-4-image.html clipping-4-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,77) == clipping-4-overflow-hidden.html clipping-4-ref.html
 == clipping-5-canvas.html clipping-5-refc.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html
 fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
-fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) fuzzy-if(webrender,7-7,60-70) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
+fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) fuzzy-if(webrender,7-7,62-62) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
 fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
 == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
 == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
 fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
 fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
 
@@ -71,17 +71,17 @@ fuzzy-if(true,1,33) fuzzy-if(d2d,48,350)
 fuzzy-if(skiaContent,1,116) == invalidate-1a.html invalidate-1-ref.html
 fuzzy-if(skiaContent,1,117) == invalidate-1b.html invalidate-1-ref.html
 
 # test that border-radius is reduced for scrollbars
 fails-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,12,12) fuzzy-if(browserIsRemote&&layersGPUAccelerated&&/^Windows\x20NT\x206\.1/.test(http.oscpu),12,12) fuzzy-if(skiaContent&&!Android,1,50) fuzzy-if(gtkWidget&&layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html
 fails-if(Android) == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html
 
 # Test for bad corner joins.
-fuzzy-if(true,1,1) fuzzy-if(webrender,13-13,900-1000) == corner-joins-1.xhtml corner-joins-1-ref.xhtml
+fuzzy-if(true,1,1) fuzzy-if(webrender,13-13,913-913) == corner-joins-1.xhtml corner-joins-1-ref.xhtml
 fuzzy(255,20) random-if(winWidget) fuzzy-if(skiaContent,255,610) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml
 
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(d2d,64,157) fuzzy-if(Android,166,400) fuzzy-if(skiaContent,58,145) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166
 
 == transforms-1.html transforms-1-ref.html
 
 == zero-radius-clip-1.html zero-radius-clip-ref.html
 
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -13,19 +13,19 @@ random != boxshadow-blur-2.html boxshado
 fails-if(Android) fuzzy-if(webrender,50,3310) == boxshadow-button.html boxshadow-button-ref.html
 fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,908) fuzzy-if(webrender,48,2040) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
 
 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
 fuzzy-if(skiaContent,13,28) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
 random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
 random-if(d2d) fuzzy-if(skiaContent,1,100) fuzzy-if(webrender,127,3528) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
 fuzzy-if(skiaContent,1,50) HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
-random-if(d2d) fuzzy-if(webrender,1-1,10-20) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
-random-if(d2d) fuzzy-if(webrender,1-1,20-30) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
-random-if(d2d) fuzzy-if(webrender,1-1,40-50) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
+random-if(d2d) fuzzy-if(webrender,1-1,16-16) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
+random-if(d2d) fuzzy-if(webrender,1-1,26-26) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
+random-if(d2d) fuzzy-if(webrender,1-1,42-42) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
 fuzzy(2,440) fuzzy-if(webrender,25,1300) == boxshadow-skiprect.html boxshadow-skiprect-ref.html
 == boxshadow-opacity.html boxshadow-opacity-ref.html
 == boxshadow-color-rounding.html boxshadow-color-rounding-ref.html
 == boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html
 fuzzy(3,500) fuzzy-if(d2d,2,1080) fuzzy-if(webrender,12,1500) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
 fuzzy-if(webrender,1,4) == boxshadow-inset-neg-spread.html about:blank
 == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html
 fuzzy(26,3610) fuzzy-if(d2d,26,5910) fuzzy-if(webrender,43,200) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1192,18 +1192,18 @@ test-pref(dom.use_xbl_scopes_for_remote_
 == 454361.html about:blank
 == 455105-1.html 455105-ref.html
 == 455105-2.html 455105-ref.html
 == 455171-5.html 455171-5-ref.html
 == 455280-1.xhtml 455280-1-ref.xhtml
 == 455826-1.html 455826-1-ref.html
 fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) == 456219-1a.html 456219-1-ref.html # bug 1128229
-fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) fuzzy-if(webrender,24-24,150-200) == 456219-1b.html 456219-1-ref.html # bug 1128229
-fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) fuzzy-if(webrender,24-24,150-200) == 456219-1c.html 456219-1-ref.html # bug 1128229
+fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) fuzzy-if(webrender,24-24,155-155) == 456219-1b.html 456219-1-ref.html # bug 1128229
+fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) fuzzy-if(skiaContent,42,150) fuzzy-if(webrender,24-24,155-155) == 456219-1c.html 456219-1-ref.html # bug 1128229
 fuzzy-if(skiaContent,1,45) == 456219-2.html 456219-2-ref.html
 == 456330-1.gif 456330-1-ref.png
 == 456484-1.html 456484-1-ref.html
 == 457398-1.html 457398-1-ref.html
 == 457398-2.html 457398-2-ref.html
 == 458296-1a.html 458296-1a-ref.html
 == 458296-1b.html 458296-1-ref.html
 == 458296-1c.html 458296-1-ref.html
--- a/layout/reftests/columns/reftest.list
+++ b/layout/reftests/columns/reftest.list
@@ -1,16 +1,16 @@
 == basic-1.html basic-ref.html
 == pref-width-1a.html pref-width-1-ref.html
 == pref-width-1b.html pref-width-1-ref.html
 == pref-width-1c.html pref-width-1-ref.html
 == min-width-1a.html pref-width-1-ref.html
 == min-width-1b.html min-width-1-ref.html
 == min-width-1c.html min-width-1-ref.html
-fuzzy-if(webrender,255-255,30-40) == min-width-2.html min-width-2-ref.html
+fuzzy-if(webrender,255-255,37-37) == min-width-2.html min-width-2-ref.html
 == column-balancing-overflow-000.html column-balancing-overflow-000.ref.html
 == column-balancing-overflow-001.html column-balancing-overflow-000.ref.html
 == column-balancing-overflow-002.html column-balancing-overflow-002.ref.html
 == column-balancing-overflow-003.html column-balancing-overflow-003.ref.html
 == column-balancing-overflow-004.html column-balancing-overflow-004.ref.html
 fuzzy-if(webrender,126,364) == column-balancing-overflow-005.html column-balancing-overflow-005.ref.html
 == column-balancing-000.html column-balancing-000.ref.html
 == column-balancing-001.html column-balancing-000.ref.html
--- a/layout/reftests/css-ui-invalid/default-style/reftest.list
+++ b/layout/reftests/css-ui-invalid/default-style/reftest.list
@@ -1,10 +1,10 @@
 == input.html input-ref.html
-fuzzy-if(webrender,1-1,5-10) == button.html button-ref.html
+fuzzy-if(webrender,1-1,6-6) == button.html button-ref.html
 == textarea.html textarea-ref.html
 == select.html select-ref.html
 == fieldset.html fieldset-ref.html
 == output.html output-ref.html
 random-if(winWidget) needs-focus == input-focus.html input-focus-ref.html # Intermittent failures, bug 660224
 needs-focus == button-focus.html button-focus-ref.html
 needs-focus == textarea-focus.html textarea-focus-ref.html
 random-if(winWidget) needs-focus == select-focus.html select-focus-ref.html # Intermittent failures, bug 660224
--- a/layout/reftests/dom/reftest.list
+++ b/layout/reftests/dom/reftest.list
@@ -46,10 +46,10 @@
 # test appending some nodes whose frame construction should be done lazily
 # followed by appending a node that might not be done lazily
 == multipleappendwithxul.xhtml multipleappendwithxul-ref.xhtml
 == multipleappendwithinput.xhtml multipleappendwithinput-ref.xhtml
 == multipleappendwitheditable.xhtml multipleappendwitheditable-ref.xhtml
 
 fails-if(styloVsGecko||stylo) == xbl-children-1.xhtml xbl-children-1-ref.xhtml
 == xbl-children-2.xhtml about:blank
-fuzzy-if(webrender,8-8,1000-1100) == xbl-children-3.xhtml xbl-children-3-ref.html
+fuzzy-if(webrender,8-8,1036-1036) == xbl-children-3.xhtml xbl-children-3-ref.html
 == xbl-children-4.xhtml about:blank
--- a/layout/reftests/svg/as-image/reftest.list
+++ b/layout/reftests/svg/as-image/reftest.list
@@ -155,18 +155,18 @@ fuzzy-if(skiaContent,255,10) == img-novb
 
 == list-simple-1.html list-simple-1-ref.html
 
 == svg-image-simple-1.svg lime100x100.svg
 == svg-image-simple-2.svg lime100x100.svg
 == svg-image-simple-3.svg lime100x100.svg
 
 # tests for <svg> files that include themselves as an <image>
-fuzzy-if(webrender,1-1,3-5) == svg-image-recursive-1a.svg  svg-image-recursive-1-ref.svg
-fuzzy-if(webrender,1-1,3-5) == svg-image-recursive-1b.svg  svg-image-recursive-1-ref.svg
+fuzzy-if(webrender,1-1,4-4) == svg-image-recursive-1a.svg  svg-image-recursive-1-ref.svg
+fuzzy-if(webrender,1-1,4-4) == svg-image-recursive-1b.svg  svg-image-recursive-1-ref.svg
 == svg-image-recursive-2a.svg  svg-image-recursive-2-ref.svg
 == svg-image-recursive-2b.html svg-image-recursive-2-ref.svg
 
 # tests for external resources vs. data URIs in SVG as an image
 == svg-image-datauri-1.html            lime100x100.svg
 HTTP == svg-image-datauri-1.html       lime100x100.svg
 == svg-image-external-1.html           blue100x100.svg
 HTTP == svg-image-external-1.html      blue100x100.svg
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -328,17 +328,17 @@ fuzzy-if(skiaContent,7,175) fuzzy-if(ski
 == overflow-on-outer-svg-02d.xhtml overflow-on-outer-svg-02-ref.xhtml
 == overflow-on-outer-svg-03a.xhtml overflow-on-outer-svg-03-ref.xhtml
 == overflow-on-outer-svg-03b.xhtml overflow-on-outer-svg-03-ref.xhtml
 
 == paint-on-maskLayer-1a.html paint-on-maskLayer-1-ref.html
 == paint-on-maskLayer-1b.html paint-on-maskLayer-1-ref.html
 pref(layout.css.clip-path-shapes.enabled,true) == paint-on-maskLayer-1c.html paint-on-maskLayer-1-ref.html
 pref(svg.paint-order.enabled,true) == paint-order-01.svg paint-order-01-ref.svg
-pref(svg.paint-order.enabled,true) fuzzy-if(webrender,1-1,110-120) == paint-order-02.svg paint-order-02-ref.svg
+pref(svg.paint-order.enabled,true) fuzzy-if(webrender,1-1,112-112) == paint-order-02.svg paint-order-02-ref.svg
 pref(svg.paint-order.enabled,true) == paint-order-03.svg paint-order-03-ref.svg
 
 #fuzzy(23,60) fails-if(d2d) == path-01.svg path-01-ref.svg
 == path-02.svg pass.svg
 == path-03.svg pass.svg
 == path-04.svg pass.svg
 == path-05.svg pass.svg
 fuzzy-if(skiaContent,1,400) == path-06.svg path-06-ref.svg
--- a/layout/reftests/svg/smil/transform/reftest.list
+++ b/layout/reftests/svg/smil/transform/reftest.list
@@ -4,15 +4,15 @@
 fuzzy(111,1802) fuzzy-if(skiaContent,130,1000) == additive-1.svg additive-1-ref.svg # bug 981344, bug 1239766
 == animate-width-1.svg lime.svg
 fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,30) fuzzy-if(gtkWidget,1,30) == paced-1.svg paced-1-ref.svg # bug 981640, Bug 1293550
 fuzzy-if(skiaContent,7,90) == rotate-angle-1.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,7,90) == rotate-angle-2.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,7,130) == rotate-angle-3.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,7,90) == rotate-angle-4.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,1,130) == rotate-angle-5.svg rotate-angle-ref.svg
-fuzzy(12,27) fuzzy-if(skiaContent,1,180) fuzzy-if(Android,16,3) fuzzy-if(webrender,7-7,300-310) == scale-1.svg scale-1-ref.svg  # bug 981004
+fuzzy(12,27) fuzzy-if(skiaContent,1,180) fuzzy-if(Android,16,3) fuzzy-if(webrender,7-7,306-306) == scale-1.svg scale-1-ref.svg  # bug 981004
 == set-transform-1.svg lime.svg
 fuzzy-if(winWidget||gtkWidget||OSX,1,27) fuzzy-if(skiaContent,7,1548) == skew-1.svg skew-1-ref.svg # bug 983671, Bug 1260629
 == translate-clipPath-1.svg lime.svg
 == translate-gradient-1.svg lime.svg
 == translate-pattern-1.svg lime.svg
 == use-1.svg lime.svg
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -13,32 +13,32 @@ default-preferences pref(layout.css.clip
 == clip-path-polygon-007.html clip-path-stripes-001-ref.html
 == clip-path-polygon-008.html clip-path-stripes-002-ref.html
 == clip-path-polygon-009.html clip-path-square-002-ref.html
 == clip-path-polygon-010.html clip-path-stripes-001-ref.html
 == clip-path-polygon-011.html clip-path-stripes-001-ref.html
 == clip-path-polygon-012.html clip-path-stripes-001-ref.html
 fuzzy-if(skiaContent,1,20) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
 
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-001.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-002.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-003.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-004.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,90-90,705-705) == clip-path-circle-001.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,90-90,705-705) == clip-path-circle-002.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,90-90,705-705) == clip-path-circle-003.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,90-90,705-705) == clip-path-circle-004.html clip-path-circle-001-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-005.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-006.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,90-90,705-705) == clip-path-circle-006.html clip-path-circle-001-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-007.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-008.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-009.html clip-path-circle-003-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-010.html clip-path-circle-004-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-011.html clip-path-circle-005-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-012.html clip-path-circle-006-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-013.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-014.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,90-90,709-709) == clip-path-circle-014.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-015.html clip-path-circle-008-ref.html
-fuzzy-if(webrender,90-90,700-710) == clip-path-circle-016.html clip-path-circle-009-ref.html
+fuzzy-if(webrender,90-90,709-709) == clip-path-circle-016.html clip-path-circle-009-ref.html
 fuzzy-if(webrender,128,714) == clip-path-circle-017.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-018.html clip-path-circle-010-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-019.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64,714) == clip-path-circle-020.html clip-path-circle-002-ref.html
 == clip-path-circle-021.html clip-path-circle-021-ref.html
 
 fuzzy-if(webrender,64,1106) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,64,1106) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2096,22 +2096,22 @@ pref("network.auth.subresource-img-cross
 //
 // This preference has no effect when the browser is set to "Never Remember History",
 // in that case default credentials will always be used.
 pref("network.auth.private-browsing-sso", false);
 
 // Control how throttling of http responses works - number of ms that each
 // suspend and resume period lasts (prefs named appropriately)
 pref("network.http.throttle.enable", true);
-pref("network.http.throttle.suspend-for", 3000);
-pref("network.http.throttle.resume-for", 200);
+pref("network.http.throttle.suspend-for", 900);
+pref("network.http.throttle.resume-for", 100);
 // Delay we resume throttled background responses after the last unthrottled
 // response has finished.  Prevents resuming too soon during an active page load
 // at which sub-resource reqeusts quickly come and go.
-pref("network.http.throttle.resume-background-in", 400);
+pref("network.http.throttle.resume-background-in", 1000);
 
 pref("permissions.default.image",           1); // 1-Accept, 2-Deny, 3-dontAcceptForeign
 
 pref("network.proxy.type",                  5);
 pref("network.proxy.ftp",                   "");
 pref("network.proxy.ftp_port",              0);
 pref("network.proxy.http",                  "");
 pref("network.proxy.http_port",             0);
@@ -5218,17 +5218,17 @@ pref("urlclassifier.phishTable", "googpu
 #ifdef NIGHTLY_BUILD
 pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256,goog-downloadwhite-proto");
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar,goog-badbinurl-proto");
 #else
 pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
 #endif // NIGHTLY_BUILD
 
-pref("urlclassifier.disallow_completions", "test-malware-simple,test-phish-simple,test-unwanted-simple,test-track-simple,test-trackwhite-simple,test-block-simple,test-flashallow-simple,testexcept-flashallow-simple,test-flash-simple,testexcept-flash-simple,test-flashsubdoc-simple,testexcept-flashsubdoc-simple,goog-downloadwhite-digest256,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");
+pref("urlclassifier.disallow_completions", "test-malware-simple,test-phish-simple,test-unwanted-simple,test-track-simple,test-trackwhite-simple,test-block-simple,test-flashallow-simple,testexcept-flashallow-simple,test-flash-simple,testexcept-flash-simple,test-flashsubdoc-simple,testexcept-flashsubdoc-simple,goog-downloadwhite-digest256,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");
 
 // The table and update/gethash URLs for Safebrowsing phishing and malware
 // checks.
 pref("urlclassifier.trackingTable", "test-track-simple,base-track-digest256");
 pref("urlclassifier.trackingWhitelistTable", "test-trackwhite-simple,mozstd-trackwhite-digest256");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
@@ -5286,17 +5286,17 @@ pref("browser.safebrowsing.provider.goog
 pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
 
 // The table and global pref for blocking plugin content
 pref("browser.safebrowsing.blockedURIs.enabled", true);
 pref("urlclassifier.blockedTable", "test-block-simple,mozplugin-block-digest256");
 
 // The protocol version we communicate with mozilla server.
 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");
+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");
 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");
@@ -5304,16 +5304,17 @@ pref("browser.safebrowsing.provider.mozi
 pref("browser.safebrowsing.provider.mozilla.lists.content.description", "mozfullDesc");
 
 pref("urlclassifier.flashAllowTable", "test-flashallow-simple,allow-flashallow-digest256");
 pref("urlclassifier.flashAllowExceptTable", "testexcept-flashallow-simple,except-flashallow-digest256");
 pref("urlclassifier.flashTable", "test-flash-simple,block-flash-digest256");
 pref("urlclassifier.flashExceptTable", "testexcept-flash-simple,except-flash-digest256");
 pref("urlclassifier.flashSubDocTable", "test-flashsubdoc-simple,block-flashsubdoc-digest256");
 pref("urlclassifier.flashSubDocExceptTable", "testexcept-flashsubdoc-simple,except-flashsubdoc-digest256");
+pref("urlclassifier.flashInfobarTable", "except-flashinfobar-digest256");
 
 pref("plugins.http_https_only", true);
 pref("plugins.flashBlock.enabled", false);
 
 // Allow users to ignore Safe Browsing warnings.
 pref("browser.safebrowsing.allowOverride", true);
 
 #ifdef MOZILLA_OFFICIAL
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3004,18 +3004,18 @@ nsHttpConnectionMgr::RemoveActiveTransac
         LOG(("  delay resuming throttled for background tabs"));
         DelayedResumeBackgroundThrottledTransactions();
         return;
     }
 
     if (forActiveTab) {
         // Removing the last transaction for the active tab frees up the unthrottled
         // background tabs transactions.
-        LOG(("  resuming unthrottled for background tabs"));
-        ResumeReadOf(mActiveTransactions[false]);
+        LOG(("  delay resuming unthrottled for background tabs"));
+        DelayedResumeBackgroundThrottledTransactions();
         return;
     }
 
     LOG(("  not resuming anything"));
 }
 
 void
 nsHttpConnectionMgr::MoveActiveTransaction(nsHttpTransaction * aTrans, bool aThrottled)
@@ -3031,47 +3031,67 @@ nsHttpConnectionMgr::ShouldStopReading(n
 {
     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
 
     if (!mThrottlingInhibitsReading || !mThrottleEnabled) {
         return false;
     }
 
     uint64_t tabId = aTrans->TopLevelOuterContentWindowId();
+    bool forActiveTab = tabId == mCurrentTopLevelOuterContentWindowId;
 
     if (mActiveTabTransactionsExist) {
         if (!tabId) {
             // Chrome initiated and unidentified transactions just respect
             // their throttle flag, when something for the active tab is happening.
             return aThrottled;
         }
-        if (tabId != mCurrentTopLevelOuterContentWindowId) {
+        if (!forActiveTab) {
             // This is a background tab request, we want them to always throttle.
             return true;
         }
         if (mActiveTabUnthrottledTransactionsExist) {
             // Unthrottled transactions for the active tab take precedence
             return aThrottled;
         }
         // This is a throttled transaction for the active tab and there are no
         // unthrottled for the active tab, just let go on full fuel.
         return false;
     }
 
+    MOZ_ASSERT(!forActiveTab);
+
+    if (mDelayedResumeReadTimer) {
+        // If this timer exists, background transactions are scheduled to be woken
+        // after a delay.
+        return true;
+    }
+
     if (!mActiveTransactions[false].IsEmpty()) {
         // This means there are unthrottled active transactions for background tabs.
         // If we are here, there can't be any transactions for the active tab.
         // (If there is no transaction for a tab id, there is no entry for it in the hashtable.)
         return aThrottled;
     }
 
     // There are only unthrottled transactions for background tabs: don't throttle.
     return false;
 }
 
+bool nsHttpConnectionMgr::IsConnEntryUnderPressure(nsHttpConnectionInfo *connInfo)
+{
+    nsConnectionEntry *ent = mCT.Get(connInfo->HashKey());
+    MOZ_ASSERT(ent);
+
+    nsTArray<RefPtr<PendingTransactionInfo>> *transactions =
+        ent->mPendingTransactionTable.Get(mCurrentTopLevelOuterContentWindowId);
+
+    return transactions && !transactions->IsEmpty();
+}
+
 bool nsHttpConnectionMgr::IsThrottleTickerNeeded()
 {
     LOG(("nsHttpConnectionMgr::IsThrottleTickerNeeded"));
 
     if (mActiveTabUnthrottledTransactionsExist &&
         mActiveTransactions[false].Count() > 1) {
         LOG(("  there are unthrottled transactions for both active and bck"));
         return true;
@@ -3148,31 +3168,31 @@ void
 nsHttpConnectionMgr::ThrottlerTick()
 {
     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
 
     mThrottlingInhibitsReading = !mThrottlingInhibitsReading;
 
     LOG(("nsHttpConnectionMgr::ThrottlerTick inhibit=%d", mThrottlingInhibitsReading));
 
-    if (!mThrottlingInhibitsReading && !IsThrottleTickerNeeded()) {
+    // If there are only background transactions to be woken after a delay, keep
+    // the ticker so that we woke them only for the resume-for interval and then
+    // throttle them again until the background-resume delay passes.
+    if (!mThrottlingInhibitsReading &&
+        !mDelayedResumeReadTimer &&
+        !IsThrottleTickerNeeded()) {
+        LOG(("  last tick"));
         mThrottleTicker = nullptr;
-    } else {
-        mThrottleTicker = do_CreateInstance("@mozilla.org/timer;1");
     }
 
     if (mThrottlingInhibitsReading) {
         if (mThrottleTicker) {
             mThrottleTicker->Init(this, mThrottleSuspendFor, nsITimer::TYPE_ONE_SHOT);
         }
     } else {
-        // Resume by the ticker happens sooner than delayed resume, no need
-        // for the delayed resume timer
-        CancelDelayedResumeBackgroundThrottledTransactions();
-
         if (mThrottleTicker) {
             mThrottleTicker->Init(this, mThrottleResumeFor, nsITimer::TYPE_ONE_SHOT);
         }
 
         ResumeReadOf(mActiveTransactions[false], true);
         ResumeReadOf(mActiveTransactions[true]);
     }
 }
@@ -3208,25 +3228,25 @@ nsHttpConnectionMgr::CancelDelayedResume
 void
 nsHttpConnectionMgr::ResumeBackgroundThrottledTransactions()
 {
     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
 
     LOG(("nsHttpConnectionMgr::ResumeBackgroundThrottledTransactions"));
     mDelayedResumeReadTimer = nullptr;
 
-    // We can destroy the ticker, since only transactions to resume now
-    // are background throttled.  If 'higher class' transactions have
-    // been added, we don't get here - the ticker has been scheduled
-    // and hence the delayed resume timer canceled.
-    MOZ_ASSERT(mActiveTransactions[false].IsEmpty() &&
-                          !mActiveTabTransactionsExist);
-
-    DestroyThrottleTicker();
-    ResumeReadOf(mActiveTransactions[true], true);
+    if (!IsThrottleTickerNeeded()) {
+        DestroyThrottleTicker();
+    }
+
+    if (!mActiveTransactions[false].IsEmpty()) {
+        ResumeReadOf(mActiveTransactions[false], true);
+    } else {
+        ResumeReadOf(mActiveTransactions[true], true);
+    }
 }
 
 void
 nsHttpConnectionMgr::ResumeReadOf(
     nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>>& hashtable,
     bool excludeForActiveTab)
 {
     for (auto iter = hashtable.Iter(); !iter.Done(); iter.Next()) {
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -221,16 +221,22 @@ public:
     void MoveActiveTransaction(nsHttpTransaction* aTrans, bool aThrottled);
 
     // called by nsHttpTransaction::WriteSegments.  decides whether the transaction
     // should stop reading data based on: the throttling ticker status, overall
     // status of all active transactions regarding active tab and respective
     // throttling state.
     bool ShouldStopReading(nsHttpTransaction* aTrans, bool aThrottled);
 
+    // return true iff the connection has pending transactions for the active tab.
+    // it's mainly used to disallow throttling (stop reading) of a response
+    // belonging to the same conn info to free up a connection ASAP.
+    // NOTE: relatively expensive to call, there are two hashtable lookups.
+    bool IsConnEntryUnderPressure(nsHttpConnectionInfo*);
+
 private:
     virtual ~nsHttpConnectionMgr();
 
     class nsHalfOpenSocket;
     class PendingTransactionInfo;
 
     // nsConnectionEntry
     //
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -815,37 +815,63 @@ nsHttpTransaction::WritePipeSegment(nsIO
     //
     rv = trans->ProcessData(buf, *countWritten, countWritten);
     if (NS_FAILED(rv))
         trans->Close(rv);
 
     return rv; // failure code only stops WriteSegments; it is not propagated.
 }
 
+bool nsHttpTransaction::ShouldStopReading()
+{
+    if (mActivatedAsH2) {
+        // Throttling feature is now disabled for http/2 transactions
+        // because of bug 1367861.  The logic around mActivatedAsH2
+        // will be removed when that is fixed
+        return false;
+    }
+
+    if (!gHttpHandler->ConnMgr()->ShouldStopReading(
+            this, mClassOfService & nsIClassOfService::Throttleable)) {
+        // We are not obligated to throttle
+        return false;
+    }
+
+    if (mContentRead < 16000) {
+        // Let the first bytes go, it may also well be all the content we get
+        LOG(("nsHttpTransaction::ShouldStopReading too few content (%" PRIi64 ") this=%p", mContentRead, this));
+        return false;
+    }
+
+    if (gHttpHandler->ConnMgr()->IsConnEntryUnderPressure(mConnInfo)) {
+        LOG(("nsHttpTransaction::ShouldStopReading entry pressure this=%p", this));
+        // This is expensive to check (two hashtable lookups) but may help
+        // freeing connections for active tab transactions.
+        return false;
+    }
+
+    return true;
+}
+
 nsresult
 nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
                                  uint32_t count, uint32_t *countWritten)
 {
     LOG(("nsHttpTransaction::WriteSegments %p", this));
 
     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
 
     if (mTransactionDone) {
         return NS_SUCCEEDED(mStatus) ? NS_BASE_STREAM_CLOSED : mStatus;
     }
 
-    // Throttling feature is now disabled for http/2 transactions
-    // because of bug 1367861.  The logic around mActivatedAsH2
-    // will be removed when that is fixed
-    if (!mActivatedAsH2 &&
-        gHttpHandler->ConnMgr()->ShouldStopReading(this,
-            mClassOfService & nsIClassOfService::Throttleable)) {
-        LOG(("nsHttpTransaction::WriteSegments %p response throttled", this));
+    if (ShouldStopReading()) {
         // Must remember that we have to call ResumeRecv() on our connection when
         // called back by the conn manager to resume reading.
+        LOG(("nsHttpTransaction::WriteSegments %p response throttled", this));
         mReadingStopped = true;
         // This makes the underlaying connection or stream wait for explicit resume.
         // For h1 this means we stop reading from the socket.
         // For h2 this means we stop updating recv window for the stream.
         return NS_BASE_STREAM_WOULD_BLOCK;
     }
 
     mWriter = writer;
--- a/netwerk/protocol/http/nsHttpTransaction.h
+++ b/netwerk/protocol/http/nsHttpTransaction.h
@@ -218,16 +218,20 @@ private:
     // Called right after we parsed the response head.  Checks for connection based
     // authentication schemes in reponse headers for WWW and Proxy authentication.
     // If such is found in any of them, NS_HTTP_STICKY_CONNECTION is set in mCaps.
     // We need the sticky flag be set early to keep the connection from very start
     // of the authentication process.
     void CheckForStickyAuthScheme();
     void CheckForStickyAuthSchemeAt(nsHttpAtom const& header);
 
+    // Called from WriteSegments.  Checks for conditions whether to throttle reading
+    // the content.  When this returns true, WriteSegments returns WOULD_BLOCK.
+    bool ShouldStopReading();
+
 private:
     class UpdateSecurityCallbacks : public Runnable
     {
       public:
         UpdateSecurityCallbacks(nsHttpTransaction* aTrans,
                                 nsIInterfaceRequestor* aCallbacks)
         : mTrans(aTrans), mCallbacks(aCallbacks) {}
 
--- a/old-configure.in
+++ b/old-configure.in
@@ -61,17 +61,17 @@ CAIRO_VERSION=1.10
 GTK2_VERSION=2.18.0
 GTK3_VERSION=3.4.0
 GDK_VERSION_MAX_ALLOWED=GDK_VERSION_3_4
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GCONF_VERSION=1.2.1
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
-SQLITE_VERSION=3.19.2
+SQLITE_VERSION=3.19.3
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 
 dnl Initialize the Pthread test variables early so they can be
 dnl  overridden by each platform.
 dnl ========================================================
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
@@ -38,16 +38,19 @@ std::unique_ptr<BYTE[]> GetTokenInfo(con
   *error = ERROR_SUCCESS;
   return buffer;
 }
 
 }  // namespace
 
 namespace sandbox {
 
+// We want to use restricting SIDs in the tokens by default.
+bool gUseRestricting = true;
+
 RestrictedToken::RestrictedToken()
     : integrity_level_(INTEGRITY_LEVEL_LAST),
       init_(false),
       lockdown_default_dacl_(false) {}
 
 RestrictedToken::~RestrictedToken() {
 }
 
@@ -78,17 +81,17 @@ DWORD RestrictedToken::Init(const HANDLE
 
 DWORD RestrictedToken::GetRestrictedToken(
     base::win::ScopedHandle* token) const {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
   size_t deny_size = sids_for_deny_only_.size();
-  size_t restrict_size = sids_to_restrict_.size();
+  size_t restrict_size = gUseRestricting ? sids_to_restrict_.size() : 0;
   size_t privileges_size = privileges_to_disable_.size();
 
   SID_AND_ATTRIBUTES *deny_only_array = NULL;
   if (deny_size) {
     deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
 
     for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
       deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
@@ -221,33 +224,41 @@ DWORD RestrictedToken::GetRestrictedToke
   return ERROR_SUCCESS;
 }
 
 DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
+  // If this is normally a token with restricting SIDs, but we're not allowing
+  // them, then use the sids_to_restrict_ as an exceptions list to give a
+  // similar effect.
+  std::vector<Sid>* localExpections =
+    gUseRestricting || !sids_to_restrict_.size() ? exceptions : &sids_to_restrict_;
+
   DWORD error;
   std::unique_ptr<BYTE[]> buffer =
       GetTokenInfo(effective_token_, TokenGroups, &error);
 
   if (!buffer)
     return error;
 
   TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
 
-  // Build the list of the deny only group SIDs
+  // Build the list of the deny only group SIDs.  We want to be able to have
+  // logon SID as deny only, if we're not allowing restricting SIDs.
   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
-        (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
+        (!gUseRestricting ||
+         (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0)) {
       bool should_ignore = false;
-      if (exceptions) {
-        for (unsigned int j = 0; j < exceptions->size(); ++j) {
-          if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
+      if (localExpections) {
+        for (unsigned int j = 0; j < localExpections->size(); ++j) {
+          if (::EqualSid(const_cast<SID*>((*localExpections)[j].GetPSID()),
                           token_groups->Groups[i].Sid)) {
             should_ignore = true;
             break;
           }
         }
       }
       if (!should_ignore) {
         sids_for_deny_only_.push_back(
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.h
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
@@ -20,16 +20,19 @@
 #define SE_GROUP_INTEGRITY (0x00000020L)
 #endif
 #ifndef SE_GROUP_INTEGRITY_ENABLED
 #define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
 #endif
 
 namespace sandbox {
 
+// Whether we are allowing restricting SIDs in the access tokens or not.
+extern bool gUseRestricting;
+
 // Handles the creation of a restricted token using the effective token or
 // any token handle.
 // Sample usage:
 //    RestrictedToken restricted_token;
 //    DWORD err_code = restricted_token.Init(NULL);  // Use the current
 //                                                   // effective token
 //    if (ERROR_SUCCESS != err_code) {
 //      // handle error.
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
@@ -78,16 +78,17 @@ DWORD CreateRestrictedToken(TokenLevel s
       restricted_token.AddRestrictingSidLogonSession();
       break;
     }
     case USER_LIMITED: {
       sid_exceptions.push_back(WinBuiltinUsersSid);
       sid_exceptions.push_back(WinWorldSid);
       sid_exceptions.push_back(WinInteractiveSid);
       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+      restricted_token.AddUserSidForDenyOnly();
       restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
       restricted_token.AddRestrictingSid(WinWorldSid);
       restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
 
       // This token has to be able to create objects in BNO.
       // Unfortunately, on Vista+, it needs the current logon sid
       // in the token to achieve this. You should also set the process to be
       // low integrity level so it can't access object created by other
--- a/security/sandbox/win/SandboxInitialization.cpp
+++ b/security/sandbox/win/SandboxInitialization.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=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 "SandboxInitialization.h"
 
+#include "sandbox/win/src/restricted_token.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "mozilla/sandboxing/permissionsService.h"
 
 namespace mozilla {
 namespace sandboxing {
 
 static sandbox::TargetServices*
 InitializeTargetServices()
@@ -73,15 +74,31 @@ sandbox::BrokerServices*
 GetInitializedBrokerServices()
 {
   static sandbox::BrokerServices* sInitializedBrokerServices =
     InitializeBrokerServices();
 
   return sInitializedBrokerServices;
 }
 
+void
+NetworkDriveCheck()
+{
+  wchar_t exePath[MAX_PATH];
+  if (!::GetModuleFileNameW(nullptr, exePath, MAX_PATH)) {
+    return;
+  }
+
+  wchar_t volPath[MAX_PATH];
+  if (!::GetVolumePathNameW(exePath, volPath, MAX_PATH)) {
+    return;
+  }
+
+  sandbox::gUseRestricting = (::GetDriveTypeW(volPath) != DRIVE_REMOTE);
+}
+
 PermissionsService* GetPermissionsService()
 {
   return PermissionsService::GetInstance();
 }
 
 } // sandboxing
 } // mozilla
--- a/security/sandbox/win/SandboxInitialization.h
+++ b/security/sandbox/win/SandboxInitialization.h
@@ -38,14 +38,22 @@ void LowerSandbox();
 
 /**
  * Initializes (if required) and returns the Chromium sandbox BrokerServices.
  *
  * @return the BrokerServices or null if the creation or initialization failed.
  */
 sandbox::BrokerServices* GetInitializedBrokerServices();
 
+/**
+ * Checks to see if we are running from a network drive and sets a flag in
+ * sandbox code to disable the use of restricting SIDs.
+ * Using restricting SIDs blocks access to network drives and prevents DLL
+ * loading during initial sandboxed child process start-up.
+ */
+void NetworkDriveCheck();
+
 PermissionsService* GetPermissionsService();
 
 } // sandboxing
 } // mozilla
 
 #endif // mozilla_sandboxing_SandboxInitialization_h
--- a/testing/mozharness/configs/merge_day/beta_to_release.py
+++ b/testing/mozharness/configs/merge_day/beta_to_release.py
@@ -11,24 +11,26 @@ config = {
         },
     ],
     "replacements": [
         # File, from, to
         ("{}{}".format(d, f),
         "ac_add_options --with-branding=mobile/android/branding/beta",
         "ac_add_options --with-branding=mobile/android/branding/official")
         for d in ["mobile/android/config/mozconfigs/android-api-15/",
-                  "mobile/android/config/mozconfigs/android-x86/"]
+                  "mobile/android/config/mozconfigs/android-x86/",
+                  "mobile/android/config/mozconfigs/android-aarch64/"]
         for f in ["debug", "nightly", "l10n-nightly"]
     ] + [
         # File, from, to
         (f, "ac_add_options --with-l10n-base=../../mozilla-beta",
         "ac_add_options --with-l10n-base=../../mozilla-release")
         for f in ["mobile/android/config/mozconfigs/android-api-15/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly"]
+                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly",
+                  "mobile/android/config/mozconfigs/android-aarch64/l10n-nightly"]
     ] + [
         # File, from, to
         ("browser/confvars.sh",
          "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-beta,firefox-mozilla-release",
          "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-release"),
         ("browser/confvars.sh",
          "MAR_CHANNEL_ID=firefox-mozilla-beta",
          "MAR_CHANNEL_ID=firefox-mozilla-release"),
--- a/testing/mozharness/configs/merge_day/central_to_beta.py
+++ b/testing/mozharness/configs/merge_day/central_to_beta.py
@@ -10,38 +10,41 @@ config = {
         {"file": "config/milestone.txt", "suffix": ""},
     ],
     "replacements": [
         # File, from, to
         ("{}{}".format(d, f),
         "ac_add_options --with-branding=mobile/android/branding/nightly",
         "ac_add_options --with-branding=mobile/android/branding/beta")
         for d in ["mobile/android/config/mozconfigs/android-api-15/",
-                  "mobile/android/config/mozconfigs/android-x86/"]
+                  "mobile/android/config/mozconfigs/android-x86/",
+                  "mobile/android/config/mozconfigs/android-aarch64/"]
         for f in ["debug", "nightly", "l10n-nightly"]
     ] + [
         # File, from, to
         (f, "ac_add_options --with-branding=browser/branding/nightly",
         "ac_add_options --enable-official-branding")
         for f in ["browser/config/mozconfigs/linux32/l10n-mozconfig",
                   "browser/config/mozconfigs/linux64/l10n-mozconfig",
                   "browser/config/mozconfigs/win32/l10n-mozconfig",
                   "browser/config/mozconfigs/win64/l10n-mozconfig",
                   "browser/config/mozconfigs/macosx64/l10n-mozconfig"]
     ] + [
         # File, from, to
         (f, "ac_add_options --with-l10n-base=../../l10n-central",
         "ac_add_options --with-l10n-base=../../mozilla-beta")
         for f in ["mobile/android/config/mozconfigs/android-api-15/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly"]
+                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly",
+                  "mobile/android/config/mozconfigs/android-aarch64/l10n-nightly"]
     ] + [
         # File, from, to
         (f, "ac_add_options --enable-profiling", "") for f in
         ["mobile/android/config/mozconfigs/android-api-15/nightly",
          "mobile/android/config/mozconfigs/android-x86/nightly",
+         "mobile/android/config/mozconfigs/android-aarch64/nightly",
          "browser/config/mozconfigs/linux32/nightly",
          "browser/config/mozconfigs/linux64/nightly",
          "browser/config/mozconfigs/macosx64/nightly",
          "browser/config/mozconfigs/win32/nightly",
          "browser/config/mozconfigs/win64/nightly"]
     ] + [
         # File, from, to
         ("browser/confvars.sh",
--- a/testing/mozharness/configs/releases/dev_updates_firefox_beta.py
+++ b/testing/mozharness/configs/releases/dev_updates_firefox_beta.py
@@ -16,17 +16,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "ftp.stage.mozaws.net",
     "archive_prefix": "https://ftp.stage.mozaws.net/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "http://ec2-54-241-39-23.us-west-1.compute.amazonaws.com",
-    "balrog_username": "stage-ffxbld",
+    "balrog_username": "balrog-stage-ffxbld",
     "update_channels": {
         "beta-dev": {
             "version_regex": r"^(\d+\.\d+(b\d+)?)$",
             "requires_mirrors": True,
             # TODO - when we use a real repo, rename this file # s/MozDate/MozBeta-dev/
             "patcher_config": "mozDate-branch-patcher2.cfg",
             "update_verify_channel": "beta-dev-localtest",
             "mar_channel_ids": [],
--- a/testing/mozharness/configs/releases/dev_updates_firefox_release.py
+++ b/testing/mozharness/configs/releases/dev_updates_firefox_release.py
@@ -16,17 +16,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "ftp.stage.mozaws.net",
     "archive_prefix": "https://ftp.stage.mozaws.net/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "http://ec2-54-241-39-23.us-west-1.compute.amazonaws.com",
-    "balrog_username": "stage-ffxbld",
+    "balrog_username": "balrog-stage-ffxbld",
     "update_channels": {
         "beta-dev": {
             "version_regex": r"^(\d+\.\d+(b\d+)?)$",
             "requires_mirrors": False,
             "patcher_config": "mozDate-branch-patcher2.cfg",
             "update_verify_channel": "beta-dev-localtest",
             "mar_channel_ids": [
                 "firefox-mozilla-beta-dev", "firefox-mozilla-release-dev",
--- a/testing/mozharness/configs/releases/updates_firefox_beta.py
+++ b/testing/mozharness/configs/releases/updates_firefox_beta.py
@@ -13,17 +13,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "archive.mozilla.org",
     "archive_prefix": "https://archive.mozilla.org/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "https://aus5.mozilla.org",
-    "balrog_username": "ffxbld",
+    "balrog_username": "balrog-ffxbld",
     "update_channels": {
         "beta": {
             "version_regex": r"^(\d+\.\d+(b\d+)?)$",
             "requires_mirrors": True,
             "patcher_config": "mozBeta-branch-patcher2.cfg",
             "update_verify_channel": "beta-localtest",
             "mar_channel_ids": [],
             "channel_names": ["beta", "beta-localtest", "beta-cdntest"],
--- a/testing/mozharness/configs/releases/updates_firefox_devedition.py
+++ b/testing/mozharness/configs/releases/updates_firefox_devedition.py
@@ -13,17 +13,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "archive.mozilla.org",
     "archive_prefix": "https://archive.mozilla.org/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "https://aus5.mozilla.org",
-    "balrog_username": "ffxbld",
+    "balrog_username": "balrog-ffxbld",
     "update_channels": {
         "aurora": {
             "version_regex": r"^.*$",
             "requires_mirrors": True,
             "patcher_config": "mozDevedition-branch-patcher2.cfg",
             # Allow to override the patcher config product name, regardless
             # the value set by buildbot properties
             "patcher_config_product_override": "firefox",
--- a/testing/mozharness/configs/releases/updates_firefox_esr52.py
+++ b/testing/mozharness/configs/releases/updates_firefox_esr52.py
@@ -13,17 +13,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "archive.mozilla.org",
     "archive_prefix": "https://archive.mozilla.org/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "https://aus5.mozilla.org",
-    "balrog_username": "ffxbld",
+    "balrog_username": "balrog-ffxbld",
     "update_channels": {
         "esr": {
             "version_regex": r".*",
             "requires_mirrors": True,
             "patcher_config": "mozEsr52-branch-patcher2.cfg",
             "update_verify_channel": "esr-localtest",
             "mar_channel_ids": [],
             "channel_names": ["esr", "esr-localtest", "esr-cdntest"],
--- a/testing/mozharness/configs/releases/updates_firefox_release.py
+++ b/testing/mozharness/configs/releases/updates_firefox_release.py
@@ -13,17 +13,17 @@ config = {
     "ignore_no_changes": True,
     "ssh_user": "ffxbld",
     "ssh_key": "~/.ssh/ffxbld_rsa",
     "archive_domain": "archive.mozilla.org",
     "archive_prefix": "https://archive.mozilla.org/pub",
     "previous_archive_prefix": "https://archive.mozilla.org/pub",
     "download_domain": "download.mozilla.org",
     "balrog_url": "https://aus5.mozilla.org",
-    "balrog_username": "ffxbld",
+    "balrog_username": "balrog-ffxbld",
     "update_channels": {
         "beta": {
             "version_regex": r"^(\d+\.\d+(b\d+)?)$",
             "requires_mirrors": False,
             "patcher_config": "mozBeta-branch-patcher2.cfg",
             "update_verify_channel": "beta-localtest",
             "mar_channel_ids": [
                 "firefox-mozilla-beta", "firefox-mozilla-release",
--- a/testing/tools/autotry/autotry.py
+++ b/testing/tools/autotry/autotry.py
@@ -249,17 +249,22 @@ class AutoTry(object):
             'action': 'store_true',
             'dest': 'all_emails',
             'help': 'Request all emails',
         },
         '--artifact': {
             'action': 'store_true',
             'dest': 'artifact',
             'help': 'Force artifact builds where possible.',
-        }
+        },
+        '--upload-xdbs': {
+            'action': 'store_true',
+            'dest': 'upload_xdbs',
+            'help': 'Upload XDB compilation db files generated by hazard build',
+        },
     }
 
     def __init__(self, topsrcdir, resolver_func, mach_context):
         self.topsrcdir = topsrcdir
         self._resolver_func = resolver_func
         self._resolver = None
         self.mach_context = mach_context
 
--- a/testing/web-platform/tests/web-animations/testcommon.js
+++ b/testing/web-platform/tests/web-animations/testcommon.js
@@ -73,17 +73,18 @@ function createStyle(test, rules, doc) {
   test.add_cleanup(function() {
     extraStyle.remove();
   });
 }
 
 // Create a pseudo element
 function createPseudo(test, type) {
   createStyle(test, { '@keyframes anim': '',
-                      ['.pseudo::' + type]: 'animation: anim 10s;' });
+                      ['.pseudo::' + type]: 'animation: anim 10s; ' +
+                                            'content: \'\';'  });
   var div = createDiv(test);
   div.classList.add('pseudo');
   var anims = document.getAnimations();
   assert_true(anims.length >= 1);
   var anim = anims[anims.length - 1];
   assert_equals(anim.effect.target.parentElement, div);
   assert_equals(anim.effect.target.type, '::' + type);
   anim.cancel();
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -64,16 +64,17 @@ skip-if = (os == 'linux' && debug) || (t
 [test_ext_contentscript_context.html]
 [test_ext_contentscript_create_iframe.html]
 [test_ext_contentscript_devtools_metadata.html]
 [test_ext_contentscript_exporthelpers.html]
 [test_ext_contentscript_incognito.html]
 skip-if = os == 'android' # Android does not support multiple windows.
 [test_ext_contentscript_css.html]
 [test_ext_contentscript_about_blank.html]
+skip-if = os == 'android' # bug 1369440
 [test_ext_contentscript_permission.html]
 [test_ext_contentscript_teardown.html]
 [test_ext_exclude_include_globs.html]
 [test_ext_external_messaging.html]
 [test_ext_generate.html]
 [test_ext_geolocation.html]
 skip-if = os == 'android' # Android support Bug 1336194
 [test_ext_notifications.html]
--- a/toolkit/components/satchel/test/browser/browser.ini
+++ b/toolkit/components/satchel/test/browser/browser.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 support-files =
   !/toolkit/components/satchel/test/subtst_privbrowsing.html
 
+[browser_popup_mouseover.js]
 [browser_privbrowsing_perwindowpb.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/satchel/test/browser/browser_popup_mouseover.js
@@ -0,0 +1,54 @@
+/* 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/. */
+
+const {FormHistory} = Cu.import("resource://gre/modules/FormHistory.jsm", {});
+
+
+add_task(async function test() {
+  const url = `data:text/html,<input type="text" name="field1">`;
+  await BrowserTestUtils.withNewTab({gBrowser, url}, async function(browser) {
+    const {autoCompletePopup, autoCompletePopup: {richlistbox: itemsBox}} = browser;
+    const mockHistory = [
+      {op: "add", fieldname: "field1", value: "value1"},
+      {op: "add", fieldname: "field1", value: "value2"},
+      {op: "add", fieldname: "field1", value: "value3"},
+      {op: "add", fieldname: "field1", value: "value4"},
+    ];
+
+    await new Promise(resolve => FormHistory.update([{op: "remove"}, ...mockHistory], {handleCompletion: resolve}));
+    await ContentTask.spawn(browser, {}, async function() {
+      const input = content.document.querySelector("input");
+
+      input.focus();
+    });
+
+    // show popup
+    await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
+    await BrowserTestUtils.waitForCondition(() => {
+      return autoCompletePopup.popupOpen;
+    });
+    const listItemElems = itemsBox.querySelectorAll(".autocomplete-richlistitem");
+    is(listItemElems.length, mockHistory.length, "ensure result length");
+    is(itemsBox.mousedOverIndex, -1, "mousedOverIndex should be -1");
+
+    // navigate to the firt item
+    await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
+    is(autoCompletePopup.selectedIndex, 0, "selectedIndex should be 0");
+
+    // mouseover the second item
+    EventUtils.synthesizeMouseAtCenter(listItemElems[1], {type: "mouseover"});
+    await BrowserTestUtils.waitForCondition(() => {
+      return itemsBox.mousedOverIndex = 1;
+    });
+    ok(true, "mousedOverIndex changed");
+    is(autoCompletePopup.selectedIndex, 0, "selectedIndex should not be changed by mouseover");
+
+    // close popup
+    await ContentTask.spawn(browser, {}, async function() {
+      const input = content.document.querySelector("input");
+
+      input.blur();
+    });
+  });
+});
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13316,10 +13316,22 @@
     "alert_emails": ["addons-dev-internal@mozilla.com"],
     "bug_numbers": [1353171],
     "expires_in_version": "60",
     "kind": "exponential",
     "releaseChannelCollection": "opt-out",
     "high": 50000,
     "n_buckets": 100,
     "description": "The amount of time it takes for a WebExtension to start up, from when the startup function is called to when the startup promise resolves."
+  },
+  "NOTIFY_OBSERVERS_LATENCY_MS": {
+    "record_in_processes": ["main", "content", "gpu"],
+    "alert_emails": ["michael@thelayzells.com"],
+    "bug_numbers": [1368524],
+    "expires_in_version": "60",
+    "kind": "exponential",
+    "low": 3,
+    "high": 512,
+    "n_buckets": 20,
+    "keyed": true,
+    "description": "Measures the number of milliseconds we spend synchronously notifying observers, keyed by topic. Note: only NotifyObservers calls which take over 500 microseconds are included in this probe."
   }
 }
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -42,17 +42,18 @@ const tablePreferences = [
   "urlclassifier.trackingTable",
   "urlclassifier.trackingWhitelistTable",
   "urlclassifier.blockedTable",
   "urlclassifier.flashAllowTable",
   "urlclassifier.flashAllowExceptTable",
   "urlclassifier.flashTable",
   "urlclassifier.flashExceptTable",
   "urlclassifier.flashSubDocTable",
-  "urlclassifier.flashSubDocExceptTable"
+  "urlclassifier.flashSubDocExceptTable",
+  "urlclassifier.flashInfobarTable"
 ];
 
 this.SafeBrowsing = {
 
   init: function() {
     if (this.initialized) {
       log("Already initialized");
       return;
@@ -113,34 +114,40 @@ this.SafeBrowsing = {
       this.registerTableWithURLs(this.trackingProtectionWhitelists[i]);
     }
     for (let i = 0; i < this.blockedLists.length; ++i) {
       this.registerTableWithURLs(this.blockedLists[i]);
     }
     for (let i = 0; i < this.flashLists.length; ++i) {
       this.registerTableWithURLs(this.flashLists[i]);
     }
+    for (let i = 0; i < this.flashInfobarLists.length; ++i) {
+      this.registerTableWithURLs(this.flashInfobarLists[i]);
+    }
   },
 
 
   initialized:          false,
   phishingEnabled:      false,
   malwareEnabled:       false,
   trackingEnabled:      false,
   blockedEnabled:       false,
   trackingAnnotations:  false,
   flashBlockEnabled:    false,
+  flashInfobarListEnabled: true,
 
   phishingLists:                [],
   malwareLists:                 [],
   downloadBlockLists:           [],
   downloadAllowLists:           [],
   trackingProtectionLists:      [],
   trackingProtectionWhitelists: [],
   blockedLists:                 [],
+  flashLists:                   [],
+  flashInfobarLists:            [],
 
   updateURL:             null,
   gethashURL:            null,
 
   reportURL:             null,
 
   getReportURL: function(kind, info) {
     let pref;
@@ -208,17 +215,18 @@ this.SafeBrowsing = {
      this.trackingProtectionLists,
      this.trackingProtectionWhitelists,
      this.blockedLists,
      flashAllowTable,
      flashAllowExceptTable,
      flashTable,
      flashExceptTable,
      flashSubDocTable,
-     flashSubDocExceptTable] = tablePreferences.map(getLists);
+     flashSubDocExceptTable,
+     this.flashInfobarLists] = tablePreferences.map(getLists);
 
     this.flashLists = flashAllowTable.concat(flashAllowExceptTable,
                                              flashTable,
                                              flashExceptTable,
                                              flashSubDocTable,
                                              flashSubDocExceptTable)
 
     this.updateProviderURLs();
@@ -301,17 +309,18 @@ this.SafeBrowsing = {
       }
     }, this);
   },
 
   controlUpdateChecking: function() {
     log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:",
         this.malwareEnabled, "trackingEnabled:", this.trackingEnabled,
         "blockedEnabled:", this.blockedEnabled, "trackingAnnotations",
-        this.trackingAnnotations, "flashBlockEnabled", this.flashBlockEnabled);
+        this.trackingAnnotations, "flashBlockEnabled", this.flashBlockEnabled,
+        "flashInfobarListEnabled:", this.flashInfobarListEnabled);
 
     let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                       getService(Ci.nsIUrlListManager);
 
     for (let i = 0; i < this.phishingLists.length; ++i) {
       if (this.phishingEnabled) {
         listManager.enableUpdate(this.phishingLists[i]);
       } else {
@@ -362,16 +371,23 @@ this.SafeBrowsing = {
     }
     for (let i = 0; i < this.flashLists.length; ++i) {
       if (this.flashBlockEnabled) {
         listManager.enableUpdate(this.flashLists[i]);
       } else {
         listManager.disableUpdate(this.flashLists[i]);
       }
     }
+    for (let i = 0; i < this.flashInfobarLists.length; ++i) {
+      if (this.flashInfobarListEnabled) {
+        listManager.enableUpdate(this.flashInfobarLists[i]);
+      } else {
+        listManager.disableUpdate(this.flashInfobarLists[i]);
+      }
+    }
     listManager.maybeToggleUpdateChecking();
   },
 
 
   addMozEntries: function() {
     // Add test entries to the DB.
     // XXX bug 779008 - this could be done by DB itself?
     const phishURL    = "itisatrap.org/firefox/its-a-trap.html";
--- a/toolkit/content/tests/reftests/reftest.list
+++ b/toolkit/content/tests/reftests/reftest.list
@@ -1,3 +1,3 @@
-random-if(cocoaWidget) == bug-442419-progressmeter-max.xul bug-442419-progressmeter-max-ref.xul # fails most of the time on Mac because progress meter animates
+random-if(cocoaWidget||(/^Windows\x20NT\x206\.2/.test(http.oscpu)&&isDebugBuild)) == bug-442419-progressmeter-max.xul bug-442419-progressmeter-max-ref.xul # fails most of the time on Mac because progress meter animates
 != textbox-multiline-default-value.xul textbox-multiline-empty.xul
 fails-if(styloVsGecko) == videocontrols-dynamically-add-cc.html videocontrols-dynamically-add-cc-ref.html
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -2585,17 +2585,24 @@ extends="chrome://global/content/binding
         while (item && item.localName != "richlistitem") {
           item = item.parentNode;
         }
 
         if (!item) {
           return;
         }
 
-        this.mousedOverIndex = this.getIndexOfItem(item);
+        let index = this.getIndexOfItem(item);
+
+        this.mousedOverIndex = index;
+
+        if (item.selectedByMouseOver) {
+          this.selectedIndex = index;
+        }
+
         this.mLastMoveTime = Date.now();
       ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="autocomplete-treebody">
     <implementation>
--- a/toolkit/content/widgets/richlistbox.xml
+++ b/toolkit/content/widgets/richlistbox.xml
@@ -529,16 +529,18 @@
       <children/>
     </content>
 
     <resources>
       <stylesheet src="chrome://global/skin/richlistbox.css"/>
     </resources>
 
     <implementation>
+      <field name="selectedByMouseOver">false</field>
+
       <destructor>
         <![CDATA[
           var control = this.control;
           if (!control)
             return;
           // When we are destructed and we are current or selected, unselect ourselves
           // so that richlistbox's selection doesn't point to something not in the DOM.
           // We don't want to reset last-selected, so we set _suppressOnSelect.
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -1494,49 +1494,25 @@ ChildFPEFilter(void* context, EXCEPTION_
   if (result) {
     PrepareChildExceptionTimeAnnotations();
   }
   return result;
 }
 
 MINIDUMP_TYPE GetMinidumpType()
 {
-  MINIDUMP_TYPE minidump_type = MiniDumpNormal;
-
-  // Try to determine what version of dbghelp.dll we're using.
-  // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer.
-
-  DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", nullptr);
-  if (version_size > 0) {
-    std::vector<BYTE> buffer(version_size);
-    if (GetFileVersionInfoW(L"dbghelp.dll",
-                            0,
-                            version_size,
-                            &buffer[0])) {
-      UINT len;
-      VS_FIXEDFILEINFO* file_info;
-      VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len);
-      WORD major = HIWORD(file_info->dwFileVersionMS),
-        minor = LOWORD(file_info->dwFileVersionMS),
-        revision = HIWORD(file_info->dwFileVersionLS);
-      if (major > 6 || (major == 6 && minor > 1) ||
-          (major == 6 && minor == 1 && revision >= 7600)) {
-        minidump_type = MiniDumpWithFullMemoryInfo;
-      }
+  MINIDUMP_TYPE minidump_type = MiniDumpWithFullMemoryInfo;
+
 #ifdef NIGHTLY_BUILD
-      // This is Nightly only because this doubles the size of minidumps based
-      // on the experimental data.
-      if (major > 5 || (major == 5 && minor > 1)) {
-        minidump_type = static_cast<MINIDUMP_TYPE>(minidump_type |
-            MiniDumpWithUnloadedModules |
-            MiniDumpWithProcessThreadData);
-      }
+  // This is Nightly only because this doubles the size of minidumps based
+  // on the experimental data.
+  minidump_type = static_cast<MINIDUMP_TYPE>(minidump_type |
+      MiniDumpWithUnloadedModules |
+      MiniDumpWithProcessThreadData);
 #endif
-    }
-  }
 
   const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
   if (e && *e) {
     minidump_type = MiniDumpWithFullMemory;
   }
 
   return minidump_type;
 }
--- a/toolkit/modules/tests/modules/MockDocument.jsm
+++ b/toolkit/modules/tests/modules/MockDocument.jsm
@@ -4,31 +4,37 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["MockDocument"]
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.importGlobalProperties(["URL"]);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 
 const MockDocument = {
   /**
    * Create a document for the given URL containing the given HTML with the ownerDocument of all <form>s having a mocked location.
    */
   createTestDocument(aDocumentURL, aContent = "<form>", aType = "text/html") {
     let parser = Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(Ci.nsIDOMParser);
     parser.init();
     let parsedDoc = parser.parseFromString(aContent, aType);
 
+    // Assign onwerGlobal to documentElement as well for the form-less
+    // inputs treating it as rootElement.
+    this.mockOwnerGlobalProperty(parsedDoc.documentElement);
+
     for (let element of parsedDoc.forms) {
       this.mockOwnerDocumentProperty(element, parsedDoc, aDocumentURL);
+      this.mockOwnerGlobalProperty(element);
     }
     return parsedDoc;
   },
 
   mockOwnerDocumentProperty(aElement, aDoc, aURL) {
     // Mock the document.location object so we can unit test without a frame. We use a proxy
     // instead of just assigning to the property since it's not configurable or writable.
     let document = new Proxy(aDoc, {
@@ -43,16 +49,29 @@ const MockDocument = {
     });
 
     // Assign element.ownerDocument to the proxy so document.location works.
     Object.defineProperty(aElement, "ownerDocument", {
       value: document,
     });
   },
 
+  mockOwnerGlobalProperty(aElement) {
+    Object.defineProperty(aElement, "ownerGlobal", {
+      value: {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
+        getInterface: () => ({
+          addManuallyManagedState() {},
+          removeManuallyManagedState() {},
+        }),
+      },
+      configurable: true,
+    });
+  },
+
   createTestDocumentFromFile(aDocumentURL, aFile) {
     let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
                      createInstance(Ci.nsIFileInputStream);
     fileStream.init(aFile, -1, -1, 0);
 
     let data = NetUtil.readInputStreamToString(fileStream, fileStream.available());
 
     return this.createTestDocument(aDocumentURL, data);
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -13,19 +13,24 @@
 #include "nsObserverService.h"
 #include "nsObserverList.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsEnumeratorUtils.h"
 #include "xpcpublic.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/Services.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/TimeStamp.h"
+#include "nsString.h"
 
 #define NOTIFY_GLOBAL_OBSERVERS
 
+static const uint32_t kMinTelemetryNotifyObserversLatencyMs = 1;
+
 // Log module for nsObserverService logging...
 //
 // To enable logging (see prlog.h for full details):
 //
 //    set MOZ_LOG=ObserverService:5
 //    set MOZ_LOG_FILE=service.log
 //
 // This enables LogLevel::Debug level information and places all output in
@@ -271,28 +276,37 @@ NS_IMETHODIMP nsObserverService::NotifyO
 {
   LOG(("nsObserverService::NotifyObservers(%s)", aTopic));
 
   NS_ENSURE_VALIDCALL
   if (NS_WARN_IF(!aTopic)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  mozilla::TimeStamp start = TimeStamp::Now();
+
   nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
   if (observerList) {
     observerList->NotifyObservers(aSubject, aTopic, aSomeData);
   }
 
 #ifdef NOTIFY_GLOBAL_OBSERVERS
   observerList = mObserverTopicTable.GetEntry("*");
   if (observerList) {
     observerList->NotifyObservers(aSubject, aTopic, aSomeData);
   }
 #endif
 
+  uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
+  if (latencyMs >= kMinTelemetryNotifyObserversLatencyMs) {
+    Telemetry::Accumulate(Telemetry::NOTIFY_OBSERVERS_LATENCY_MS,
+                          nsDependentCString(aTopic),
+                          latencyMs);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObserverService::UnmarkGrayStrongObservers()
 {
   NS_ENSURE_VALIDCALL
 
--- a/xpcom/io/nsLocalFileUnix.cpp
+++ b/xpcom/io/nsLocalFileUnix.cpp
@@ -1748,42 +1748,40 @@ nsLocalFile::GetNativeTarget(nsACString&
     return NSRESULT_FOR_ERRNO();
   }
 
   if (!S_ISLNK(symStat.st_mode)) {
     return NS_ERROR_FILE_INVALID_PATH;
   }
 
   int32_t size = (int32_t)symStat.st_size;
-  char* target = (char*)moz_xmalloc(size + 1);
-  if (!target) {
+  nsAutoCString target;
+  if (!target.SetLength(size, mozilla::fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  if (readlink(mPath.get(), target, (size_t)size) < 0) {
-    free(target);
+  if (readlink(mPath.get(), target.BeginWriting(), (size_t)size) < 0) {
     return NSRESULT_FOR_ERRNO();
   }
-  target[size] = '\0';
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIFile> self(this);
   int32_t maxLinks = 40;
   while (true) {
     if (maxLinks-- == 0) {
       rv = NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
       break;
     }
 
     if (target[0] != '/') {
       nsCOMPtr<nsIFile> parent;
       if (NS_FAILED(rv = self->GetParent(getter_AddRefs(parent)))) {
         break;
       }
-      if (NS_FAILED(rv = parent->AppendRelativeNativePath(nsDependentCString(target)))) {
+      if (NS_FAILED(rv = parent->AppendRelativeNativePath(target))) {
         break;
       }
       if (NS_FAILED(rv = parent->GetNativePath(aResult))) {
         break;
       }
       self = parent;
     } else {
       aResult = target;
@@ -1798,36 +1796,31 @@ nsLocalFile::GetNativeTarget(nsACString&
     }
 
     // And of course we're done if it isn't a symlink.
     if (!S_ISLNK(symStat.st_mode)) {
       break;
     }
 
     int32_t newSize = (int32_t)symStat.st_size;
-    if (newSize > size) {
-      char* newTarget = (char*)moz_xrealloc(target, newSize + 1);
-      if (!newTarget) {
-        rv = NS_ERROR_OUT_OF_MEMORY;
-        break;
-      }
-      target = newTarget;
-      size = newSize;
+    size = newSize;
+    nsAutoCString newTarget;
+    if (!newTarget.SetLength(size, mozilla::fallible)) {
+      rv = NS_ERROR_OUT_OF_MEMORY;
+      break;
     }
 
-    int32_t linkLen = readlink(flatRetval.get(), target, size);
+    int32_t linkLen = readlink(flatRetval.get(), newTarget.BeginWriting(), size);
     if (linkLen == -1) {
       rv = NSRESULT_FOR_ERRNO();
       break;
     }
-    target[linkLen] = '\0';
+    target = newTarget;
   }
 
-  free(target);
-
   if (NS_FAILED(rv)) {
     aResult.Truncate();
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocalFile::GetFollowLinks(bool* aFollowLinks)