Merge mozilla-central to inbound a=merge on a CLOSED TREE
authorCoroiu Cristina <ccoroiu@mozilla.com>
Wed, 21 Nov 2018 23:50:57 +0200
changeset 504041 e92b86330728c5e78343d092d074762c34423540
parent 504040 11e4a0b13d536bf8306de656927d76de5c1fb7b6 (current diff)
parent 504033 fbd97100c83cc07705244725a3245e6d14bbe9cf (diff)
child 504042 fee6e5895b63477ac789aa50db43e6912e30106d
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound a=merge on a CLOSED TREE
testing/web-platform/meta/resource-timing/resource_subframe_self_navigation.html.ini
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -74,17 +74,17 @@ gfx/sfntly/.*
 gfx/skia/.*
 gfx/vr/service/openvr/.*
 gfx/webrender/.*
 gfx/webrender_api/.*
 gfx/wrench/.*
 gfx/ycbcr/.*
 intl/hyphenation/hyphen/.*
 intl/icu/.*
-ipc/chromium/.*
+ipc/chromium/src/third_party/.*
 js/src/ctypes/libffi/.*
 js/src/dtoa.c.*
 js/src/jit/arm64/vixl/.*
 js/src/vtune/disable_warnings.h
 js/src/vtune/ittnotify.h
 js/src/vtune/ittnotify_config.h
 js/src/vtune/ittnotify_static.c
 js/src/vtune/ittnotify_static.h
--- a/.eslintignore
+++ b/.eslintignore
@@ -179,85 +179,72 @@ dom/cache/test/mochitest/**
 dom/cache/test/xpcshell/**
 dom/canvas/**
 dom/console/**
 dom/crypto/**
 dom/encoding/**
 dom/events/**
 dom/fetch/**
 dom/file/**
-dom/filehandle/**
 dom/filesystem/**
 dom/flex/**
-dom/gamepad/**
-dom/geolocation/**
 dom/grid/**
 dom/html/**
-dom/imptests/**
-dom/interfaces/**
 dom/ipc/**
 dom/jsurl/**
-dom/locales/**
 dom/manifest/**
-dom/mathml/**
 dom/media/test/**
 dom/media/tests/**
 dom/media/webaudio/**
 dom/media/webspeech/**
 dom/messagechannel/**
 dom/midi/**
 dom/network/**
 dom/notification/Notification*.*
 dom/notification/test/browser/**
 dom/notification/test/mochitest/**
-dom/offline/**
 dom/payments/**
 dom/performance/**
 dom/permission/**
 dom/plugins/test/mochitest/**
 dom/plugins/test/unit/**
-dom/power/**
 dom/promise/**
 dom/push/**
 dom/quota/**
-dom/res/**
 dom/security/test/cors/**
 dom/security/test/csp/**
 dom/security/test/general/**
 dom/security/test/mixedcontentblocker/**
 dom/security/test/sri/**
 dom/security/test/unit/**
 dom/serviceworkers/**
 dom/smil/**
-dom/storage/**
 dom/svg/**
 dom/system/**
 dom/tests/browser/**
 dom/tests/html/**
-dom/tests/js/**
 dom/tests/mochitest/**
 dom/tests/unit/**
 dom/u2f/**
 dom/url/**
 dom/vr/**
 dom/webauthn/**
-dom/webbrowserpersist/**
 dom/webgpu/**
-dom/webidl/**
 dom/websocket/**
 dom/workers/**
 dom/worklet/**
 dom/xbl/**
 dom/xhr/**
 dom/xml/**
 dom/xslt/**
 dom/xul/**
 
 # Third-party
 dom/canvas/test/webgl-conf/**
+dom/imptests/**
 dom/media/webvtt/**
 
 # Third-party
 editor/libeditor/tests/browserscope/**
 
 # Third-party
 gfx/ots/**
 gfx/skia/**
--- a/.flake8
+++ b/.flake8
@@ -5,21 +5,21 @@ max-line-length = 99
 exclude =
     browser/extensions/mortar/ppapi/,
     browser/moz.configure,
     build/moz.configure/*.configure,
     build/pymake/,
     dom/canvas/test/webgl-conf/checkout/closure-library/,
     editor/libeditor/tests/browserscope/,
     intl/icu/,
-    ipc/chromium/,
+    ipc/chromium/src/third_party/,
     gfx/angle/,
     gfx/harfbuzz,
     glx/skia/,
     js/*.configure,
     memory/moz.configure,
     mobile/android/*.configure,
     node_modules,
     security/nss/,
     testing/mochitest/pywebsocket,
     tools/lint/test/files,
     build/build-infer/build-infer.py,
-    tools/infer/test/*.configure,    tools/infer/test/*.configure,
\ No newline at end of file
+    tools/infer/test/*.configure,    tools/infer/test/*.configure,
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -281,17 +281,20 @@ var StarUI = {
   // we start a PlacesTransactions batch when the star UI panel is shown, and
   // we keep the batch ongoing until the panel is hidden.
   _batchBlockingDeferred: null,
   beginBatch() {
     if (this._batching)
       return;
     this._batchBlockingDeferred = PromiseUtils.defer();
     PlacesTransactions.batch(async () => {
+      // First await for the batch to be concluded.
       await this._batchBlockingDeferred.promise;
+      // And then for any pending promises added in the meanwhile.
+      await Promise.all(gEditItemOverlay.transactionPromises);
     });
     this._batching = true;
   },
 
   endBatch() {
     if (!this._batching)
       return;
 
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -1,12 +1,13 @@
 /* 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/. */
 
+/* eslint-env mozilla/browser-window */
 
 /**
  * Utility object to handle manipulations of the identity indicators in the UI
  */
 var gIdentityHandler = {
   /**
    * nsIURI for which the identity UI is displayed. This has been already
    * processed by nsIURIFixup.createExposableURI.
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -278,17 +278,17 @@ window:not([chromehidden~="toolbar"]) #n
  */
 #widget-overflow-list:empty + #widget-overflow-fixed-separator,
 #widget-overflow:not([hasfixeditems]) #widget-overflow-fixed-separator {
   display: none;
 }
 
 
 %ifdef MENUBAR_CAN_AUTOHIDE
-#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-item,
+#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-buttonbox-container,
 #toolbar-menubar:not([autohide=true]) + #TabsToolbar .titlebar-spacer,
 %endif
 %ifndef MOZ_WIDGET_COCOA
 #main-window:not([sizemode=normal]) .titlebar-spacer[type="pre-tabs"],
 %endif
 #main-window:not([chromemargin]) .titlebar-buttonbox-container,
 #main-window[inFullscreen] .titlebar-buttonbox-container,
 #main-window[inFullscreen] .titlebar-spacer,
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -106,16 +106,18 @@ XPCOMUtils.defineLazyScriptGetter(this, 
                                          "gXPInstallObserver"],
                                   "chrome://browser/content/browser-addons.js");
 XPCOMUtils.defineLazyScriptGetter(this, "ctrlTab",
                                   "chrome://browser/content/browser-ctrlTab.js");
 XPCOMUtils.defineLazyScriptGetter(this, ["CustomizationHandler", "AutoHideMenubar"],
                                   "chrome://browser/content/browser-customization.js");
 XPCOMUtils.defineLazyScriptGetter(this, ["PointerLock", "FullScreen"],
                                   "chrome://browser/content/browser-fullScreenAndPointerLock.js");
+XPCOMUtils.defineLazyScriptGetter(this, "gIdentityHandler",
+                                  "chrome://browser/content/browser-siteIdentity.js");
 XPCOMUtils.defineLazyScriptGetter(this, ["gGestureSupport", "gHistorySwipeAnimation"],
                                   "chrome://browser/content/browser-gestureSupport.js");
 XPCOMUtils.defineLazyScriptGetter(this, "gSafeBrowsing",
                                   "chrome://browser/content/browser-safebrowsing.js");
 XPCOMUtils.defineLazyScriptGetter(this, "gSync",
                                   "chrome://browser/content/browser-sync.js");
 XPCOMUtils.defineLazyScriptGetter(this, "gBrowserThumbnails",
                                   "chrome://browser/content/browser-thumbnails.js");
@@ -5303,17 +5305,17 @@ const AccessibilityRefreshBlocker = {
       mm.loadFrameScript("chrome://browser/content/content-refreshblocker.js", true, true);
     }
   },
 };
 
 var TabsProgressListener = {
   onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
     // Collect telemetry data about tab load times.
-    if (aWebProgress.isTopLevel && (!aRequest.originalURI || aRequest.originalURI.spec.scheme != "about")) {
+    if (aWebProgress.isTopLevel && (!aRequest.originalURI || aRequest.originalURI.scheme != "about")) {
       let stopwatchRunning = TelemetryStopwatch.running("FX_PAGE_LOAD_MS_2", aBrowser);
 
       if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
         if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
           if (stopwatchRunning) {
             // Oops, we're seeing another start without having noticed the previous stop.
             TelemetryStopwatch.cancel("FX_PAGE_LOAD_MS_2", aBrowser);
           }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -785,20 +785,20 @@ xmlns="http://www.w3.org/1999/xhtml"
 
             <hbox class="titlebar-spacer" type="post-tabs"
                   ordinal="1000"
                   skipintoolbarset="true"/>
           </hbox>
         </vbox>
 
 #ifndef XP_MACOSX
-        <button class="accessibility-indicator titlebar-item"  tooltiptext="&accessibilityIndicator.tooltip;"
+        <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
                 ordinal="1000"
                 aria-live="polite" skipintoolbarset="true"/>
-        <hbox class="private-browsing-indicator titlebar-item" skipintoolbarset="true"
+        <hbox class="private-browsing-indicator" skipintoolbarset="true"
               ordinal="1000"/>
 #endif
 
 #include titlebar-items.inc.xul
 
 #ifdef XP_MACOSX
         <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
              buttonbox from reversing order in RTL by forcing an LTR direction. -->
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -20,17 +20,16 @@ for (let script of [
   "chrome://browser/content/browser-captivePortal.js",
   "chrome://browser/content/browser-compacttheme.js",
   "chrome://browser/content/browser-contentblocking.js",
   "chrome://browser/content/browser-media.js",
   "chrome://browser/content/browser-pageActions.js",
   "chrome://browser/content/browser-places.js",
   "chrome://browser/content/browser-plugins.js",
   "chrome://browser/content/browser-sidebar.js",
-  "chrome://browser/content/browser-siteIdentity.js",
   "chrome://browser/content/browser-tabsintitlebar.js",
 
   "chrome://global/content/globalOverlay.js",
   "chrome://browser/content/utilityOverlay.js",
 #ifdef XP_MACOSX
   "chrome://global/content/macWindowMenu.js",
 #endif
 #ifdef MOZ_DATA_REPORTING
--- a/browser/base/content/test/general/browser_bookmark_popup.js
+++ b/browser/base/content/test/general/browser_bookmark_popup.js
@@ -82,17 +82,18 @@ async function test_bookmarks_popup({isN
       if (!shouldAutoClose) {
         await new Promise(resolve => setTimeout(resolve, 400));
         Assert.equal(bookmarkPanel.state, "open", "Panel should still be 'open' for non-autoclose");
       }
 
       let onItemRemovedPromise = Promise.resolve();
       if (isBookmarkRemoved) {
         onItemRemovedPromise = PlacesTestUtils.waitForNotification("onItemRemoved",
-          (id, parentId, index, type, itemUrl) => TEST_URL == itemUrl.spec);
+          (id, parentId, index, type, uri, guid, parentGuid) =>
+            parentGuid == PlacesUtils.bookmarks.unfiledGuid && TEST_URL == uri.spec);
       }
 
       let hiddenPromise = promisePopupHidden(bookmarkPanel);
       if (popupHideFn) {
         await popupHideFn();
       }
       await Promise.all([hiddenPromise, onItemRemovedPromise]);
 
@@ -132,21 +133,21 @@ add_task(async function panel_shown_once
   });
 });
 
 add_task(async function panel_shown_once_for_slow_doubleclick_on_new_bookmark_star_and_autocloses() {
   todo(false, "bug 1250267, may need to add some tracking state to " +
               "browser-places.js for this.");
 
   /*
-  yield test_bookmarks_popup({
+  await test_bookmarks_popup({
     isNewBookmark: true,
     *popupShowFn() {
       EventUtils.synthesizeMouse(bookmarkStar, 10, 10, window);
-      yield new Promise(resolve => setTimeout(resolve, 300));
+      await new Promise(resolve => setTimeout(resolve, 300));
       EventUtils.synthesizeMouse(bookmarkStar, 10, 10, window);
     },
     shouldAutoClose: true,
     isBookmarkRemoved: false,
   });
   */
 });
 
@@ -475,17 +476,17 @@ add_task(async function enter_during_aut
 
       Assert.equal(tagsField.value, "Abc",
         "Autocomplete should've inserted the selected item");
     },
     shouldAutoClose: false,
     popupHideFn() {
       EventUtils.synthesizeKey("KEY_Escape", {}, window);
     },
-    isBookmarkRemoved: false,
+    isBookmarkRemoved: true,
   });
 });
 
 add_task(async function escape_during_autocomplete_should_prevent_autoclose() {
   await test_bookmarks_popup({
     isNewBookmark: true,
     async popupShowFn(browser) {
       EventUtils.synthesizeKey("d", {accelKey: true}, window);
@@ -506,25 +507,28 @@ add_task(async function escape_during_au
       tagsField.focus();
       EventUtils.sendString("a", window);
       await promiseShown;
       ok(promiseShown, "autocomplete shown");
 
       // Select first candidate.
       EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
 
-      // Type Enter key to choose the item.
+      // Type Escape key to close autocomplete.
       EventUtils.synthesizeKey("KEY_Escape", {}, window);
 
-      Assert.equal(tagsField.value, "Abc",
-        "Autocomplete should've inserted the selected item and shouldn't clear it");
+      // The text reverts to what was typed.
+      // Note, it's important that this is different from the previously
+      // inserted tag, since it will test an untag/tag undo condition.
+      Assert.equal(tagsField.value, "a",
+        "Autocomplete should revert to what was typed");
     },
     shouldAutoClose: false,
     popupHideFn() {
       EventUtils.synthesizeKey("KEY_Escape", {}, window);
     },
-    isBookmarkRemoved: false,
+    isBookmarkRemoved: true,
   });
 });
 
 registerCleanupFunction(function() {
   delete StarUI._closePanelQuickForTesting;
 });
--- a/browser/base/content/titlebar-items.inc.xul
+++ b/browser/base/content/titlebar-items.inc.xul
@@ -1,11 +1,11 @@
 # 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/.
 
-<hbox class="titlebar-buttonbox-container titlebar-item">
+<hbox class="titlebar-buttonbox-container">
   <hbox class="titlebar-buttonbox titlebar-color">
     <toolbarbutton class="titlebar-button titlebar-min" oncommand="window.minimize();"/>
     <toolbarbutton class="titlebar-button titlebar-max" oncommand="onTitlebarMaxClick();"/>
     <toolbarbutton class="titlebar-button titlebar-close" command="cmd_closeWindow"/>
   </hbox>
 </hbox>
--- a/browser/components/aboutconfig/content/aboutconfig.css
+++ b/browser/components/aboutconfig/content/aboutconfig.css
@@ -27,17 +27,17 @@
   border-spacing: 0;
 }
 
 #prefs > tr:nth-child(odd) {
   background-color: var(--in-content-box-background-odd);
 }
 
 #prefs > tr:hover {
-  background-color: var(--in-content-box-background-hover);
+  background-color: var(--in-content-item-hover);
 }
 
 #prefs > tr.has-user-value {
   font-weight: bold;
 }
 
 #prefs > tr > td {
   padding: 4px;
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -162,18 +162,18 @@ CustomizeMode.prototype = {
       this.enter();
     }
   },
 
   _updateLWThemeButtonIcon() {
     let lwthemeButton = this.$("customization-lwtheme-button");
     let lwthemeIcon = this.document.getAnonymousElementByAttribute(lwthemeButton,
                         "class", "button-icon");
-    lwthemeIcon.style.backgroundImage = LightweightThemeManager.currentTheme ?
-      "url(" + LightweightThemeManager.currentTheme.iconURL + ")" : "";
+    let theme = LightweightThemeManager.currentTheme;
+    lwthemeIcon.style.backgroundImage = theme ? "url(" + theme.iconURL + ")" : "";
   },
 
   setTab(aTab) {
     if (gTab == aTab) {
       return;
     }
 
     if (gTab) {
@@ -339,16 +339,17 @@ CustomizeMode.prototype = {
         // Force layout reflow to ensure the animation runs,
         // and make it async so it doesn't affect the timing.
         this.visiblePalette.clientTop;
         this.visiblePalette.setAttribute("showing", "true");
       }, 0);
       this._updateEmptyPaletteNotice();
 
       this._updateLWThemeButtonIcon();
+      Services.obs.addObserver(this, "lightweight-theme-changed");
 
       this._setupDownloadAutoHideToggle();
 
       this._handler.isEnteringCustomizeMode = false;
 
       CustomizableUI.dispatchToolboxEvent("customizationready", {}, window);
 
       if (!this._wantToBeInCustomizeMode) {
@@ -381,16 +382,17 @@ CustomizeMode.prototype = {
                 "We'll exit after resetting has finished.");
       return;
     }
 
     this._handler.isExitingCustomizeMode = true;
 
     this._teardownDownloadAutoHideToggle();
 
+    Services.obs.removeObserver(this, "lightweight-theme-changed");
     CustomizableUI.removeListener(this);
 
     this.document.removeEventListener("keypress", this);
 
     let window = this.window;
     let document = this.document;
 
     this.togglePong(false);
@@ -1063,18 +1065,16 @@ CustomizeMode.prototype = {
     let btn = this.$("customization-reset-button");
     btn.disabled = true;
     return (async () => {
       await this.depopulatePalette();
       await this._unwrapToolbarItems();
 
       CustomizableUI.reset();
 
-      this._updateLWThemeButtonIcon();
-
       await this._wrapToolbarItems();
       this.populatePalette();
 
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._moveDownloadsButtonToNavBar = false;
       this.resetting = false;
@@ -1088,18 +1088,16 @@ CustomizeMode.prototype = {
     this.resetting = true;
 
     return (async () => {
       await this.depopulatePalette();
       await this._unwrapToolbarItems();
 
       CustomizableUI.undoReset();
 
-      this._updateLWThemeButtonIcon();
-
       await this._wrapToolbarItems();
       this.populatePalette();
 
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._moveDownloadsButtonToNavBar = false;
       this.resetting = false;
@@ -1323,18 +1321,19 @@ CustomizeMode.prototype = {
         aPreviewThemeEvent.target.theme : null);
     }
 
     function resetPreview() {
       LightweightThemeManager.resetPreview();
     }
 
     let onThemeSelected = panel => {
-      this._updateLWThemeButtonIcon();
-      this._onUIChange();
+      // This causes us to call _onUIChange when the LWT actually changes,
+      // so the restore defaults / undo reset button is updated correctly.
+      this._nextThemeChangeUserTriggered = true;
       panel.hidePopup();
     };
 
     let doc = this.window.document;
 
     function buildToolbarButton(aTheme) {
       let tbb = doc.createXULElement("toolbarbutton");
       tbb.theme = aTheme;
@@ -1563,16 +1562,23 @@ CustomizeMode.prototype = {
       case "nsPref:changed":
         this._updateResetButton();
         this._updateUndoResetButton();
         if (this._canDrawInTitlebar()) {
           this._updateTitlebarCheckbox();
           this._updateDragSpaceCheckbox();
         }
         break;
+      case "lightweight-theme-changed":
+        this._updateLWThemeButtonIcon();
+        if (this._nextThemeChangeUserTriggered) {
+          this._onUIChange();
+        }
+        this._nextThemeChangeUserTriggered = false;
+        break;
     }
   },
 
   _canDrawInTitlebar() {
     return this.window.TabsInTitlebar.systemSupported;
   },
 
   _updateTitlebarCheckbox() {
--- a/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
+++ b/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
@@ -9,18 +9,35 @@ const LIGHT_THEME_ID = "firefox-compact-
 const DARK_THEME_ID = "firefox-compact-dark@mozilla.org";
 const {LightweightThemeManager} = ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
 add_task(async function() {
   Services.prefs.clearUserPref("lightweightThemes.usedThemes");
   Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
 
   await startCustomizing();
+  // Check restore defaults button is disabled.
+  ok(document.getElementById("customization-reset-button").disabled,
+     "Reset button should start out disabled");
 
   let themesButton = document.getElementById("customization-lwtheme-button");
+  let themesButtonIcon = document.getAnonymousElementByAttribute(themesButton,
+      "class", "button-icon");
+  let iconURL = themesButtonIcon.style.backgroundImage;
+  // If we've run other tests before, we might have set the image to the
+  // default theme's icon explicitly, otherwise it might be empty, in which
+  // case the icon is determined by CSS (which will be the default
+  // theme's icon).
+  if (iconURL) {
+    ok((/default/i).test(themesButtonIcon.style.backgroundImage),
+       `Button should show default theme thumbnail - was: "${iconURL}"`);
+  } else {
+    is(iconURL, "",
+       `Button should show default theme thumbnail (empty string) - was: "${iconURL}"`);
+  }
   let popup = document.getElementById("customization-lwtheme-menu");
 
   let popupShownPromise = popupShown(popup);
   EventUtils.synthesizeMouseAtCenter(themesButton, {});
   info("Clicked on themes button");
   await popupShownPromise;
 
   // close current tab and re-open Customize menu to confirm correct number of Themes
@@ -45,16 +62,22 @@ add_task(async function() {
   is(header.nextElementSibling.nextElementSibling.nextElementSibling.theme.id, DARK_THEME_ID,
      "The third theme should be the dark theme");
 
   let themeChangedPromise = promiseObserverNotified("lightweight-theme-changed");
   header.nextElementSibling.nextElementSibling.doCommand(); // Select light theme
   info("Clicked on light theme");
   await themeChangedPromise;
 
+  // Check restore defaults button is enabled.
+  ok(!document.getElementById("customization-reset-button").disabled,
+     "Reset button should not be disabled anymore");
+  ok((/light/i).test(themesButtonIcon.style.backgroundImage),
+     `Button should show light theme thumbnail - was: "${themesButtonIcon.style.backgroundImage}"`);
+
   popupShownPromise = popupShown(popup);
   EventUtils.synthesizeMouseAtCenter(themesButton, {});
   info("Clicked on themes button a third time");
   await popupShownPromise;
 
   let activeThemes = popup.querySelectorAll("toolbarbutton.customization-lwtheme-menu-theme[active]");
   is(activeThemes.length, 1, "Exactly 1 theme should be selected");
   if (activeThemes.length > 0) {
--- a/browser/components/payments/content/paymentDialogWrapper.js
+++ b/browser/components/payments/content/paymentDialogWrapper.js
@@ -657,20 +657,22 @@ var paymentDialogWrapper = {
       stateChange: {},
     };
     try {
       let isTemporary = record.isTemporary;
       let collection = isTemporary ? this.temporaryStore[collectionName] :
                                      formAutofillStorage[collectionName];
 
       if (guid) {
-        // We only care to preserve old properties for credit cards,
-        // because credit cards don't get their full record sent to the
-        // unprivileged frame (the cc-number is excluded).
-        let preserveOldProperties = collectionName == "creditCards";
+        // We want to preserve old properties since the edit forms are often
+        // shown without all fields visible/enabled and we don't want those
+        // fields to be blanked upon saving. Examples of hidden/disabled fields:
+        // email, cc-number, mailing-address on the payer forms, and payer fields
+        // not requested in the payer form.
+        let preserveOldProperties = true;
         await collection.update(guid, record, preserveOldProperties);
       } else {
         responseMessage.guid = await collection.add(record);
       }
 
       if (isTemporary && collectionName == "addresses") {
         // there will be no formautofill-storage-changed event to update state
         // so add updated collection here
--- a/browser/components/payments/res/components/address-option.js
+++ b/browser/components/payments/res/components/address-option.js
@@ -26,16 +26,17 @@ import RichOption from "./rich-option.js
  * Attribute names follow FormAutofillStorage.jsm.
  */
 
 export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
   static get recordAttributes() {
     return [
       "address-level1",
       "address-level2",
+      "address-level3",
       "country",
       "email",
       "guid",
       "name",
       "organization",
       "postal-code",
       "street-address",
       "tel",
--- a/browser/components/payments/test/browser/browser.ini
+++ b/browser/components/payments/test/browser/browser.ini
@@ -5,16 +5,17 @@ prefs =
   dom.payments.request.enabled=true
   extensions.formautofill.creditCards.available=true
 skip-if = !e10s # Bug 1365964 - Payment Request isn't implemented for non-e10s
 support-files =
   blank_page.html
 
 [browser_address_edit.js]
 skip-if = verify && debug && os == 'mac'
+[browser_address_edit_hidden_fields.js]
 [browser_card_edit.js]
 skip-if = debug && (os == 'mac' || os == 'linux') # bug 1465673
 [browser_change_shipping.js]
 [browser_dropdowns.js]
 [browser_host_name.js]
 [browser_onboarding_wizard.js]
 [browser_openPreferences.js]
 [browser_payerRequestedFields.js]
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit.js
@@ -591,155 +591,16 @@ add_task(async function test_private_per
        "Check street-address in response");
     is(responseAddress.country, addressToAdd.country, "Check country in response");
   });
   // verify formautofill store doesnt have the new temp addresses
   is((await formAutofillStorage.addresses.getAll()).length, 1,
      "Original 1 stored address at end of test");
 });
 
-add_task(async function test_hiddenFieldNotSaved() {
-  await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let newAddress = Object.assign({}, PTU.Addresses.TimBL);
-    newAddress["given-name"] = "hiddenFields";
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    let options = {
-      expectPersist: true,
-      isEditing: false,
-    };
-    await navigateToAddAddressPage(frame);
-    info("navigated to add address page");
-    await fillInShippingAddressForm(frame, newAddress, options);
-    info("filled in TimBL address");
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "DE");
-    });
-    info("changed selected country to Germany");
-
-    await submitAddressForm(frame, null, options);
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(savedAddresses).length, 2, "2 saved addresses");
-      let savedAddress = Object.values(savedAddresses)
-                               .find(address => address["given-name"] == "hiddenFields");
-      ok(savedAddress, "found the saved address");
-      is(savedAddress.country, "DE", "check country");
-      is(savedAddress["address-level2"], PTU.Addresses.TimBL["address-level2"],
-         "check address-level2");
-      is(savedAddress["address-level1"], undefined, "address-level1 should not be saved");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_hiddenFieldRemovedWhenCountryChanged() {
-  await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let picker = content.document
-                     .querySelector("address-picker[selected-state-key='selectedShippingAddress']");
-      Cu.waiveXrays(picker).dropdown.popupBox.focus();
-      EventUtils.synthesizeKey(PTU.Addresses.TimBL["given-name"], {}, content.window);
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "DE");
-      info("changed selected country to Germany");
-    });
-
-    let options = {
-      isEditing: true,
-    };
-    await submitAddressForm(frame, null, options);
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(savedAddresses).length, 1, "1 saved address");
-      let savedAddress = Object.values(savedAddresses)[0];
-      is(savedAddress.country, "DE", "check country");
-      is(savedAddress["address-level2"], PTU.Addresses.TimBL["address-level2"],
-         "check address-level2");
-      is(savedAddress["address-level1"], undefined, "address-level1 should not be saved");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
 add_task(async function test_countrySpecificFieldsGetRequiredness() {
   await setup();
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
     let {win, frame} =
       await setupPaymentDialog(browser, {
copy from browser/components/payments/test/browser/browser_address_edit.js
copy to browser/components/payments/test/browser/browser_address_edit_hidden_fields.js
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit_hidden_fields.js
@@ -1,9 +1,11 @@
-/* eslint-disable no-shadow */
+/**
+ * Test saving/updating address records with fields sometimes not visible to the user.
+ */
 
 "use strict";
 
 async function setup() {
   await setupFormAutofillStorage();
   await cleanupFormAutofillStorage();
   // add an address and card to avoid the FTU sequence
   let prefilledGuids = await addSampleAddressesAndBasicCard(
@@ -12,594 +14,16 @@ async function setup() {
   info("associating the card with the billing address");
   await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
     billingAddressGUID: prefilledGuids.address1GUID,
   }, true);
 
   return prefilledGuids;
 }
 
-/*
- * Test that we can correctly add an address and elect for it to be saved or temporary
- */
-add_task(async function test_add_link() {
-  let prefilledGuids = await setup();
-
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    info("setup got prefilledGuids: " + JSON.stringify(prefilledGuids));
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-    });
-
-    let testOptions = [
-      { setPersistCheckedValue: true, expectPersist: true },
-      { setPersistCheckedValue: false, expectPersist: false },
-    ];
-    let newAddress = Object.assign({}, PTU.Addresses.TimBL2);
-    // Emails aren't part of shipping addresses
-    delete newAddress.email;
-
-    for (let options of testOptions) {
-      let shippingAddressChangePromise = ContentTask.spawn(browser, {
-        eventName: "shippingaddresschange",
-      }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-      await manuallyAddShippingAddress(frame, newAddress, options);
-      await shippingAddressChangePromise;
-      info("got shippingaddresschange event");
-
-      await spawnPaymentDialogTask(frame, async ({address, options, prefilledGuids}) => {
-        let {
-          PaymentTestUtils: PTU,
-        } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-        let newAddresses = await PTU.DialogContentUtils.waitForState(content, (state) => {
-          return state.tempAddresses && state.savedAddresses;
-        });
-        let colnName = options.expectPersist ? "savedAddresses" : "tempAddresses";
-        // remove any pre-filled entries
-        delete newAddresses[colnName][prefilledGuids.address1GUID];
-
-        let addressGUIDs = Object.keys(newAddresses[colnName]);
-        is(addressGUIDs.length, 1, "Check there is one address");
-        let resultAddress = newAddresses[colnName][addressGUIDs[0]];
-        for (let [key, val] of Object.entries(address)) {
-          is(resultAddress[key], val, "Check " + key);
-        }
-      }, {address: newAddress, options, prefilledGuids});
-    }
-
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_edit_link() {
-  let prefilledGuids = await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    let shippingAddressChangePromise = ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Jaws",
-      "family-name": "swaJ",
-      "organization": "aliizoM",
-    };
-
-    info("setup got prefilledGuids: " + JSON.stringify(prefilledGuids));
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-
-      let picker = content.document
-                     .querySelector("address-picker[selected-state-key='selectedShippingAddress']");
-      Cu.waiveXrays(picker).dropdown.popupBox.focus();
-      EventUtils.synthesizeKey(PTU.Addresses.TimBL["given-name"], {}, content.window);
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Edit Shipping Address", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Update", "Save button has the correct label");
-    });
-
-    let editOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      isEditing: true,
-      expectPersist: true,
-    };
-    await fillInShippingAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-    await verifyPersistCheckbox(frame, editOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        let addresses = Object.entries(state.savedAddresses);
-        return addresses.length == 1 &&
-               addresses[0][1]["given-name"] == address["given-name"];
-      }, "Check address was edited");
-
-      let addressGUIDs = Object.keys(state.savedAddresses);
-      is(addressGUIDs.length, 1, "Check there is still one address");
-      let savedAddress = state.savedAddresses[addressGUIDs[0]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val, "Check updated " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-
-      state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "payment-summary";
-      }, "Switched back to payment-summary");
-    }, EXPECTED_ADDRESS);
-
-    await shippingAddressChangePromise;
-    info("got shippingaddresschange event");
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-  await cleanupFormAutofillStorage();
-});
-
-add_task(async function test_add_payer_contact_name_email_link() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameAndEmail,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Deraj",
-      "family-name": "Niew",
-      "email": "test@example.com",
-    };
-
-    const addOptions = {
-      addLinkSelector: "address-picker.payer-related .add-link",
-      checkboxSelector: "#address-page .persist-checkbox",
-      initialPageId: "payment-summary",
-      expectPersist: true,
-    };
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {tempAddresses, savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-      is(Object.keys(tempAddresses).length, 0, "No temporary addresses at the start of test");
-      is(Object.keys(savedAddresses).length, 1, "1 saved address at the start of test");
-    });
-
-    await navigateToAddAddressPage(frame, addOptions);
-
-    await spawnPaymentDialogTask(frame, async () => {
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Add Payer Contact", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Next", "Save button has the correct label");
-
-      info("check that non-payer requested fields are hidden");
-      for (let selector of ["#organization", "#tel"]) {
-        let element = content.document.querySelector(selector);
-        ok(content.isHidden(element), selector + " should be hidden");
-      }
-    });
-
-    await fillInPayerAddressForm(frame, EXPECTED_ADDRESS, addOptions);
-    await verifyPersistCheckbox(frame, addOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, addOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let {savedAddresses} = await PTU.DialogContentUtils.getCurrentState(content);
-
-      let addressGUIDs = Object.keys(savedAddresses);
-      is(addressGUIDs.length, 2, "Check there are now 2 addresses");
-      let savedAddress = savedAddresses[addressGUIDs[1]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val, "Check " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, EXPECTED_ADDRESS);
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_edit_payer_contact_name_email_phone_link() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameEmailAndPhone,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    const EXPECTED_ADDRESS = {
-      "given-name": "Deraj",
-      "family-name": "Niew",
-      "email": "test@example.com",
-      "tel": "+15555551212",
-    };
-    const editOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      expectPersist: true,
-      isEditing: true,
-    };
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-
-      let editLink =
-        content.document.querySelector("address-picker.payer-related .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let title = content.document.querySelector("address-form h2");
-      is(title.textContent, "Edit Payer Contact", "Page title should be set");
-
-      let saveButton = content.document.querySelector("address-form .save-button");
-      is(saveButton.textContent, "Update", "Save button has the correct label");
-
-      info("check that non-payer requested fields are hidden");
-      let formElements =
-        content.document.querySelectorAll("address-form :-moz-any(input, select, textarea");
-      let allowedFields = ["given-name", "additional-name", "family-name", "email", "tel"];
-      for (let element of formElements) {
-        let shouldBeVisible = allowedFields.includes(element.id);
-        if (shouldBeVisible) {
-          ok(content.isVisible(element), element.id + " should be visible");
-        } else {
-          ok(content.isHidden(element), element.id + " should be hidden");
-        }
-      }
-
-      info("overwriting field values");
-      for (let [key, val] of Object.entries(address)) {
-        let field = content.document.getElementById(key);
-        field.value = val + "1";
-        ok(!field.disabled, `Field #${key} shouldn't be disabled`);
-      }
-    }, EXPECTED_ADDRESS);
-
-    await verifyPersistCheckbox(frame, editOptions);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, editOptions);
-
-    await spawnPaymentDialogTask(frame, async (address) => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        let addresses = Object.entries(state.savedAddresses);
-        return addresses.length == 1 &&
-               addresses[0][1]["given-name"] == address["given-name"] + "1";
-      }, "Check address was edited");
-
-      let addressGUIDs = Object.keys(state.savedAddresses);
-      is(addressGUIDs.length, 1, "Check there is still one address");
-      let savedAddress = state.savedAddresses[addressGUIDs[0]];
-      for (let [key, val] of Object.entries(address)) {
-        is(savedAddress[key], val + "1", "Check updated " + key);
-      }
-      ok(savedAddress.guid, "Address has a guid");
-      ok(savedAddress.name, "Address has a name");
-      ok(savedAddress.name.includes(address["given-name"]) &&
-         savedAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, EXPECTED_ADDRESS);
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_shipping_address_picker() {
-  await setup();
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await spawnPaymentDialogTask(frame, async function test_picker_option_label(address) {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-      ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-      let savedAddress = Object.values(state.savedAddresses)[0];
-
-      let selector = "address-picker[selected-state-key='selectedShippingAddress']";
-      let picker = content.document.querySelector(selector);
-      let option = Cu.waiveXrays(picker).dropdown.popupBox.children[0];
-      is(option.textContent,
-         FormAutofillUtils.getAddressLabel(savedAddress, null),
-         "Shows correct shipping option label");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-add_task(async function test_payer_address_picker() {
-  await BrowserTestUtils.withNewTab({
-    gBrowser,
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: PTU.Details.total60USD,
-        options: PTU.Options.requestPayerNameEmailAndPhone,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await spawnPaymentDialogTask(frame, async function test_picker_option_label(address) {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-      ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return Object.keys(state.savedAddresses).length == 1;
-      }, "One saved addresses when starting test");
-      let savedAddress = Object.values(state.savedAddresses)[0];
-
-      let selector = "address-picker[selected-state-key='selectedPayerAddress']";
-      let picker = content.document.querySelector(selector);
-      let option = Cu.waiveXrays(picker).dropdown.popupBox.children[0];
-      is(option.textContent.includes("32 Vassar Street"), false,
-         "Payer option label does not contain street address");
-      is(option.textContent,
-         FormAutofillUtils.getAddressLabel(savedAddress, "name tel email"),
-         "Shows correct payer option label");
-    });
-
-    info("clicking cancel");
-    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
-
-    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
-  });
-});
-
-/*
- * Test that we can correctly add an address from a private window
- */
-add_task(async function test_private_persist_addresses() {
-  if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
-    todo(false, "Cannot test OS key store login on official builds.");
-    return;
-  }
-  let prefilledGuids = await setup();
-
-  is((await formAutofillStorage.addresses.getAll()).length, 1,
-     "Setup results in 1 stored address at start of test");
-
-  await withNewTabInPrivateWindow({
-    url: BLANK_PAGE_URL,
-  }, async browser => {
-    info("in new tab w. private window");
-    let {frame} =
-      // setupPaymentDialog from a private window.
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-    info("/setupPaymentDialog");
-
-    let addressToAdd = Object.assign({}, PTU.Addresses.Temp);
-    // Emails aren't part of shipping addresses
-    delete addressToAdd.email;
-    const addOptions = {
-      checkboxSelector: "#address-page .persist-checkbox",
-      expectPersist: false,
-      isPrivate: true,
-    };
-
-    await navigateToAddAddressPage(frame);
-    await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.getCurrentState(content);
-      info("on address-page and state.isPrivate: " + state.isPrivate);
-      ok(state.isPrivate,
-         "isPrivate flag is set when paymentrequest is shown in a private session");
-    });
-
-    info("wait for initialAddresses");
-    let initialAddresses =
-      await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
-    is(initialAddresses.options.length, 1,
-       "Got expected number of pre-filled shipping addresses");
-
-    await fillInShippingAddressForm(frame, addressToAdd, addOptions);
-    await verifyPersistCheckbox(frame, addOptions);
-    await submitAddressForm(frame, addressToAdd, addOptions);
-
-    let shippingAddresses =
-      await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);
-    info("shippingAddresses", shippingAddresses);
-    let addressOptions = shippingAddresses.options;
-    // expect the prefilled address + the new temporary address
-    is(addressOptions.length, 2, "The picker has the expected number of address options");
-    let tempAddressOption = addressOptions.find(addr => addr.guid != prefilledGuids.address1GUID);
-    let tempAddressGuid = tempAddressOption.guid;
-    // select the new address
-    await spawnPaymentDialogTask(frame,
-                                 PTU.DialogContentTasks.selectShippingAddressByGuid,
-                                 tempAddressGuid);
-
-    info("awaiting the shippingaddresschange event");
-    await ContentTask.spawn(browser, {
-      eventName: "shippingaddresschange",
-    }, PTU.ContentTasks.awaitPaymentRequestEventPromise);
-
-    await spawnPaymentDialogTask(frame, async (args) => {
-      let {address, tempAddressGuid} = args;
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.selectedShippingAddress == tempAddressGuid;
-      }, "Check the temp address is the selectedShippingAddress");
-
-      let addressGUIDs = Object.keys(state.tempAddresses);
-      is(addressGUIDs.length, 1, "Check there is one address");
-
-      is(addressGUIDs[0], tempAddressGuid, "guid from state and picker options match");
-      let tempAddress = state.tempAddresses[tempAddressGuid];
-      for (let [key, val] of Object.entries(address)) {
-        is(tempAddress[key], val, "Check field " + key);
-      }
-      ok(tempAddress.guid, "Address has a guid");
-      ok(tempAddress.name, "Address has a name");
-      ok(tempAddress.name.includes(address["given-name"]) &&
-         tempAddress.name.includes(address["family-name"]), "Address.name was computed");
-    }, {address: addressToAdd, tempAddressGuid});
-
-    await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
-      securityCode: "123",
-    });
-
-    info("clicking pay");
-    await loginAndCompletePayment(frame);
-
-    // Add a handler to complete the payment above.
-    info("acknowledging the completion from the merchant page");
-    let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
-
-    // Verify response has the expected properties
-    info("response: " + JSON.stringify(result.response));
-    let responseAddress = result.response.shippingAddress;
-    ok(responseAddress, "response should contain the shippingAddress");
-    ok(responseAddress.recipient.includes(addressToAdd["given-name"]),
-       "Check given-name matches recipient in response");
-    ok(responseAddress.recipient.includes(addressToAdd["family-name"]),
-       "Check family-name matches recipient in response");
-    is(responseAddress.addressLine[0], addressToAdd["street-address"],
-       "Check street-address in response");
-    is(responseAddress.country, addressToAdd.country, "Check country in response");
-  });
-  // verify formautofill store doesnt have the new temp addresses
-  is((await formAutofillStorage.addresses.getAll()).length, 1,
-     "Original 1 stored address at end of test");
-});
 
 add_task(async function test_hiddenFieldNotSaved() {
   await setup();
 
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
@@ -730,85 +154,185 @@ add_task(async function test_hiddenField
     info("clicking cancel");
     spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
     await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
   });
   await cleanupFormAutofillStorage();
 });
 
-add_task(async function test_countrySpecificFieldsGetRequiredness() {
-  await setup();
+add_task(async function test_hiddenNonShippingFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: BLANK_PAGE_URL,
   }, async browser => {
-    let {win, frame} =
-      await setupPaymentDialog(browser, {
-        methodData: [PTU.MethodData.basicCard],
-        details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
-        options: PTU.Options.requestShippingOption,
-        merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
-      }
-    );
-
-    await navigateToAddAddressPage(frame);
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
+      options: PTU.Options.requestShippingOption,
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
 
-    const EXPECTED_ADDRESS = {
-      "country": "MO",
-      "given-name": "First",
-      "family-name": "Last",
-      "street-address": "12345 FooFoo Bar",
-    };
-    await fillInShippingAddressForm(frame, EXPECTED_ADDRESS);
-    await submitAddressForm(frame, EXPECTED_ADDRESS, {expectPersist: true});
+    await selectPaymentDialogShippingAddressByCountry(frame, "BR");
 
-    await navigateToAddAddressPage(frame);
-
-    await selectPaymentDialogShippingAddressByCountry(frame, "MO");
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] .edit-link",
+      initialPageId: "payment-summary",
+    });
 
     await spawnPaymentDialogTask(frame, async () => {
-      let {
-        PaymentTestUtils: PTU,
-      } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
-
-      let editLink = content.document.querySelector("address-picker .edit-link");
-      is(editLink.textContent, "Edit", "Edit link text");
-
-      editLink.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "address-page" && !!state["address-page"].guid;
-      }, "Check edit page state");
-
-      let provinceField = content.document.getElementById("address-level1");
-      let provinceContainer = provinceField.parentNode;
-      is(provinceContainer.style.display, "none", "Province should be hidden for Macau");
+      let givenNameField = content.document.querySelector(
+        "address-form #given-name"
+      );
+      await content.fillField(givenNameField, "Timothy-edit");
+    });
 
-      let countryField = content.document.getElementById("country");
-      await content.fillField(countryField, "CA");
-      info("changed selected country to Canada");
-
-      isnot(provinceContainer.style.display, "none", "Province should be visible for Canada");
-      ok(provinceContainer.hasAttribute("required"),
-         "Province container should have required attribute");
-      let provinceSpan = provinceContainer.querySelector("span");
-      is(provinceSpan.getAttribute("fieldRequiredSymbol"), "*",
-         "Province span should have asterisk as fieldRequiredSymbol");
-      is(content.window.getComputedStyle(provinceSpan, "::after").content,
-         "attr(fieldRequiredSymbol)",
-         "Asterisk should be on Province");
-
-      let addressBackButton = content.document.querySelector("address-form .back-button");
-      addressBackButton.click();
-
-      await PTU.DialogContentUtils.waitForState(content, (state) => {
-        return state.page.id == "payment-summary";
-      }, "Switched back to payment-summary");
-    });
+    let options = {
+      isEditing: true,
+    };
+    await submitAddressForm(frame, null, options);
 
     info("clicking cancel");
     spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
 
     await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
   });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    "given-name": "Timothy-edit",
+    "name": "Timothy-edit João Berners-Lee",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  isnot(actual.email, "", "Check email isn't empty");
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields");
+
   await cleanupFormAutofillStorage();
 });
+
+add_task(async function test_hiddenNonPayerFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.total2USD),
+      options: {
+        requestPayerEmail: true,
+      },
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
+
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: "address-picker[selected-state-key=\"selectedPayerAddress\"] .edit-link",
+      initialPageId: "payment-summary",
+    });
+
+    info("Change the email address");
+    await spawnPaymentDialogTask(frame, `async () => {
+      let emailField = content.document.querySelector("address-form #email");
+      await content.fillField(emailField, "new@example.com");
+    }`);
+
+    let options = {
+      isEditing: true,
+    };
+    await submitAddressForm(frame, null, options);
+
+    info("clicking cancel");
+    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
+
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    email: "new@example.com",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields and change was made");
+
+  await cleanupFormAutofillStorage();
+});
+
+add_task(async function test_hiddenNonBillingAddressFieldsPreservedUponEdit() {
+  await setupFormAutofillStorage();
+  await cleanupFormAutofillStorage();
+  // add a Brazilian address (since it uses all fields) and card to avoid the FTU sequence
+  let prefilledGuids = await addSampleAddressesAndBasicCard(
+    [PTU.Addresses.TimBR], [PTU.BasicCards.JohnDoe]);
+  let expected = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+
+  info("associating the card with the billing address");
+  await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
+    billingAddressGUID: prefilledGuids.address1GUID,
+  }, true);
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: BLANK_PAGE_URL,
+  }, async browser => {
+    let {win, frame} = await setupPaymentDialog(browser, {
+      methodData: [PTU.MethodData.basicCard],
+      details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total2USD),
+      options: PTU.Options.requestShippingOption,
+      merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
+    });
+
+    await navigateToAddCardPage(frame, {
+      addLinkSelector: "payment-method-picker .edit-link",
+    });
+
+    await navigateToAddAddressPage(frame, {
+      addLinkSelector: ".billingAddressRow .edit-link",
+      initialPageId: "basic-card-page",
+    });
+
+    await spawnPaymentDialogTask(frame, `async () => {
+      let givenNameField = content.document.querySelector(
+        "address-form #given-name"
+      );
+      await content.fillField(givenNameField, "Timothy-edit");
+    }`);
+
+    let options = {
+      isEditing: true,
+      nextPageId: "basic-card-page",
+    };
+    await submitAddressForm(frame, null, options);
+
+    info("clicking cancel");
+    spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
+
+    await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
+  });
+
+  Object.assign(expected, PTU.Addresses.TimBR, {
+    "given-name": "Timothy-edit",
+    "name": "Timothy-edit João Berners-Lee",
+  });
+  let actual = await formAutofillStorage.addresses.get(prefilledGuids.address1GUID);
+  // timeLastModified changes and isn't relevant
+  delete actual.timeLastModified;
+  delete expected.timeLastModified;
+  SimpleTest.isDeeply(actual, expected, "Check profile didn't lose fields");
+
+  await cleanupFormAutofillStorage();
+});
--- a/browser/components/payments/test/browser/head.js
+++ b/browser/components/payments/test/browser/head.js
@@ -543,31 +543,34 @@ async function verifyCardNetwork(frame, 
        "Should have one more than the number of supported networks");
     is(networkSelect.children[0].value, "",
        "The first option should be the blank/empty option");
     is(networkSelect.value, options.expectedNetwork,
        `The network picker should have the expected value`);
   }, {options: aOptions});
 }
 
-async function submitAddressForm(frame, aAddress, aOptions = {}) {
+async function submitAddressForm(frame, aAddress, aOptions = {
+  nextPageId: "payment-summary",
+}) {
   await spawnPaymentDialogTask(frame, async (args) => {
     let {options = {}} = args;
+    let nextPageId = options.nextPageId || "payment-summary";
     let {
       PaymentTestUtils,
     } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
 
     let oldAddresses = await PaymentTestUtils.DialogContentUtils.getCurrentState(content);
 
     // submit the form to return to summary page
     content.document.querySelector("address-form button:last-of-type").click();
 
     let currState = await PaymentTestUtils.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "payment-summary";
-    }, "submitAddressForm: Switched back to payment-summary");
+      return state.page.id == nextPageId;
+    }, `submitAddressForm: Switched back to ${nextPageId}`);
 
     let savedCount = Object.keys(currState.savedAddresses).length;
     let tempCount = Object.keys(currState.tempAddresses).length;
     let oldSavedCount = Object.keys(oldAddresses.savedAddresses).length;
     let oldTempCount = Object.keys(oldAddresses.tempAddresses).length;
 
     if (options.isEditing) {
       is(tempCount, oldTempCount, "tempAddresses count didn't change");
@@ -612,18 +615,18 @@ async function navigateToAddCardPage(fra
     }, "Check summary page state");
 
     // click through to add/edit card page
     let addLink = content.document.querySelector(options.addLinkSelector);
     addLink.click();
 
     // wait for card page
     await PaymentTestUtils.DialogContentUtils.waitForState(content, (state) => {
-      return state.page.id == "basic-card-page" && !state["basic-card-page"].guid;
-    }, "Check add page state");
+      return state.page.id == "basic-card-page";
+    }, "Check add/edit page state");
   }, aOptions);
 }
 
 async function fillInCardForm(frame, aCard, aOptions = {}) {
   await spawnPaymentDialogTask(frame, async (args) => {
     let {card, options = {}} = args;
 
     // fill the form
--- a/browser/components/payments/test/mochitest/test_address_form.html
+++ b/browser/components/payments/test/mochitest/test_address_form.html
@@ -169,16 +169,17 @@ add_task(async function test_saveButton(
     guid: undefined,
     messageType: "updateAutofillRecord",
     record: {
       "given-name": "Jaws",
       "family-name": "Swaj",
       "additional-name": "",
       "organization": "Allizom",
       "street-address": "404 Internet Super Highway",
+      "address-level3": "",
       "address-level2": "Firefoxity City",
       "address-level1": "CA",
       "postal-code": "00001",
       "country": "US",
       "tel": "+15555551212",
     },
   }, "Check event details for the message to chrome");
   form.remove();
@@ -770,12 +771,65 @@ add_task(async function test_field_valid
   postalCode.focus();
   sendString("12345", window);
   is(errorTextSpan.innerText, "", "DOM validation message should be removed when no error");
   postalCode.blur();
 
   form.remove();
 });
 
+add_task(async function test_hiddenMailingAddressFieldsCleared() {
+  let form = new AddressForm();
+  form.dataset.updateButtonLabel = "Update";
+  await form.promiseReady;
+  display.appendChild(form);
+  await asyncElementRendered();
+
+  let address1 = deepClone(PTU.Addresses.TimBL);
+  address1.guid = "9864798564";
+
+  await form.requestStore.setState({
+    page: {
+      id: "address-page",
+    },
+    "address-page": {
+      guid: address1.guid,
+      selectedStateKey: ["selectedShippingAddress"],
+    },
+    savedAddresses: {
+      [address1.guid]: deepClone(address1),
+    },
+  });
+  await asyncElementRendered();
+
+  info("Change the country to hide address-level1");
+  fillField(form.form.querySelector("#country"), "DE");
+
+  let expectedRecord = Object.assign({}, address1, {
+    country: "DE",
+    // address-level1 & 3 aren't used for Germany so should be blanked.
+    "address-level1": "",
+    "address-level3": "",
+  });
+  delete expectedRecord.guid;
+  // The following were not shown so shouldn't be part of the message:
+  delete expectedRecord.email;
+
+  let messagePromise = promiseContentToChromeMessage("updateAutofillRecord");
+  form.saveButton.scrollIntoView();
+  synthesizeMouseAtCenter(form.saveButton, {});
+
+  let details = await messagePromise;
+  delete details.messageID;
+  is(details.collectionName, "addresses", "Check collectionName");
+  isDeeply(details, {
+    collectionName: "addresses",
+    guid: address1.guid,
+    messageType: "updateAutofillRecord",
+    record: expectedRecord,
+  }, "Check update event details for the message to chrome");
+
+  form.remove();
+});
 </script>
 
 </body>
 </html>
--- a/browser/components/places/content/editBookmark.js
+++ b/browser/components/places/content/editBookmark.js
@@ -2,16 +2,19 @@
  * 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/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
 
 var gEditItemOverlay = {
+  // Array of PlacesTransactions accumulated by internal changes. It can be used
+  // to wait for completion.
+  transactionPromises: null,
   _observersAdded: false,
   _staticFoldersListBuilt: false,
 
   _paneInfo: null,
   _setPaneInfo(aInitInfo) {
     if (!aInitInfo)
       return this._paneInfo = null;
 
@@ -191,16 +194,18 @@ var gEditItemOverlay = {
       }
     }
 
     // For sanity ensure that the implementer has uninited the panel before
     // trying to init it again, or we could end up leaking due to observers.
     if (this.initialized)
       this.uninitPanel(false);
 
+    this.transactionPromises = [];
+
     let { parentGuid, isItem, isURI,
           isBookmark, bulkTagging, uris,
           visibleRows, focusedElement,
           onPanelReady } = this._setPaneInfo(aInfo);
 
     let showOrCollapse =
       (rowId, isAppropriateForInput, nameInHiddenRows = null) => {
         let visible = isAppropriateForInput;
@@ -459,16 +464,17 @@ var gEditItemOverlay = {
 
     if (this._folderMenuListListenerAdded) {
       this._folderMenuList.removeEventListener("select", this);
       this._folderMenuListListenerAdded = false;
     }
 
     this._setPaneInfo(null);
     this._firstEditedField = "";
+    this.transactionPromises = [];
   },
 
   get selectedFolderGuid() {
     return this._folderMenuList.selectedItem && this._folderMenuList.selectedItem.folderGuid;
   },
 
   onTagsFieldChange() {
     // Check for _paneInfo existing as the dialog may be closing but receiving
@@ -506,37 +512,48 @@ var gEditItemOverlay = {
     let removedTags = aCurrentTags.filter(t => !lcInputTags.includes(t.toLowerCase()));
     let newTags = inputTags.filter(t => !aCurrentTags.includes(t));
     return { removedTags, newTags };
   },
 
   // Adds and removes tags for one or more uris.
   _setTagsFromTagsInputField(aCurrentTags, aURIs) {
     let { removedTags, newTags } = this._getTagsChanges(aCurrentTags);
-    if (removedTags.length + newTags.length == 0)
+    if (removedTags.length + newTags.length == 0) {
       return false;
+    }
 
-    let setTags = async function() {
+    let setTags = async () => {
+      let promises = [];
       if (removedTags.length > 0) {
-        await PlacesTransactions.Untag({ urls: aURIs, tags: removedTags })
-                                .transact();
+        let promise = PlacesTransactions.Untag({ urls: aURIs, tags: removedTags })
+                                        .transact().catch(Cu.reportError);
+        this.transactionPromises.push(promise);
+        promises.push(promise);
       }
       if (newTags.length > 0) {
-        await PlacesTransactions.Tag({ urls: aURIs, tags: newTags })
-                                .transact();
+        let promise = PlacesTransactions.Tag({ urls: aURIs, tags: newTags })
+                                        .transact().catch(Cu.reportError);
+        this.transactionPromises.push(promise);
+        promises.push(promise);
+      }
+      // Don't use Promise.all because we want these to be executed in order.
+      for (let promise of promises) {
+        await promise;
       }
     };
 
     // Only in the library info-pane it's safe (and necessary) to batch these.
     // TODO bug 1093030: cleanup this mess when the bookmarksProperties dialog
     // and star UI code don't "run a batch in the background".
-    if (window.document.documentElement.id == "places")
-      PlacesTransactions.batch(setTags).catch(Cu.reportError);
-    else
-      setTags().catch(Cu.reportError);
+    if (window.document.documentElement.id == "places") {
+      PlacesTransactions.batch(setTags);
+    } else {
+      setTags();
+    }
     return true;
   },
 
   async _updateTags() {
     let uris = this._paneInfo.bulkTagging ?
                  this._paneInfo.uris : [this._paneInfo.uri];
     let currentTags = this._paneInfo.bulkTagging ?
                         await this._getCommonTags() :
@@ -592,23 +609,28 @@ var gEditItemOverlay = {
       // Get all the bookmarks for the old tag, tag them with the new tag, and
       // untag them from the old tag.
       let oldTag = this._paneInfo.tag;
       this._paneInfo.tag = tag;
       let title = this._paneInfo.title;
       if (title == oldTag) {
         this._paneInfo.title = tag;
       }
-      await PlacesTransactions.RenameTag({ oldTag, tag }).transact();
+      let promise = PlacesTransactions.RenameTag({ oldTag, tag }).transact();
+      this.transactionPromises.push(promise.catch(Cu.reportError));
+      await promise;
       return;
     }
 
     this._mayUpdateFirstEditField("namePicker");
-    await PlacesTransactions.EditTitle({ guid: this._paneInfo.itemGuid,
-                                         title: this._namePicker.value }).transact();
+    let promise = PlacesTransactions.EditTitle({ guid: this._paneInfo.itemGuid,
+                                                 title: this._namePicker.value })
+                                    .transact();
+    this.transactionPromises.push(promise.catch(Cu.reportError));
+    await promise;
   },
 
   onLocationFieldChange() {
     if (this.readOnly || !this._paneInfo.isBookmark)
       return;
 
     let newURI;
     try {
@@ -617,30 +639,30 @@ var gEditItemOverlay = {
       // TODO: Bug 1089141 - Provide some feedback about the invalid url.
       return;
     }
 
     if (this._paneInfo.uri.equals(newURI))
       return;
 
     let guid = this._paneInfo.itemGuid;
-    PlacesTransactions.EditUrl({ guid, url: newURI })
-                      .transact().catch(Cu.reportError);
+    this.transactionPromises.push(PlacesTransactions.EditUrl({ guid, url: newURI })
+                                                    .transact().catch(Cu.reportError));
   },
 
   onKeywordFieldChange() {
     if (this.readOnly || !this._paneInfo.isBookmark)
       return;
 
     let oldKeyword = this._keyword;
     let keyword = this._keyword = this._keywordField.value;
     let postData = this._paneInfo.postData;
     let guid = this._paneInfo.itemGuid;
-    PlacesTransactions.EditKeyword({ guid, keyword, postData, oldKeyword })
-                      .transact().catch(Cu.reportError);
+    this.transactionPromises.push(PlacesTransactions.EditKeyword({ guid, keyword, postData, oldKeyword })
+                                                    .transact().catch(Cu.reportError));
   },
 
   toggleFolderTreeVisibility() {
     var expander = this._element("foldersExpander");
     var folderTreeRow = this._element("folderTreeRow");
     expander.classList.toggle("expander-up", folderTreeRow.collapsed);
     expander.classList.toggle("expander-down", !folderTreeRow.collapsed);
     if (!folderTreeRow.collapsed) {
@@ -712,20 +734,22 @@ var gEditItemOverlay = {
       setTimeout(() => this.toggleFolderTreeVisibility(), 100);
       return;
     }
 
     // Move the item
     let containerGuid = this._folderMenuList.selectedItem.folderGuid;
     if (this._paneInfo.parentGuid != containerGuid &&
         this._paneInfo.itemGuid != containerGuid) {
-      await PlacesTransactions.Move({
+      let promise = PlacesTransactions.Move({
         guid: this._paneInfo.itemGuid,
         newParentGuid: containerGuid,
       }).transact();
+      this.transactionPromises.push(promise.catch(Cu.reportError));
+      await promise;
 
       // Auto-show the bookmarks toolbar when adding / moving an item there.
       if (containerGuid == PlacesUtils.bookmarks.toolbarGuid) {
         Services.obs.notifyObservers(null, "autoshow-bookmarks-toolbar");
       }
     }
 
     // Update folder-tree selection
@@ -844,21 +868,23 @@ var gEditItemOverlay = {
       ip = new PlacesInsertionPoint({
         parentId: PlacesUtils.bookmarksMenuFolderId,
         parentGuid: PlacesUtils.bookmarks.menuGuid,
       });
     }
 
     // XXXmano: add a separate "New Folder" string at some point...
     let title = this._element("newFolderButton").label;
-    let guid = await PlacesTransactions.NewFolder({
+    let promise = PlacesTransactions.NewFolder({
       parentGuid: ip.guid,
       title,
       index: await ip.getIndex(),
-    }).transact().catch(Cu.reportError);
+    }).transact();
+    this.transactionPromises.push(promise.catch(Cu.reportError));
+    let guid = await promise;
 
     this._folderTree.focus();
     this._folderTree.selectItems([ip.guid]);
     PlacesUtils.asContainer(this._folderTree.selectedNode).containerOpen = true;
     this._folderTree.selectItems([guid]);
     this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
                                   this._folderTree.columns.getFirstColumn());
   },
--- a/browser/components/places/content/editBookmarkPanel.inc.xul
+++ b/browser/components/places/content/editBookmarkPanel.inc.xul
@@ -89,16 +89,17 @@
              control="editBMPanel_tagsField"/>
       <hbox flex="1" align="center">
         <textbox id="editBMPanel_tagsField"
                  type="autocomplete"
                  flex="1"
                  autocompletesearch="places-tag-autocomplete"
                  autocompletepopup="PopupAutoComplete"
                  completedefaultindex="true"
+                 completeselectedindex="true"
                  tabscrolling="true"
                  placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"
                  onchange="gEditItemOverlay.onTagsFieldChange();"/>
         <button id="editBMPanel_tagsSelectorExpander"
                 class="expander-down panel-button"
                 tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                 tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                 tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
--- a/browser/components/search/searchplugins/hoepli.xml
+++ b/browser/components/search/searchplugins/hoepli.xml
@@ -3,15 +3,15 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Hoepli</ShortName>
 <Description>Dizionario della lingua italiana Hoepli</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/png;base64,
 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAEZJREFUeNpi/P//PwMpgAVCMSYehDD+z7dHlsYUZ2IgEQxCDSxofLgvB4+TcMUDLZ2kQKqGBxQ6iZHU1EqyDQAAAAD//wMApAcRQrj9oIAAAAAASUVORK5CYII=</Image>
-<Url type="text/html" method="GET" template="http://dizionari.hoepli.it/Dizionario_Italiano/cerca.aspx" resultdomain="hoepli.it">
+<Url type="text/html" method="GET" template="http://www.grandidizionari.it/Dizionario_Italiano/cerca.aspx" resultdomain="hoepli.it">
 	<Param name="idD" value="1" />
 	<Param name="utm_source" value="mozilla-firefox" />
 	<Param name="query" value="{searchTerms}" />
 </Url>
-<SearchForm>http://dizionari.hoepli.it/Dizionario_Italiano.aspx?idD=1</SearchForm>
-</SearchPlugin>
\ No newline at end of file
+<SearchForm>http://www.grandidizionari.it/Dizionario_Italiano.aspx</SearchForm>
+</SearchPlugin>
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -12,16 +12,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   QueryContext: "resource:///modules/UrlbarController.jsm",
   Services: "resource://gre/modules/Services.jsm",
   UrlbarController: "resource:///modules/UrlbarController.jsm",
   UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
   UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
   UrlbarValueFormatter: "resource:///modules/UrlbarValueFormatter.jsm",
   UrlbarView: "resource:///modules/UrlbarView.jsm",
+  ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "ClipboardHelper",
                                    "@mozilla.org/widget/clipboardhelper;1",
                                    "nsIClipboardHelper");
 
 /**
  * Represents the urlbar <textbox>.
@@ -267,53 +268,63 @@ class UrlbarInput {
     // BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
     //   event, this.userSelectionBehavior);
 
     let where = this._whereToOpen(event);
     let openParams = {
       postData: null,
       allowInheritPrincipal: false,
     };
-    let url = result.url;
 
     switch (result.type) {
       case UrlbarUtils.MATCH_TYPE.TAB_SWITCH: {
         // TODO: Implement handleRevert or equivalent on the input.
         // this.input.handleRevert();
-        let prevTab = this.browserWindow.gBrowser.selectedTab;
+        let prevTab = this.window.gBrowser.selectedTab;
         let loadOpts = {
           adoptIntoActiveWindow: UrlbarPrefs.get("switchTabs.adoptIntoActiveWindow"),
         };
 
-        if (this.browserWindow.switchToTabHavingURI(url, false, loadOpts) &&
+        if (this.window.switchToTabHavingURI(result.payload.url, false, loadOpts) &&
             prevTab.isEmpty) {
-          this.browserWindow.gBrowser.removeTab(prevTab);
+          this.window.gBrowser.removeTab(prevTab);
         }
         return;
 
         // TODO: How to handle meta chars?
         // Once we get here, we got a TAB_SWITCH match but the user
         // bypassed it by pressing shift/meta/ctrl. Those modifiers
         // might otherwise affect where we open - we always want to
         // open in the current tab.
         // where = "current";
-
       }
+      case UrlbarUtils.MATCH_TYPE.SEARCH:
+        // TODO: port _parseAndRecordSearchEngineLoad.
+        return;
+      case UrlbarUtils.MATCH_TYPE.OMNIBOX:
+        // Give the extension control of handling the command.
+        ExtensionSearchHandler.handleInputEntered(result.payload.keyword,
+                                                  result.payload.content,
+                                                  where);
+        return;
     }
 
-    this._loadURL(url, where, openParams);
+    this._loadURL(result.payload.url, where, openParams);
   }
 
   /**
    * Called by the view when moving through results with the keyboard.
    *
    * @param {UrlbarMatch} result The result that was selected.
    */
   setValueFromResult(result) {
-    let val = result.url;
+    // FIXME: This is wrong, not all the matches have a url. For example
+    // extension matches will call into the extension code rather than loading
+    // a url. That means we likely can't use the url as our value.
+    let val = result.payload.url;
     let uri;
     try {
       uri = Services.io.newURI(val);
     } catch (ex) {}
     if (uri) {
       val = this.window.losslessDecodeURI(uri);
     }
     this.value = val;
@@ -408,16 +419,18 @@ class UrlbarInput {
     if (!selectedVal.includes("/")) {
       let remainder = inputVal.replace(selectedVal, "");
       if (remainder != "" && remainder[0] != "/") {
         return selectedVal;
       }
     }
 
     // If the value was filled by a search suggestion, just return it.
+    // FIXME: This is wrong, the new system doesn't return action urls, it
+    // should instead build this based on MATCH_TYPE.
     let action = this._parseActionUrl(this.value);
     if (action && action.type == "searchengine") {
       return selectedVal;
     }
 
     let uri;
     if (this.getAttribute("pageproxystate") == "valid") {
       uri = this.window.gBrowser.currentURI;
@@ -506,22 +519,22 @@ class UrlbarInput {
    * @param {object} params.triggeringPrincipal
    *   The principal that the action was triggered from.
    * @param {nsIInputStream} [params.postData]
    *   The POST data associated with a search submission.
    * @param {boolean} [params.allowInheritPrincipal]
    *   If the principal may be inherited
    */
   _loadURL(url, openUILinkWhere, params) {
-    let browser = this.browserWindow.gBrowser.selectedBrowser;
+    let browser = this.window.gBrowser.selectedBrowser;
 
     // TODO: These should probably be set by the input field.
     // this.value = url;
     // browser.userTypedValue = url;
-    if (this.browserWindow.gInitialPages.includes(url)) {
+    if (this.window.gInitialPages.includes(url)) {
       browser.initialPageLoadedFromURLBar = url;
     }
     try {
       UrlbarUtils.addToUrlbarHistory(url);
     } catch (ex) {
       // Things may go wrong when adding url to session history,
       // but don't let that interfere with the loading of the url.
       Cu.reportError(ex);
@@ -530,31 +543,31 @@ class UrlbarInput {
     params.allowThirdPartyFixup = true;
 
     if (openUILinkWhere == "current") {
       params.targetBrowser = browser;
       params.indicateErrorPageLoad = true;
       params.allowPinnedTabHostChange = true;
       params.allowPopups = url.startsWith("javascript:");
     } else {
-      params.initiatingDoc = this.browserWindow.document;
+      params.initiatingDoc = this.window.document;
     }
 
     // Focus the content area before triggering loads, since if the load
     // occurs in a new tab, we want focus to be restored to the content
     // area when the current tab is re-selected.
     browser.focus();
 
     if (openUILinkWhere != "current") {
       // TODO: Implement handleRevert or equivalent on the input.
       // this.input.handleRevert();
     }
 
     try {
-      this.browserWindow.openTrustedLinkIn(url, openUILinkWhere, params);
+      this.window.openTrustedLinkIn(url, openUILinkWhere, params);
     } catch (ex) {
       // This load can throw an exception in certain cases, which means
       // we'll want to replace the URL with the loaded URL:
       if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
         // TODO: Implement handleRevert or equivalent on the input.
         // this.input.handleRevert();
       }
     }
@@ -578,29 +591,29 @@ class UrlbarInput {
       // We support using 'alt' to open in a tab, because ctrl/shift
       // might be used for canonizing URLs:
       where = event.shiftKey ? "tabshifted" : "tab";
     } else if (!isMouseEvent && this._ctrlCanonizesURLs && event && event.ctrlKey) {
       // If we're allowing canonization, and this is a key event with ctrl
       // pressed, open in current tab to allow ctrl-enter to canonize URL.
       where = "current";
     } else {
-      where = this.browserWindow.whereToOpenLink(event, false, false);
+      where = this.window.whereToOpenLink(event, false, false);
     }
     if (this.openInTab) {
       if (where == "current") {
         where = "tab";
       } else if (where == "tab") {
         where = "current";
       }
       reuseEmpty = true;
     }
     if (where == "tab" &&
         reuseEmpty &&
-        this.browserWindow.gBrowser.selectedTab.isEmpty) {
+        this.window.gBrowser.selectedTab.isEmpty) {
       where = "current";
     }
     return where;
   }
 
   // Event handlers below.
 
   _on_blur(event) {
--- a/browser/components/urlbar/UrlbarMatch.jsm
+++ b/browser/components/urlbar/UrlbarMatch.jsm
@@ -43,36 +43,40 @@ class UrlbarMatch {
     // multiple sources are involved, use the more privacy restricted.
     if (!Object.values(UrlbarUtils.MATCH_SOURCE).includes(matchSource)) {
       throw new Error("Invalid match source");
     }
     this.source = matchSource;
 
     // The payload contains match data. Some of the data is common across
     // multiple types, but most of it will vary.
-    if (!payload || (typeof payload != "object") || !payload.url) {
+    if (!payload || (typeof payload != "object")) {
       throw new Error("Invalid match payload");
     }
     this.payload = payload;
   }
 
   /**
-   * Returns a final destination for this match.
-   * Different kind of matches may have different ways to express this value,
-   * and this is a common getter for all of them.
-   * @returns {string} a url to load when this match is confirmed byt the user.
-   */
-  get url() {
-    switch (this.type) {
-      case UrlbarUtils.MATCH_TYPE.TAB_SWITCH:
-        return this.payload.url;
-    }
-    return "";
-  }
-
-  /**
    * Returns a title that could be used as a label for this match.
    * @returns {string} The label to show in a simplified title / url view.
    */
   get title() {
-    return "";
+    switch (this.type) {
+      case UrlbarUtils.MATCH_TYPE.TAB_SWITCH:
+      case UrlbarUtils.MATCH_TYPE.URL:
+      case UrlbarUtils.MATCH_TYPE.OMNIBOX:
+      case UrlbarUtils.MATCH_TYPE.REMOTE_TAB:
+        return this.payload.title || "";
+      case UrlbarUtils.MATCH_TYPE.SEARCH:
+        return this.payload.engine;
+      default:
+        return "";
+    }
+  }
+
+  /**
+   * Returns an icon url.
+   * @returns {string} url of the icon.
+   */
+  get icon() {
+    return this.payload.icon;
   }
 }
--- a/browser/components/urlbar/UrlbarProviderOpenTabs.jsm
+++ b/browser/components/urlbar/UrlbarProviderOpenTabs.jsm
@@ -81,22 +81,26 @@ class ProviderOpenTabs {
    * @returns {string} the name of this provider.
    */
   get name() {
     return "OpenTabs";
   }
 
   /**
    * Returns the type of this provider.
-   * @returns {integer} one of the types from UrlbarProvidersManager.TYPE.*
+   * @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
    */
   get type() {
     return UrlbarUtils.PROVIDER_TYPE.PROFILE;
   }
 
+  /**
+   * Returns the sources returned by this provider.
+   * @returns {array} one or multiple types from UrlbarUtils.MATCH_SOURCE.*
+   */
   get sources() {
     return [
       UrlbarUtils.MATCH_SOURCE.TABS,
     ];
   }
 
   /**
    * Registers a tab as open.
@@ -134,20 +138,21 @@ class ProviderOpenTabs {
   /**
    * Starts querying.
    * @param {object} queryContext The query context object
    * @param {function} addCallback Callback invoked by the provider to add a new
    *        match.
    * @returns {Promise} resolved when the query stops.
    */
   async startQuery(queryContext, addCallback) {
+    // Note: this is not actually expected to be used as an internal provider,
+    // because normal history search will already coalesce with the open tabs
+    // temp table to return proper frecency.
     // TODO:
     //  * properly search and handle tokens, this is just a mock for now.
-    //  * we won't search openTabs like this usually, the history search will
-    //  * coalesce the temp table with its data.
     logger.info(`Starting query for ${queryContext.searchString}`);
     let instance = {};
     this.queries.set(queryContext, instance);
     let conn = await this.promiseDb();
     await conn.executeCached(`
       SELECT url, userContextId
       FROM moz_openpages_temp
     `, {}, (row, cancel) => {
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/UrlbarProviderUnifiedComplete.jsm
@@ -0,0 +1,301 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * This module exports a provider that wraps the existing UnifiedComplete
+ * component, it is supposed to be used as an interim solution while we rewrite
+ * the model providers in a more modular way.
+ */
+
+var EXPORTED_SYMBOLS = ["UrlbarProviderUnifiedComplete"];
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+  Log: "resource://gre/modules/Log.jsm",
+  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
+  UrlbarMatch: "resource:///modules/UrlbarMatch.jsm",
+  UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
+  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
+});
+
+XPCOMUtils.defineLazyServiceGetter(this, "unifiedComplete",
+  "@mozilla.org/autocomplete/search;1?name=unifiedcomplete",
+  "nsIAutoCompleteSearch");
+
+XPCOMUtils.defineLazyGetter(this, "logger",
+  () => Log.repository.getLogger("Places.Urlbar.Provider.UnifiedComplete"));
+
+// See UnifiedComplete.
+const TITLE_TAGS_SEPARATOR = " \u2013 ";
+
+/**
+ * Class used to create the provider.
+ */
+class ProviderUnifiedComplete {
+  constructor() {
+    // Maps the running queries by queryContext.
+    this.queries = new Map();
+  }
+
+  /**
+   * Returns the name of this provider.
+   * @returns {string} the name of this provider.
+   */
+  get name() {
+    return "UnifiedComplete";
+  }
+
+  /**
+   * Returns the type of this provider.
+   * @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
+   */
+  get type() {
+    return UrlbarUtils.PROVIDER_TYPE.IMMEDIATE;
+  }
+
+  /**
+   * Returns the sources returned by this provider.
+   * @returns {array} one or multiple types from UrlbarUtils.MATCH_SOURCE.*
+   */
+  get sources() {
+    return [
+      UrlbarUtils.MATCH_SOURCE.TABS,
+    ];
+  }
+
+  /**
+   * Starts querying.
+   * @param {object} queryContext The query context object
+   * @param {function} addCallback Callback invoked by the provider to add a new
+   *        match.
+   * @returns {Promise} resolved when the query stops.
+   */
+  async startQuery(queryContext, addCallback) {
+    logger.info(`Starting query for ${queryContext.searchString}`);
+    let instance = {};
+    this.queries.set(queryContext, instance);
+
+    // Supported search params are:
+    //  * "enable-actions": default to true.
+    //  * "disable-private-actions": set for private windows, if not in permanent
+    //    private browsing mode. ()
+    //  * "private-window": the search is taking place in a private window.
+    //  * "user-context-id:#": the userContextId to use.
+    let params = ["enable-actions"];
+    if (queryContext.isPrivate) {
+      params.push("private-window");
+      if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
+        params.push("disable-private-actions");
+      }
+    }
+    if (queryContext.userContextId) {
+      params.push(`user-context-id:${queryContext.userContextId}}`);
+    }
+
+    let urls = new Set();
+    await new Promise(resolve => {
+      let listener = {
+        onSearchResult(_, result) {
+          let {done, matches} = convertResultToMatches(queryContext, result, urls);
+          for (let match of matches) {
+            addCallback(this, match);
+          }
+          if (done) {
+            resolve();
+          }
+        },
+      };
+      unifiedComplete.startSearch(queryContext.searchString,
+                                  params.join(" "),
+                                  null, // previousResult
+                                  listener);
+    });
+
+    // We are done.
+    this.queries.delete(queryContext);
+  }
+
+  /**
+   * Cancels a running query.
+   * @param {object} queryContext The query context object
+   */
+  cancelQuery(queryContext) {
+    logger.info(`Canceling query for ${queryContext.searchString}`);
+    // This doesn't properly support being used concurrently by multiple fields.
+    this.queries.delete(queryContext);
+    unifiedComplete.stopSearch();
+  }
+}
+
+var UrlbarProviderUnifiedComplete = new ProviderUnifiedComplete();
+
+/**
+ * Convert from a nsIAutocompleteResult to a list of new matches.
+ * Note that at every call we get the full set of matches, included the
+ * previously returned ones, and new matches may be inserted in the middle.
+ * This means we could sort these wrongly, the muxer should take care of it.
+ * In any case at least we're sure there's just one heuristic result and it
+ * comes first.
+ *
+ * @param {object} context the QueryContext
+ * @param {object} result an nsIAutocompleteResult
+ * @param {set} urls a Set containing all the found urls, used to discard
+ *        already added matches.
+ * @returns {object} { matches: {array}, done: {boolean} }
+ */
+function convertResultToMatches(context, result, urls) {
+  let matches = [];
+  let done = [
+    Ci.nsIAutoCompleteResult.RESULT_IGNORED,
+    Ci.nsIAutoCompleteResult.RESULT_FAILURE,
+    Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
+    Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
+  ].includes(result.searchResult) || result.errorDescription;
+
+  for (let i = 0; i < result.matchCount; ++i) {
+    // First, let's check if we already added this match.
+    // nsIAutocompleteResult always contains all of the matches, includes ones
+    // we may have added already. This means we'll end up adding things in the
+    // wrong order here, but that's a task for the UrlbarMuxer.
+    let url = result.getFinalCompleteValueAt(i);
+    if (urls.has(url)) {
+      continue;
+    }
+    urls.add(url);
+    // Not used yet: result.getValueAt(i), result.getLabelAt(i)
+    let style = result.getStyleAt(i);
+    let match = makeUrlbarMatch({
+      url,
+      icon: result.getImageAt(i),
+      style,
+      comment: result.getCommentAt(i),
+      firstToken: context.tokens[0],
+    });
+    // Should not happen, but better safe than sorry.
+    if (!match) {
+      continue;
+    }
+    matches.push(match);
+    // Manage autofill and preselected properties for the first match.
+    if (i == 0 && result.defaultIndex == 0) {
+      if (style.includes("autofill")) {
+        context.autofill = true;
+      }
+      if (style.includes("heuristic")) {
+        context.preselected = true;
+      }
+    }
+  }
+  return {matches, done};
+}
+
+/**
+ * Creates a new UrlbarMatch from the provided data.
+ * @param {object} info includes properties from the legacy match.
+ * @returns {object} an UrlbarMatch
+ */
+function makeUrlbarMatch(info) {
+  let action = PlacesUtils.parseActionUrl(info.url);
+  if (action) {
+    switch (action.type) {
+      case "searchengine":
+        return new UrlbarMatch(
+          UrlbarUtils.MATCH_TYPE.SEARCH,
+          UrlbarUtils.MATCH_SOURCE.SEARCH,
+          {
+            engine: action.params.engineName,
+            suggestion: action.params.searchSuggestion,
+            keyword: action.params.alias,
+            query: action.params.searchQuery,
+            icon: info.icon,
+          }
+        );
+      case "keyword":
+        return new UrlbarMatch(
+          UrlbarUtils.MATCH_TYPE.KEYWORD,
+          UrlbarUtils.MATCH_SOURCE.BOOKMARKS,
+          {
+            url: action.params.url,
+            keyword: info.firstToken,
+            postData: action.params.postData,
+            icon: info.icon,
+          }
+        );
+      case "extension":
+        return new UrlbarMatch(
+          UrlbarUtils.MATCH_TYPE.OMNIBOX,
+          UrlbarUtils.MATCH_SOURCE.OTHER_NETWORK,
+          {
+            title: info.comment,
+            content: action.params.content,
+            keyword: action.params.keyword,
+            icon: info.icon,
+          }
+        );
+      case "remotetab":
+        return new UrlbarMatch(
+          UrlbarUtils.MATCH_TYPE.REMOTE_TAB,
+          UrlbarUtils.MATCH_SOURCE.TABS,
+          {
+            url: action.params.url,
+            title: info.comment,
+            device: action.params.deviceName,
+            icon: info.icon,
+          }
+        );
+      case "visiturl":
+        return new UrlbarMatch(
+          UrlbarUtils.MATCH_TYPE.URL,
+          UrlbarUtils.MATCH_SOURCE.OTHER_LOCAL,
+          {
+            title: info.comment,
+            url: action.params.url,
+            icon: info.icon,
+          }
+        );
+      default:
+        Cu.reportError("Unexpected action type");
+        return null;
+    }
+  }
+
+  if (info.style.includes("priority-search")) {
+    return new UrlbarMatch(
+      UrlbarUtils.MATCH_TYPE.SEARCH,
+      UrlbarUtils.MATCH_SOURCE.SEARCH,
+      {
+        engine: info.comment,
+        icon: info.icon,
+      }
+    );
+  }
+
+  // This is a normal url/title tuple.
+  let source, tags, comment;
+  let hasTags = info.style.includes("tag");
+  if (info.style.includes("bookmark") || hasTags) {
+    source = UrlbarUtils.MATCH_SOURCE.BOOKMARKS;
+    if (info.style.includes("tag")) {
+      // Split title and tags.
+      [comment, tags] = info.comment.split(TITLE_TAGS_SEPARATOR);
+      tags = tags.split(",").map(t => t.trim());
+    }
+  } else if (info.style.includes("preloaded-top-sites")) {
+    source = UrlbarUtils.MATCH_SOURCE.OTHER_LOCAL;
+  } else {
+    source = UrlbarUtils.MATCH_SOURCE.HISTORY;
+  }
+  return new UrlbarMatch(
+    UrlbarUtils.MATCH_TYPE.URL,
+    source,
+    {
+      url: info.url,
+      icon: info.icon,
+      title: comment,
+      tags,
+    }
+  );
+}
--- a/browser/components/urlbar/UrlbarProvidersManager.jsm
+++ b/browser/components/urlbar/UrlbarProvidersManager.jsm
@@ -21,17 +21,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
 });
 
 XPCOMUtils.defineLazyGetter(this, "logger", () =>
   Log.repository.getLogger("Places.Urlbar.ProvidersManager"));
 
 // List of available local providers, each is implemented in its own jsm module
 // and will track different queries internally by queryContext.
 var localProviderModules = {
-  UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.jsm",
+  UrlbarProviderUnifiedComplete: "resource:///modules/UrlbarProviderUnifiedComplete.jsm",
 };
 
 // To improve dataflow and reduce UI work, when a match is added by a
 // non-immediate provider, we notify it to the controller after a delay, so
 // that we can chunk matches coming in that timeframe into a single call.
 const CHUNK_MATCHES_DELAY_MS = 16;
 
 /**
@@ -176,17 +176,17 @@ class Query {
     logger.debug(`Acceptable sources ${this.acceptableSources}`);
 
     let promises = [];
     for (let provider of this.providers.get(UrlbarUtils.PROVIDER_TYPE.IMMEDIATE).values()) {
       if (this.canceled) {
         break;
       }
       if (this._providerHasAcceptableSources(provider)) {
-        promises.push(provider.startQuery(this.context, this.add));
+        promises.push(provider.startQuery(this.context, this.add.bind(this)));
       }
     }
 
     // Tracks the delay timer. We will fire (in this specific case, cancel would
     // do the same, since the callback is empty) the timer when the search is
     // canceled, unblocking start().
     this._sleepTimer = new SkippableTimer(() => {}, UrlbarPrefs.get("delay"));
     await this._sleepTimer.promise;
@@ -249,17 +249,17 @@ class Query {
   add(provider, match) {
     // Stop returning results as soon as we've been canceled.
     if (this.canceled || !this.acceptableSources.includes(match.source)) {
       return;
     }
 
     // Filter out javascript results for safety. The provider is supposed to do
     // it, but we don't want to risk leaking these out.
-    if (match.url.startsWith("javascript:") &&
+    if (match.payload.url && match.payload.url.startsWith("javascript:") &&
         !this.context.searchString.startsWith("javascript:") &&
         UrlbarPrefs.get("filter.javascript")) {
       return;
     }
 
     this.context.results.push(match);
 
     let notifyResults = () => {
@@ -376,17 +376,17 @@ function getAcceptableMatchSources(conte
         break;
       case UrlbarUtils.MATCH_SOURCE.HISTORY:
         if (UrlbarPrefs.get("suggest.history") &&
             (!restrictTokenType ||
              restrictTokenType === UrlbarTokenizer.TYPE.RESTRICT_HISTORY)) {
           acceptedSources.push(source);
         }
         break;
-      case UrlbarUtils.MATCH_SOURCE.SEARCHENGINE:
+      case UrlbarUtils.MATCH_SOURCE.SEARCH:
         if (UrlbarPrefs.get("suggest.searches") &&
             (!restrictTokenType ||
              restrictTokenType === UrlbarTokenizer.TYPE.RESTRICT_SEARCH)) {
           acceptedSources.push(source);
         }
         break;
       case UrlbarUtils.MATCH_SOURCE.TABS:
         if (UrlbarPrefs.get("suggest.openpage") &&
--- a/browser/components/urlbar/UrlbarUtils.jsm
+++ b/browser/components/urlbar/UrlbarUtils.jsm
@@ -57,29 +57,44 @@ var UrlbarUtils = {
     // Can be delayed, contains results coming from the network.
     NETWORK: 3,
     // Can be delayed, contains results coming from unknown sources.
     EXTENSION: 4,
   },
 
   // Defines UrlbarMatch types.
   MATCH_TYPE: {
-    // Indicates an open tab.
-    // The payload is: { url, userContextId }
+    // An open tab.
+    // Payload: { icon, url, userContextId }
     TAB_SWITCH: 1,
+    // A search suggestion or engine.
+    // Payload: { icon, suggestion, keyword, query }
+    SEARCH: 2,
+    // A common url/title tuple, may be a bookmark with tags.
+    // Payload: { icon, url, title, tags }
+    URL: 3,
+    // A bookmark keyword.
+    // Payload: { icon, url, keyword, postData }
+    KEYWORD: 4,
+    // A WebExtension Omnibox match.
+    // Payload: { icon, keyword, title, content }
+    OMNIBOX: 5,
+    // A tab from another synced device.
+    // Payload: { url, icon, device, title }
+    REMOTE_TAB: 6,
   },
 
   // This defines the source of matches returned by a provider. Each provider
   // can return matches from more than one source. This is used by the
   // ProvidersManager to decide which providers must be queried and which
   // matches can be returned.
   MATCH_SOURCE: {
     BOOKMARKS: 1,
     HISTORY: 2,
-    SEARCHENGINE: 3,
+    SEARCH: 3,
     TABS: 4,
     OTHER_LOCAL: 5,
     OTHER_NETWORK: 6,
   },
 
   /**
    * Adds a url to history as long as it isn't in a private browsing window,
    * and it is valid.
--- a/browser/components/urlbar/UrlbarView.jsm
+++ b/browser/components/urlbar/UrlbarView.jsm
@@ -141,27 +141,27 @@ class UrlbarView {
     content.appendChild(actionIcon);
 
     let favicon = this._createElement("span");
     favicon.className = "urlbarView-favicon";
     content.appendChild(favicon);
 
     let title = this._createElement("span");
     title.className = "urlbarView-title";
-    title.textContent = result.title || result.url;
+    title.textContent = result.title || result.payload.url;
     content.appendChild(title);
 
     let secondary = this._createElement("span");
     secondary.className = "urlbarView-secondary";
     if (result.type == UrlbarUtils.MATCH_TYPE.TAB_SWITCH) {
       secondary.classList.add("urlbarView-action");
       secondary.textContent = "Switch to Tab";
     } else {
       secondary.classList.add("urlbarView-url");
-      secondary.textContent = result.url;
+      secondary.textContent = result.payload.url;
     }
     content.appendChild(secondary);
 
     this._rows.appendChild(item);
   }
 
   /**
    * Passes DOM events for the view to the _on_<event type> methods.
--- a/browser/components/urlbar/moz.build
+++ b/browser/components/urlbar/moz.build
@@ -7,16 +7,17 @@ with Files("**"):
 
 EXTRA_JS_MODULES += [
     'UrlbarController.jsm',
     'UrlbarInput.jsm',
     'UrlbarMatch.jsm',
     'UrlbarPrefs.jsm',
     'UrlbarProviderOpenTabs.jsm',
     'UrlbarProvidersManager.jsm',
+    'UrlbarProviderUnifiedComplete.jsm',
     'UrlbarTokenizer.jsm',
     'UrlbarUtils.jsm',
     'UrlbarValueFormatter.jsm',
     'UrlbarView.jsm',
 ]
 
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
--- a/browser/components/urlbar/tests/unit/test_providerOpenTabs.js
+++ b/browser/components/urlbar/tests/unit/test_providerOpenTabs.js
@@ -16,17 +16,17 @@ add_task(async function test_openTabs() 
 
   let context = createContext();
   let matchCount = 0;
   let callback = function(provider, match) {
     matchCount++;
     Assert.equal(provider, UrlbarProviderOpenTabs, "Got the expected provider");
     Assert.equal(match.type, UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
                  "Got the expected match type");
-    Assert.equal(match.url, url, "Got the expected url");
+    Assert.equal(match.payload.url, url, "Got the expected url");
     Assert.equal(match.title, "", "Got the expected title");
   };
 
   await UrlbarProviderOpenTabs.startQuery(context, callback);
   Assert.equal(matchCount, 1, "Found the expected number of matches");
   // Sanity check that this doesn't throw.
   UrlbarProviderOpenTabs.cancelQuery(context);
   Assert.equal(UrlbarProviderOpenTabs.queries.size, 0,
--- a/browser/docs/AddressBar.rst
+++ b/browser/docs/AddressBar.rst
@@ -64,16 +64,18 @@ It is augmented as it progresses through
                 // View and the Controller can do additional filtering.
     isPrivate; // {boolean} Whether the search started in a private context.
     userContextId; // {integer} The user context ID (containers feature).
 
     // Properties added by the Model.
     tokens; // {array} tokens extracted from the searchString, each token is an
             // object in the form {type, value}.
     results; // {array} list of UrlbarMatch objects.
+    preselected; // {boolean} whether the first match should be preselected.
+    autofill; // {boolean} whether the first match is an autofill match.
   }
 
 
 The Model
 =========
 
 The *Model* is the component responsible for retrieving search results based on
 the user's input, and sorting them accordingly to their importance.
@@ -295,23 +297,40 @@ properties, supported by all of the matc
   Match types are also enumerated by *UrlbarUtils.MATCH_TYPE*.
 
 .. highlight:: JavaScript
 .. code::
 
   UrlbarMatch {
     constructor(matchType, payload);
 
-    // Common properties:
     type: {integer} One of UrlbarUtils.MATCH_TYPE.
     source: {integer} One of UrlbarUtils.MATCH_SOURCE.
-    url: {string} The url pointed by this match.
     title: {string} A title that may be used as a label for this match.
+    icon: {string} Url of an icon for this match.
+    payload: {object} Object containing properties for the specific MATCH_TYPE.
   }
 
+The following MATCH_TYPEs are supported:
+
+.. highlight:: JavaScript
+.. code::
+
+    // Payload: { icon, url, userContextId }
+    TAB_SWITCH: 1,
+    // Payload: { icon, suggestion, keyword, query }
+    SEARCH: 2,
+    // Payload: { icon, url, title, tags }
+    URL: 3,
+    // Payload: { icon, url, keyword, postData }
+    KEYWORD: 4,
+    // Payload: { icon, keyword, title, content }
+    OMNIBOX: 5,
+    // Payload: { icon, url, device, title }
+    REMOTE_TAB: 6,
 
 Shared Modules
 ==============
 
 Various modules provide shared utilities to the other components:
 
 `UrlbarPrefs.jsm <https://dxr.mozilla.org/mozilla-central/source/browser/components/urlbar/UrlbarPrefs.jsm>`_
 ----------------
--- a/browser/extensions/formautofill/content/autofillEditForms.js
+++ b/browser/extensions/formautofill/content/autofillEditForms.js
@@ -43,26 +43,39 @@ class EditAutofillForm {
 
   setDefaultSelectedOptionByValue(select, value) {
     for (let option of select.options) {
       option.defaultSelected = option.value == value;
     }
   }
 
   /**
-   * Get inputs from the form.
+   * Get a record from the form suitable for a save/update in storage.
    * @returns {object}
    */
   buildFormObject() {
+    let initialObject = {};
+    if (this.hasMailingAddressFields) {
+      // Start with an empty string for each mailing-address field so that any
+      // fields hidden for the current country are blanked in the return value.
+      initialObject = {
+        "street-address": "",
+        "address-level3": "",
+        "address-level2": "",
+        "address-level1": "",
+        "postal-code": "",
+      };
+    }
+
     return Array.from(this._elements.form.elements).reduce((obj, input) => {
       if (!input.disabled) {
         obj[input.id] = input.value;
       }
       return obj;
-    }, {});
+    }, initialObject);
   }
 
   /**
    * Handle events
    *
    * @param  {DOMEvent} event
    */
   handleEvent(event) {
@@ -153,16 +166,21 @@ class EditAddress extends EditAutofillFo
       record = {
         country: this.DEFAULT_REGION,
       };
     }
     super.loadRecord(record);
     this.formatForm(record.country);
   }
 
+  get hasMailingAddressFields() {
+    let {addressFields} = this._elements.form.dataset;
+    return !addressFields || addressFields.trim().split(/\s+/).includes("mailing-address");
+  }
+
   /**
    * `mailing-address` is a special attribute token to indicate mailing fields + country.
    *
    * @param {object[]} mailingFieldsOrder - `fieldsOrder` from `getFormFormat`
    * @param {string} addressFields - white-space-separated string of requested address fields to show
    * @returns {object[]} in the same structure as `mailingFieldsOrder` but including non-mail fields
    */
   static computeVisibleFields(mailingFieldsOrder, addressFields) {
@@ -234,17 +252,21 @@ class EditAddress extends EditAutofillFo
 
   /**
    * Update address field visibility and order based on libaddressinput data.
    *
    * @param {object[]} fieldsOrder array of objects with `fieldId` and optional `newLine` properties
    * @param {Set} requiredFields Set of `fieldId` strings that mark which fields are required
    */
   arrangeFields(fieldsOrder, requiredFields) {
+    /**
+     * @see FormAutofillStorage.VALID_ADDRESS_FIELDS
+     */
     let fields = [
+      // `name` is a wrapper for the 3 name fields.
       "name",
       "organization",
       "street-address",
       "address-level3",
       "address-level2",
       "address-level1",
       "postal-code",
       "country",
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -954,17 +954,17 @@ notification[value="translation"] {
   transform: perspective(0.01px);
 }
 
 /* End customization mode */
 
 /* Prevent titlebar items (window caption buttons, private browsing indicator,
  * accessibility indicator, etc) from overlapping the nav bar's shadow on the
  * tab bar. */
-#TabsToolbar > .titlebar-item {
+#TabsToolbar > .titlebar-buttonbox-container {
   margin-bottom: @navbarTabsShadowSize@;
 }
 
 :root:not([privatebrowsingmode=temporary]) .accessibility-indicator,
 .private-browsing-indicator {
   margin-inline-end: 12px;
 }
 
--- a/devtools/client/accessibility/accessibility-startup.js
+++ b/devtools/client/accessibility/accessibility-startup.js
@@ -69,17 +69,17 @@ class AccessibilityStartup {
   initAccessibility() {
     if (!this._initAccessibility) {
       this._initAccessibility = (async function() {
         await Promise.race([
           this.toolbox.isOpen,
           this.toolbox.once("accessibility-init"),
         ]);
 
-        this._accessibility = this.target.getFront("accessibility");
+        this._accessibility = await this.target.getFront("accessibility");
         // When target is being destroyed (for example on remoteness change), it
         // destroy accessibility front. In case when a11y is not fully initialized, that
         // may result in unresolved promises.
         const prepared = await Promise.race([
           this.prepareAccessibility(),
           this.target.once("close"), // does not have a value.
         ]);
         // If the target is being destroyed, no need to continue.
--- a/devtools/client/definitions.js
+++ b/devtools/client/definitions.js
@@ -564,17 +564,17 @@ exports.ToolboxButtons = [
     async onClick(event, toolbox) {
       // Special case for screenshot button to check for clipboard preference
       const clipboardEnabled = Services.prefs
         .getBoolPref("devtools.screenshot.clipboard.enabled");
       const args = { fullpage: true, file: true };
       if (clipboardEnabled) {
         args.clipboard = true;
       }
-      const screenshotFront = toolbox.target.getFront("screenshot");
+      const screenshotFront = await toolbox.target.getFront("screenshot");
       await screenshotFront.captureAndSave(toolbox.win, args);
     },
   },
   createHighlightButton("RulersHighlighter", "rulers"),
   createHighlightButton("MeasuringToolHighlighter", "measure"),
 ];
 
 function createHighlightButton(highlighterName, id) {
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -772,17 +772,18 @@ Target.prototype = {
     if (this._destroyer) {
       return this._destroyer;
     }
 
     this._destroyer = (async () => {
       // Before taking any action, notify listeners that destruction is imminent.
       this.emit("close");
 
-      for (const [, front] of this.fronts) {
+      for (let [, front] of this.fronts) {
+        front = await front;
         await front.destroy();
       }
 
       if (this._tab) {
         this._teardownListeners();
       }
 
       this._teardownRemoteListeners();
--- a/devtools/client/framework/test/browser_target_listeners.js
+++ b/devtools/client/framework/test/browser_target_listeners.js
@@ -7,17 +7,17 @@ add_task(async function() {
 
   const target = await TargetFactory.forTab(gBrowser.selectedTab);
   await target.attach();
 
   info("Test applying onFront to a front that will be created");
   const promise = new Promise(resolve => {
     target.onFront("accessibility", resolve);
   });
-  const getFrontFront = target.getFront("accessibility");
+  const getFrontFront = await target.getFront("accessibility");
   const onFrontFront = await promise;
   is(getFrontFront, onFrontFront, "got the front instantiated in the future and it's the same");
 
   info("Test applying onFront to an existing front");
   await new Promise(resolve => {
     target.onFront("accessibility", front => {
       is(front, getFrontFront, "got the already instantiated front and it's the same");
       resolve();
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -3041,17 +3041,17 @@ Toolbox.prototype = {
       return this._performanceFrontConnection;
     }
 
     let resolvePerformance;
     this._performanceFrontConnection = new Promise(function(resolve) {
       resolvePerformance = resolve;
     });
 
-    this._performance = this.target.getFront("performance");
+    this._performance = await this.target.getFront("performance");
     await this.performance.connect();
 
     // Emit an event when connected, but don't wait on startup for this.
     this.emit("profiler-connected");
 
     this.performance.on("*", this._onPerformanceFrontEvent);
     resolvePerformance(this.performance);
     return this._performanceFrontConnection;
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -94,20 +94,18 @@ class AnimationInspector {
       setDetailVisibility,
       setHighlightedNode,
       setSelectedNode,
       simulateAnimation,
       simulateAnimationForKeyframesProgressBar,
       toggleElementPicker,
     } = this;
 
-    const target = this.inspector.target;
     const direction = this.win.document.dir;
-    this.animationsFront = target.getFront("animations");
-    this.animationsFront.setWalkerActor(this.inspector.walker);
+    this._getAnimationsFront();
 
     this.animationsCurrentTimeListeners = [];
     this.isCurrentTimeSet = false;
 
     const provider = createElement(Provider,
       {
         id: "animationinspector",
         key: "animationinspector",
@@ -143,27 +141,42 @@ class AnimationInspector {
     this.provider = provider;
 
     this.inspector.sidebar.on("select", this.onSidebarSelectionChanged);
     this.inspector.toolbox.on("picker-started", this.onElementPickerStarted);
     this.inspector.toolbox.on("picker-stopped", this.onElementPickerStopped);
     this.inspector.toolbox.on("select", this.onSidebarSelectionChanged);
   }
 
+  _getAnimationsFront() {
+    if (this.animationsFrontPromise) {
+      return this.animationsFrontPromise;
+    }
+    this.animationsFrontPromise = new Promise(async resolve => {
+      const target = this.inspector.target;
+      const front = await target.getFront("animations");
+      front.setWalkerActor(this.inspector.walker);
+      resolve(front);
+    });
+    return this.animationsFrontPromise;
+  }
+
   destroy() {
     this.setAnimationStateChangedListenerEnabled(false);
     this.inspector.off("new-root", this.onNavigate);
     this.inspector.selection.off("new-node-front", this.update);
     this.inspector.sidebar.off("select", this.onSidebarSelectionChanged);
     this.inspector.toolbox.off("inspector-sidebar-resized", this.onSidebarResized);
     this.inspector.toolbox.off("picker-started", this.onElementPickerStarted);
     this.inspector.toolbox.off("picker-stopped", this.onElementPickerStopped);
     this.inspector.toolbox.off("select", this.onSidebarSelectionChanged);
 
-    this.animationsFront.off("mutations", this.onAnimationsMutation);
+    this.animationsFrontPromise.then(front => {
+      front.off("mutations", this.onAnimationsMutation);
+    });
 
     if (this.simulatedAnimation) {
       this.simulatedAnimation.cancel();
       this.simulatedAnimation = null;
     }
 
     if (this.simulatedElement) {
       this.simulatedElement.remove();
@@ -192,17 +205,18 @@ class AnimationInspector {
   /**
    * This function calls AnimationsFront.setCurrentTimes with considering the createdTime.
    *
    * @param {Number} currentTime
    */
   async doSetCurrentTimes(currentTime) {
     const { animations, timeScale } = this.state;
     currentTime = currentTime + timeScale.minStartTime;
-    await this.animationsFront.setCurrentTimes(animations, currentTime, true,
+    const animationsFront = await this.animationsFrontPromise;
+    await animationsFront.setCurrentTimes(animations, currentTime, true,
                                                { relativeToCreatedTime: true });
   }
 
   /**
    * Return a map of animated property from given animation actor.
    *
    * @param {Object} animation
    * @return {Map} A map of animated property
@@ -364,26 +378,27 @@ class AnimationInspector {
     if (this.wasPanelVisibled === isPanelVisibled) {
       // onSidebarSelectionChanged is called some times even same state
       // from sidebar and toolbar.
       return;
     }
 
     this.wasPanelVisibled = isPanelVisibled;
 
+    const animationsFront = await this.animationsFrontPromise;
     if (this.isPanelVisible()) {
       await this.update();
       this.onSidebarResized(null, this.inspector.getSidebarSize());
-      this.animationsFront.on("mutations", this.onAnimationsMutation);
+      animationsFront.on("mutations", this.onAnimationsMutation);
       this.inspector.on("new-root", this.onNavigate);
       this.inspector.selection.on("new-node-front", this.update);
       this.inspector.toolbox.on("inspector-sidebar-resized", this.onSidebarResized);
     } else {
       this.stopAnimationsCurrentTimeTimer();
-      this.animationsFront.off("mutations", this.onAnimationsMutation);
+      animationsFront.off("mutations", this.onAnimationsMutation);
       this.inspector.off("new-root", this.onNavigate);
       this.inspector.selection.off("new-node-front", this.update);
       this.inspector.toolbox.off("inspector-sidebar-resized", this.onSidebarResized);
       this.setAnimationStateChangedListenerEnabled(false);
     }
   }
 
   onSidebarResized(size) {
@@ -444,17 +459,18 @@ class AnimationInspector {
   async setAnimationsPlaybackRate(playbackRate) {
     let animations = this.state.animations;
     // "changed" event on each animation will fire respectively when the playback
     // rate changed. Since for each occurrence of event, change of UI is urged.
     // To avoid this, disable the listeners once in order to not capture the event.
     this.setAnimationStateChangedListenerEnabled(false);
 
     try {
-      await this.animationsFront.setPlaybackRates(animations, playbackRate);
+      const animationsFront = await this.animationsFrontPromise;
+      await animationsFront.setPlaybackRates(animations, playbackRate);
       animations = await this.updateAnimations(animations);
     } catch (e) {
       // Expected if we've already been destroyed or other node have been selected
       // in the meantime.
       console.error(e);
       return;
     } finally {
       this.setAnimationStateChangedListenerEnabled(true);
@@ -475,26 +491,27 @@ class AnimationInspector {
       if (doPlay && animations.every(animation =>
                       timeScale.getEndTime(animation) <= animation.state.currentTime)) {
         await this.doSetCurrentTimes(timeScale.zeroPositionTime);
       }
 
       // If the server does not support pauseSome/playSome function, (which happens
       // when connected to server older than FF62), use pauseAll/playAll instead.
       // See bug 1456857.
+      const animationsFront = await this.animationsFrontPromise;
       if (this.hasPausePlaySome) {
         if (doPlay) {
-          await this.animationsFront.playSome(animations);
+          await animationsFront.playSome(animations);
         } else {
-          await this.animationsFront.pauseSome(animations);
+          await animationsFront.pauseSome(animations);
         }
       } else if (doPlay) {
-        await this.animationsFront.playAll();
+        await animationsFront.playAll();
       } else {
-        await this.animationsFront.pauseAll();
+        await animationsFront.pauseAll();
       }
 
       animations = await this.updateAnimations(animations);
     } catch (e) {
       // Expected if we've already been destroyed or other node have been selected
       // in the meantime.
       console.error(e);
       return;
@@ -633,19 +650,20 @@ class AnimationInspector {
   toggleElementPicker() {
     this.inspector.toolbox.highlighterUtils.togglePicker();
   }
 
   async update() {
     const done = this.inspector.updating("animationinspector");
 
     const selection = this.inspector.selection;
+    const animationsFront = await this.animationsFrontPromise;
     const animations =
       selection.isConnected() && selection.isElementNode()
-      ? await this.animationsFront.getAnimationPlayersForNode(selection.nodeFront)
+      ? await animationsFront.getAnimationPlayersForNode(selection.nodeFront)
       : [];
     this.updateState(animations);
     this.setAnimationStateChangedListenerEnabled(true);
 
     done();
   }
 
   async updateAnimations(animations) {
--- a/devtools/client/inspector/changes/ChangesView.js
+++ b/devtools/client/inspector/changes/ChangesView.js
@@ -20,70 +20,89 @@ class ChangesView {
   constructor(inspector, window) {
     this.document = window.document;
     this.inspector = inspector;
     this.store = this.inspector.store;
     this.toolbox = this.inspector.toolbox;
 
     this.onAddChange = this.onAddChange.bind(this);
     this.onClearChanges = this.onClearChanges.bind(this);
+    this.onChangesFront = this.onChangesFront.bind(this);
     this.destroy = this.destroy.bind(this);
 
-    // Get the Changes front, and listen to it.
-    this.changesFront = this.toolbox.target.getFront("changes");
-    this.changesFront.on("add-change", this.onAddChange);
-    this.changesFront.on("clear-changes", this.onClearChanges);
-
     this.init();
   }
 
   init() {
     const changesApp = ChangesApp({});
 
+    // listen to the front for initialization, add listeners
+    // when it is ready
+    this._getChangesFront();
+
     // Expose the provider to let inspector.js use it in setupSidebar.
     this.provider = createElement(Provider, {
       id: "changesview",
       key: "changesview",
       store: this.store,
     }, changesApp);
 
     this.inspector.target.on("will-navigate", this.onClearChanges);
+  }
 
-    // Get all changes collected up to this point by the ChangesActor on the server,
-    // then push them to the Redux store here on the client.
-    this.changesFront.allChanges()
-      .then(changes => {
-        changes.forEach(change => {
-          this.onAddChange(change);
-        });
-      })
-      .catch(err => {
-        // The connection to the server may have been cut, for example during test
-        // teardown. Here we just catch the error and silently ignore it.
+  _getChangesFront() {
+    if (this.changesFrontPromise) {
+      return this.changesFrontPromise;
+    }
+    this.changesFrontPromise = new Promise(async resolve => {
+      const target = this.inspector.target;
+      const front = target.getFront("changes");
+      this.onChangesFront(front);
+      resolve(front);
+    });
+    return this.changesFrontPromise;
+  }
+
+  async onChangesFront(changesFront) {
+    changesFront.on("add-change", this.onAddChange);
+    changesFront.on("clear-changes", this.onClearChanges);
+    try {
+      // Get all changes collected up to this point by the ChangesActor on the server,
+      // then push them to the Redux store here on the client.
+      const changes = await changesFront.allChanges();
+      changes.forEach(change => {
+        this.onAddChange(change);
       });
+    } catch (e) {
+      // The connection to the server may have been cut, for
+      // example during test
+      // teardown. Here we just catch the error and silently
+      // ignore it.
+    }
   }
 
   onAddChange(change) {
     // Turn data into a suitable change to send to the store.
     this.store.dispatch(trackChange(change));
   }
 
   onClearChanges() {
     this.store.dispatch(resetChanges());
   }
 
   /**
    * Destruction function called when the inspector is destroyed.
    */
-  destroy() {
+  async destroy() {
     this.store.dispatch(resetChanges());
 
-    this.changesFront.off("add-change", this.onAddChange);
-    this.changesFront.off("clear-changes", this.onClearChanges);
-    this.changesFront = null;
+    // ensure we finish waiting for the front before destroying.
+    const changesFront = await this.changesFrontPromise;
+    changesFront.off("add-change", this.onAddChange);
+    changesFront.off("clear-changes", this.onClearChanges);
 
     this.document = null;
     this.inspector = null;
     this.store = null;
     this.toolbox = null;
   }
 }
 
--- a/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js
+++ b/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js
@@ -102,17 +102,18 @@ add_task(async function testSidebarSetOb
   assertTreeView(sidebarPanelContent, {
     expectedTreeTables: 1,
     expectedStringCells: 0,
     expectedNumberCells: 1,
   });
 });
 
 add_task(async function testSidebarSetObjectValueGrip() {
-  const inspectedWindowFront = toolbox.target.getFront("webExtensionInspectedWindow");
+  const inspectedWindowFront =
+    await toolbox.target.getFront("webExtensionInspectedWindow");
   const sidebar = inspector.getPanel(SIDEBAR_ID);
   const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
 
   info("Testing sidebar.setObjectValueGrip with rootTitle");
 
   const expression = `
     var obj = Object.create(null);
     obj.prop1 = 123;
@@ -144,17 +145,18 @@ add_task(async function testSidebarSetOb
     nodesLength: 4,
     propertiesNames: ["cyclic", "prop1", "Symbol(sym1)"],
   });
 
   inspectedWindowFront.destroy();
 });
 
 add_task(async function testSidebarDOMNodeHighlighting() {
-  const inspectedWindowFront = toolbox.target.getFront("webExtensionInspectedWindow");
+  const inspectedWindowFront =
+    await toolbox.target.getFront("webExtensionInspectedWindow");
   const sidebar = inspector.getPanel(SIDEBAR_ID);
   const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
 
   const expression = "({ body: document.body })";
 
   const evalResult = await inspectedWindowFront.eval(fakeExtCallerInfo, expression, {
     evalResultAsGrip: true,
     toolboxConsoleActorID: toolbox.target.form.consoleActor,
@@ -224,17 +226,18 @@ add_task(async function testSidebarDOMNo
   is(nodeFront.displayName, "body", "The correct node has been selected");
   nodeFront = await onNodeHighlight;
   is(nodeFront.displayName, "body", "The correct node was highlighted");
 
   await onNodeUnhighlight;
 });
 
 add_task(async function testSidebarSetExtensionPage() {
-  const inspectedWindowFront = toolbox.target.getFront("webExtensionInspectedWindow");
+  const inspectedWindowFront =
+    await toolbox.target.getFront("webExtensionInspectedWindow");
 
   const sidebar = inspector.getPanel(SIDEBAR_ID);
   const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
 
   info("Testing sidebar.setExtensionPage");
 
   const expectedURL = "data:text/html,<!DOCTYPE html><html><body><h1>Extension Page";
 
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -160,16 +160,17 @@ Inspector.prototype = {
   async init() {
     // Localize all the nodes containing a data-localization attribute.
     localizeMarkup(this.panelDoc);
 
     await Promise.all([
       this._getCssProperties(),
       this._getPageStyle(),
       this._getDefaultSelection(),
+      this._getAccessibilityFront(),
     ]);
 
     return this._deferredOpen();
   },
 
   get toolbox() {
     return this._toolbox;
   },
@@ -267,17 +268,17 @@ Inspector.prototype = {
     if (this._defaultNode) {
       this.selection.setNodeFront(this._defaultNode, { reason: "inspector-open" });
     }
 
     if (Services.prefs.getBoolPref(TRACK_CHANGES_PREF)) {
       // Get the Changes front, then call a method on it, which will instantiate
       // the ChangesActor. We want the ChangesActor to be guaranteed available before
       // the user makes any changes.
-      this.changesFront = this.toolbox.target.getFront("changes");
+      this.changesFront = await this.toolbox.target.getFront("changes");
       this.changesFront.start();
     }
 
     // Setup the splitter before the sidebar is displayed so, we don't miss any events.
     this.setupSplitter();
 
     // We can display right panel with: tab bar, markup view and breadbrumb. Right after
     // the splitter set the right and left panel sizes, in order to avoid resizing it
@@ -331,16 +332,21 @@ Inspector.prototype = {
   },
 
   _getCssProperties: function() {
     return initCssProperties(this.toolbox).then(cssProperties => {
       this._cssProperties = cssProperties;
     }, this._handleRejectionIfNotDestroyed);
   },
 
+  _getAccessibilityFront: async function() {
+    this.accessibilityFront = await this.target.getFront("accessibility");
+    return this.accessibilityFront;
+  },
+
   _getDefaultSelection: function() {
     // This may throw if the document is still loading and we are
     // refering to a dead about:blank document
     return this._getDefaultNodeForSelection().catch(this._handleRejectionIfNotDestroyed);
   },
 
   _getPageStyle: function() {
     return this.inspector.getPageStyle().then(pageStyle => {
@@ -1675,20 +1681,19 @@ Inspector.prototype = {
     }
 
     const showA11YPropsItem = new MenuItem({
       id: "node-menu-showaccessibilityproperties",
       label: INSPECTOR_L10N.getStr("inspectorShowAccessibilityProperties.label"),
       click: () => this.showAccessibilityProperties(),
       disabled: true,
     });
-    // Only attempt to determine if a11y props menu item needs to be enabled iff
+    // Only attempt to determine if a11y props menu item needs to be enabled if
     // AccessibilityFront is enabled.
-    const accessibilityFront = this.target.getFront("accessibility");
-    if (accessibilityFront.enabled) {
+    if (this.accessibilityFront.enabled) {
       this._updateA11YMenuItem(showA11YPropsItem);
     }
 
     menu.append(showA11YPropsItem);
   },
 
   _updateA11YMenuItem: async function(menuItem) {
     const hasMethod = await this.target.actorHasMethod("domwalker",
@@ -2292,17 +2297,17 @@ Inspector.prototype = {
 
     const clipboardEnabled = Services.prefs
       .getBoolPref("devtools.screenshot.clipboard.enabled");
     const args = {
       file: true,
       nodeActorID: this.selection.nodeFront.actorID,
       clipboard: clipboardEnabled,
     };
-    const screenshotFront = this.target.getFront("screenshot");
+    const screenshotFront = await this.target.getFront("screenshot");
     const screenshot = await screenshotFront.capture(args);
     await saveScreenshot(this.panelWin, args, screenshot);
   },
 
   /**
    * Scroll the node into view.
    */
   scrollNodeIntoView: function() {
--- a/devtools/client/inspector/shared/reflow-tracker.js
+++ b/devtools/client/inspector/shared/reflow-tracker.js
@@ -30,20 +30,20 @@ ReflowTracker.prototype = {
       this.stopTracking();
       this.reflowFront.destroy();
       this.reflowFront = null;
     }
 
     this.listeners.clear();
   },
 
-  startTracking() {
+  async startTracking() {
     // Initialize reflow front if necessary.
     if (!this.reflowFront && this.target.form.reflowActor) {
-      this.reflowFront = this.target.getFront("reflow");
+      this.reflowFront = await this.target.getFront("reflow");
     }
 
     if (this.reflowFront) {
       this.reflowFront.on("reflows", this.onReflow);
       this.reflowFront.start();
     }
   },
 
--- a/devtools/client/memory/panel.js
+++ b/devtools/client/memory/panel.js
@@ -25,17 +25,17 @@ function MemoryPanel(iframeWindow, toolb
 MemoryPanel.prototype = {
   async open() {
     if (this._opening) {
       return this._opening;
     }
 
     this.panelWin.gToolbox = this._toolbox;
     this.panelWin.gTarget = this.target;
-    this.panelWin.gFront = this.target.getFront("memory");
+    this.panelWin.gFront = await this.target.getFront("memory");
     this.panelWin.gHeapAnalysesClient = new HeapAnalysesClient();
 
     await this.panelWin.gFront.attach();
 
     this._opening = this.initializer.initialize().then(() => {
       this.isReady = true;
       this.emit("ready");
       return this;
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -70,17 +70,17 @@ class FirefoxConnector {
     // these are used to pause/resume the connector.
     // Paused network panel should be automatically resumed when page
     // reload, so `will-navigate` listener needs to be there all the time.
     if (this.tabTarget) {
       this.tabTarget.on("will-navigate", this.willNavigate);
       this.tabTarget.on("navigate", this.navigate);
 
       // Initialize Emulation front for network throttling.
-      this.emulationFront = this.tabTarget.getFront("emulation");
+      this.emulationFront = await this.tabTarget.getFront("emulation");
     }
 
     // Displaying cache events is only intended for the UI panel.
     if (this.actions) {
       this.displayCachedEvents();
     }
   }
 
--- a/devtools/client/shadereditor/panel.js
+++ b/devtools/client/shadereditor/panel.js
@@ -28,17 +28,17 @@ ShaderEditorPanel.prototype = {
 
   /**
    * Open is effectively an asynchronous constructor.
    *
    * @return object
    *         A promise that is resolved when the Shader Editor completes opening.
    */
   async open() {
-    this.front = this.target.getFront("webgl");
+    this.front = await this.target.getFront("webgl");
     this.shadersListView = new ShadersListView();
     this.eventsHandler = new EventsHandler();
     this.shadersEditorsView = new ShadersEditorsView();
     await this.shadersListView.initialize(this._toolbox, this.shadersEditorsView);
     await this.eventsHandler.initialize(this, this._toolbox, this.target, this.front,
                                         this.shadersListView);
     await this.shadersEditorsView.initialize(this, this.shadersListView);
 
--- a/devtools/client/shadereditor/test/head.js
+++ b/devtools/client/shadereditor/test/head.js
@@ -148,17 +148,17 @@ function initBackend(aUrl) {
   DebuggerServer.registerAllActors();
 
   return (async function() {
     const tab = await addTab(aUrl);
     const target = await TargetFactory.forTab(tab);
 
     await target.attach();
 
-    const front = target.getFront("webgl");
+    const front = await target.getFront("webgl");
     return { target, front };
   })();
 }
 
 function initShaderEditor(aUrl) {
   info("Initializing a shader editor pane.");
 
   return (async function() {
--- a/devtools/client/styleeditor/StyleEditorUI.jsm
+++ b/devtools/client/styleeditor/StyleEditorUI.jsm
@@ -648,17 +648,17 @@ StyleEditorUI.prototype = {
             await showEditor.load(inputElement, this._cssProperties);
           }
 
           showEditor.onShow();
 
           this.emit("editor-selected", showEditor);
 
           // Is there any CSS coverage markup to include?
-          const usage = this._target.getFront("cssUsage");
+          const usage = await this._target.getFront("cssUsage");
           if (usage == null) {
             return;
           }
 
           const sheet = showEditor.styleSheet;
           const {reports} = await usage.createEditorReportForSheet(sheet);
 
           showEditor.removeAllUnusedRegions();
--- a/devtools/server/actors/highlighters/flexbox.js
+++ b/devtools/server/actors/highlighters/flexbox.js
@@ -17,19 +17,19 @@ const {
   updateCanvasPosition,
 } = require("./utils/canvas");
 const {
   CanvasFrameAnonymousContentHelper,
   createNode,
   getComputedStyle,
 } = require("./utils/markup");
 const {
-  getAdjustedQuads,
   getCurrentZoom,
   getDisplayPixelRatio,
+  getUntransformedQuad,
   getWindowDimensions,
   setIgnoreLayoutChanges,
 } = require("devtools/shared/layout/utils");
 
 const FLEXBOX_LINES_PROPERTIES = {
   "edge": {
     lineDash: [5, 3],
   },
@@ -303,28 +303,28 @@ class FlexboxHighlighter extends AutoRef
 
     if (!this.computedStyle) {
       this.computedStyle = getComputedStyle(this.currentNode);
     }
 
     const flex = this.currentNode.getAsFlexContainer();
 
     const oldCrossAxisDirection = this.crossAxisDirection;
-    this.crossAxisDirection = flex.crossAxisDirection;
+    this.crossAxisDirection = flex ? flex.crossAxisDirection : null;
     const newCrossAxisDirection = this.crossAxisDirection;
 
     const oldMainAxisDirection = this.mainAxisDirection;
-    this.mainAxisDirection = flex.mainAxisDirection;
+    this.mainAxisDirection = flex ? flex.mainAxisDirection : null;
     const newMainAxisDirection = this.mainAxisDirection;
 
     // Concatenate the axes to simplify conditionals.
     this.axes = `${this.mainAxisDirection} ${this.crossAxisDirection}`;
 
     const oldFlexData = this.flexData;
-    this.flexData = getFlexData(flex, this.win);
+    this.flexData = getFlexData(this.currentNode);
     const hasFlexDataChanged = compareFlexData(oldFlexData, this.flexData);
 
     const oldAlignItems = this.alignItemsValue;
     this.alignItemsValue = this.computedStyle.alignItems;
     const newAlignItems = this.alignItemsValue;
 
     const oldFlexDirection = this.flexDirection;
     this.flexDirection = this.computedStyle.flexDirection;
@@ -523,26 +523,27 @@ class FlexboxHighlighter extends AutoRef
     }
 
     const { devicePixelRatio } = this.win;
     const lineWidth = getDisplayPixelRatio(this.win);
     const offset = (lineWidth / 2) % 1;
     const zoom = getCurrentZoom(this.win);
     const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
     const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
+    const containerQuad = getUntransformedQuad(this.currentNode, "content");
+    const { width, height } = containerQuad.getBounds();
 
     this.ctx.save();
     this.ctx.translate(offset - canvasX, offset - canvasY);
     this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash);
     this.ctx.lineWidth = lineWidth * 2;
     this.ctx.strokeStyle = this.color;
     this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio);
 
-    const { clientWidth, clientHeight } = this.currentNode;
-    drawRect(this.ctx, 0, 0, clientWidth, clientHeight, this.currentMatrix);
+    drawRect(this.ctx, 0, 0, width, height, this.currentMatrix);
 
     // Find current angle of outer flex element by measuring the angle of two arbitrary
     // points, then rotate canvas, so the hash pattern stays 45deg to the boundary.
     const p1 = apply(this.currentMatrix, [0, 0]);
     const p2 = apply(this.currentMatrix, [1, 0]);
     const angleRad = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
     this.ctx.rotate(angleRad);
 
@@ -557,36 +558,26 @@ class FlexboxHighlighter extends AutoRef
     }
 
     const { devicePixelRatio } = this.win;
     const lineWidth = getDisplayPixelRatio(this.win);
     const offset = (lineWidth / 2) % 1;
     const zoom = getCurrentZoom(this.win);
     const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
     const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
-    const containerOffsets = getNodeRect(this.currentNode);
 
     this.ctx.save();
     this.ctx.translate(offset - canvasX, offset - canvasY);
     this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.item.lineDash);
     this.ctx.lineWidth = lineWidth;
     this.ctx.strokeStyle = this.color;
 
     for (const flexLine of this.flexData.lines) {
       for (const flexItem of flexLine.items) {
-        const offsets = getNodeRect(flexItem.node);
-
-        if (!offsets) {
-          continue;
-        }
-
-        const left = offsets.left - containerOffsets.left;
-        const top = offsets.top - containerOffsets.top;
-        const right = offsets.right - containerOffsets.left;
-        const bottom = offsets.bottom - containerOffsets.top;
+        const { left, top, right, bottom } = flexItem.rect;
 
         clearRect(this.ctx, left, top, right, bottom, this.currentMatrix);
         drawRect(this.ctx, left, top, right, bottom, this.currentMatrix);
         this.ctx.stroke();
       }
     }
 
     this.ctx.restore();
@@ -598,82 +589,83 @@ class FlexboxHighlighter extends AutoRef
     }
 
     const { devicePixelRatio } = this.win;
     const lineWidth = getDisplayPixelRatio(this.win);
     const offset = (lineWidth / 2) % 1;
     const zoom = getCurrentZoom(this.win);
     const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
     const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
-    const { clientWidth, clientHeight } = this.currentNode;
+    const containerQuad = getUntransformedQuad(this.currentNode, "content");
+    const { width, height } = containerQuad.getBounds();
     const options = { matrix: this.currentMatrix };
 
     this.ctx.save();
     this.ctx.translate(offset - canvasX, offset - canvasY);
     this.ctx.lineWidth = lineWidth;
     this.ctx.strokeStyle = this.color;
 
     for (const flexLine of this.flexData.lines) {
       const { crossStart, crossSize } = flexLine;
 
       switch (this.axes) {
         case "horizontal-lr vertical-tb":
         case "horizontal-lr vertical-bt":
         case "horizontal-rl vertical-tb":
         case "horizontal-rl vertical-bt":
-          clearRect(this.ctx, 0, crossStart, clientWidth, crossStart + crossSize,
+          clearRect(this.ctx, 0, crossStart, width, crossStart + crossSize,
             this.currentMatrix);
 
           // Avoid drawing the start flex line when they overlap with the flex container.
           if (crossStart != 0) {
-            drawLine(this.ctx, 0, crossStart, clientWidth, crossStart, options);
+            drawLine(this.ctx, 0, crossStart, width, crossStart, options);
             this.ctx.stroke();
           }
 
           // Avoid drawing the end flex line when they overlap with the flex container.
-          if (clientHeight - crossStart - crossSize >= lineWidth) {
-            drawLine(this.ctx, 0, crossStart + crossSize, clientWidth,
+          if (crossStart + crossSize < height - lineWidth * 2) {
+            drawLine(this.ctx, 0, crossStart + crossSize, width,
               crossStart + crossSize, options);
             this.ctx.stroke();
           }
           break;
         case "vertical-tb horizontal-lr":
         case "vertical-bt horizontal-rl":
-          clearRect(this.ctx, crossStart, 0, crossStart + crossSize, clientHeight,
+          clearRect(this.ctx, crossStart, 0, crossStart + crossSize, height,
             this.currentMatrix);
 
           // Avoid drawing the start flex line when they overlap with the flex container.
           if (crossStart != 0) {
-            drawLine(this.ctx, crossStart, 0, crossStart, clientHeight, options);
+            drawLine(this.ctx, crossStart, 0, crossStart, height, options);
             this.ctx.stroke();
           }
 
           // Avoid drawing the end flex line when they overlap with the flex container.
-          if (clientWidth - crossStart - crossSize >= lineWidth) {
+          if (crossStart + crossSize < width - lineWidth * 2) {
             drawLine(this.ctx, crossStart + crossSize, 0, crossStart + crossSize,
-              clientHeight, options);
+              height, options);
             this.ctx.stroke();
           }
           break;
         case "vertical-bt horizontal-lr":
         case "vertical-tb horizontal-rl":
-          clearRect(this.ctx, clientWidth - crossStart, 0,
-            clientWidth - crossStart - crossSize, clientHeight, this.currentMatrix);
+          clearRect(this.ctx, width - crossStart, 0, width - crossStart - crossSize,
+            height, this.currentMatrix);
 
           // Avoid drawing the start flex line when they overlap with the flex container.
           if (crossStart != 0) {
-            drawLine(this.ctx, clientWidth - crossStart, 0, clientWidth - crossStart,
-              clientHeight, options);
+            drawLine(this.ctx, width - crossStart, 0, width - crossStart, height,
+              options);
             this.ctx.stroke();
           }
 
           // Avoid drawing the end flex line when they overlap with the flex container.
-          if (clientWidth - crossStart - crossSize >= lineWidth) {
-            drawLine(this.ctx, clientWidth - crossStart - crossSize, 0,
-              clientWidth - crossStart - crossSize, clientHeight, options);
+          if (crossStart + crossSize < width - lineWidth * 2) {
+            drawLine(this.ctx, width - crossStart - crossSize, 0,
+              width - crossStart - crossSize, height, options);
             this.ctx.stroke();
           }
           break;
       }
     }
 
     this.ctx.restore();
   }
@@ -682,58 +674,48 @@ class FlexboxHighlighter extends AutoRef
    * Clear the whole alignment container along the main axis for each flex item.
    */
   renderJustifyContent() {
     if (!this.flexData || !this.currentQuads.content || !this.currentQuads.content[0]) {
       return;
     }
 
     const lineWidth = getDisplayPixelRatio(this.win);
-    const { clientWidth, clientHeight } = this.currentNode;
-    const containerOffsets = getNodeRect(this.currentNode);
+    const containerQuad = getUntransformedQuad(this.currentNode, "content");
+    const containerBounds = containerQuad.getBounds();
 
-    // Draw a justify content pattern over the whole flex container.
-    this.drawJustifyContent(0, 0, clientWidth, clientHeight);
+    // Draw a justify content pattern over the whole flex container content area.
+    this.drawJustifyContent(0, 0, containerBounds.width, containerBounds.height);
 
     for (const flexLine of this.flexData.lines) {
       const { crossStart, crossSize } = flexLine;
 
       for (const flexItem of flexLine.items) {
-        const offsets = getNodeRect(flexItem.node);
-
-        if (!offsets) {
-          continue;
-        }
-
-        const left = offsets.left - containerOffsets.left;
-        const top = offsets.top - containerOffsets.top;
-        const right = offsets.right - containerOffsets.left;
-        const bottom = offsets.bottom - containerOffsets.top;
+        const { left, top, right, bottom } = flexItem.rect;
 
         // Clear a rectangular are covering the alignment container.
         switch (this.axes) {
           case "horizontal-lr vertical-tb":
           case "horizontal-lr vertical-bt":
           case "horizontal-rl vertical-tb":
           case "horizontal-rl vertical-bt":
-            clearRect(this.ctx,
-              left, Math.round(crossStart) + 2 * lineWidth, right,
-              Math.round(crossStart + crossSize) - 2 * lineWidth, this.currentMatrix);
+            clearRect(this.ctx, left, crossStart + lineWidth, right,
+              crossStart + crossSize - lineWidth, this.currentMatrix);
             break;
           case "vertical-tb horizontal-lr":
           case "vertical-bt horizontal-rl":
             clearRect(this.ctx,
-              Math.round(crossStart) + lineWidth * 2, top,
-              Math.round(crossStart + crossSize) - lineWidth, bottom, this.currentMatrix);
+              crossStart + lineWidth * 2, top,
+              crossStart + crossSize - lineWidth, bottom, this.currentMatrix);
             break;
           case "vertical-bt horizontal-lr":
           case "vertical-tb horizontal-rl":
             clearRect(this.ctx,
-              Math.round(clientWidth - crossStart - crossSize) + lineWidth * 2, top,
-              Math.round(clientWidth - crossStart) - lineWidth, bottom,
+              containerBounds.width - crossStart - crossSize + lineWidth * 2, top,
+              containerBounds.width - crossStart - lineWidth, bottom,
               this.currentMatrix);
             break;
         }
       }
     }
   }
 
   _update() {
@@ -773,25 +755,25 @@ class FlexboxHighlighter extends AutoRef
 
     setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
     return true;
   }
 }
 
 /**
  * Returns an object representation of the Flex data object and its array of FlexLine
- * and FlexItem objects along with the box quads of the flex items.
+ * and FlexItem objects along with the DOMRects of the flex items.
  *
- * @param  {Flex} flex
- *         The Flex data object.
- * @param  {Window} win
- *         The Window object.
+ * @param  {DOMNode} container
+ *         The flex container.
  * @return {Object|null} representation of the Flex data object.
  */
-function getFlexData(flex, win) {
+function getFlexData(container) {
+  const flex = container.getAsFlexContainer();
+
   if (!flex) {
     return null;
   }
 
   return {
     lines: flex.getLines().map(line => {
       return {
         crossSize: line.crossSize,
@@ -803,25 +785,51 @@ function getFlexData(flex, win) {
           return {
             crossMaxSize: item.crossMaxSize,
             crossMinSize: item.crossMinSize,
             mainBaseSize: item.mainBaseSize,
             mainDeltaSize: item.mainDeltaSize,
             mainMaxSize: item.mainMaxSize,
             mainMinSize: item.mainMinSize,
             node: item.node,
-            quads: getAdjustedQuads(win, item.node),
+            rect: getRectFromFlexItemValues(item, container),
           };
         }),
       };
     }),
   };
 }
 
 /**
+ * Given a FlexItemValues, return a DOMRect representing the flex item taking
+ * into account its flex container's border and padding.
+ *
+ * @param  {FlexItemValues} item
+ *         The FlexItemValues for which we need the DOMRect.
+ * @param  {DOMNode}
+ *         Flex container containing the flex item.
+ * @return {DOMRect} representing the flex item.
+ */
+function getRectFromFlexItemValues(item, container) {
+  const rect = item.frameRect;
+  const domRect = new DOMRect(rect.x, rect.y, rect.width, rect.height);
+  const win = container.ownerGlobal;
+  const style = win.getComputedStyle(container);
+  const borderLeftWidth = parseInt(style.borderLeftWidth, 10) || 0;
+  const borderTopWidth = parseInt(style.borderTopWidth, 10) || 0;
+  const paddingLeft = parseInt(style.paddingLeft, 10) || 0;
+  const paddingTop = parseInt(style.paddingTop, 10) || 0;
+
+  domRect.x -= borderLeftWidth + paddingLeft;
+  domRect.y -= borderTopWidth + paddingTop;
+
+  return domRect;
+}
+
+/**
  * Returns whether or not the flex data has changed.
  *
  * @param  {Flex} oldFlexData
  *         The old Flex data object.
  * @param  {Flex} newFlexData
  *         The new Flex data object.
  * @return {Boolean} true if the flex data has changed and false otherwise.
  */
@@ -864,86 +872,26 @@ function compareFlexData(oldFlexData, ne
           oldItem.crossMinSize !== newItem.crossMinSize ||
           oldItem.mainBaseSize !== newItem.mainBaseSize ||
           oldItem.mainDeltaSize !== newItem.mainDeltaSize ||
           oldItem.mainMaxSize !== newItem.mainMaxSize ||
           oldItem.mainMinSize !== newItem.mainMinSize) {
         return true;
       }
 
-      const oldItemQuads = oldItem.quads;
-      const newItemQuads = newItem.quads;
-
-      if (oldItemQuads.length !== newItemQuads.length) {
-        return true;
-      }
+      const oldItemRect = oldItem.rect;
+      const newItemRect = newItem.rect;
 
-      const { bounds: oldItemBounds } = oldItemQuads[0];
-      const { bounds: newItemBounds } = newItemQuads[0];
-
-      if (oldItemBounds.bottom !== newItemBounds.bottom ||
-          oldItemBounds.height !== newItemBounds.height ||
-          oldItemBounds.left !== newItemBounds.left ||
-          oldItemBounds.right !== newItemBounds.right ||
-          oldItemBounds.top !== newItemBounds.top ||
-          oldItemBounds.width !== newItemBounds.width ||
-          oldItemBounds.x !== newItemBounds.x ||
-          oldItemBounds.y !== newItemBounds.y) {
+      // We are using DOMRects so we only need to compare x, y, width and
+      // height (left, top, right and bottom are calculated from these values).
+      if (oldItemRect.x !== newItemRect.x ||
+          oldItemRect.y !== newItemRect.y ||
+          oldItemRect.width !== newItemRect.width ||
+          oldItemRect.height !== newItemRect.height) {
         return true;
       }
     }
   }
 
   return false;
 }
 
-/**
- * Get the untransformed coordinates for a node.
- *
- * @param   {DOMNode} node
- *          The node for which the coordinates are to be returned.
- *
- * @returns {Object}
- *          {
- *            left: left,     // The absolute left coordinates of the node.
- *            top: top,       // The absolute top coordinates of the node.
- *            right: right,   // The absolute right coordinates of the node.
- *            bottom: bottom, // The absolute left coordinates of the node.
- *            width: width,   // The width of the node.
- *            height,         // The Height of the node.
- *          }
- */
-function getNodeRect(node) {
-  if (node.nodeType === node.TEXT_NODE) {
-    // For now ignore text node flex items because we cannot get the
-    // untransformed position and dimensions of a text node
-    // (see https://bugzil.la/1505079).
-    return null;
-  }
-
-  const win = node.ownerGlobal;
-  const style = win.getComputedStyle(node);
-  const borderLeft = parseInt(style.borderLeftWidth, 10) || 0;
-  const borderTop = parseInt(style.borderTopWidth, 10) || 0;
-  const width = node.offsetWidth;
-  const height = node.offsetHeight;
-
-  let left = 0;
-  let top = 0;
-
-  while (node) {
-    left += node.offsetLeft - node.scrollLeft + node.clientLeft;
-    top += node.offsetTop - node.scrollTop + node.clientTop;
-
-    node = node.offsetParent;
-  }
-
-  return {
-    left: left - borderLeft,
-    top: top - borderTop,
-    right: left + width - borderLeft,
-    bottom: top + height - borderTop,
-    width: width,
-    height: height,
-  };
-}
-
 exports.FlexboxHighlighter = FlexboxHighlighter;
--- a/devtools/server/tests/browser/browser_markers-cycle-collection.js
+++ b/devtools/server/tests/browser/browser_markers-cycle-collection.js
@@ -7,17 +7,17 @@
  */
 "use strict";
 
 add_task(async function() {
   // This test runs very slowly on linux32 debug EC2 instances.
   requestLongerTimeout(2);
 
   const target = await addTabTarget(MAIN_DOMAIN + "doc_force_cc.html");
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   const markers = await waitForMarkerType(front,
     ["nsCycleCollector::Collect", "nsCycleCollector::ForgetSkippable"]);
   await front.stopRecording(rec);
 
   ok(markers.some(m => m.name === "nsCycleCollector::Collect"),
--- a/devtools/server/tests/browser/browser_markers-gc.js
+++ b/devtools/server/tests/browser/browser_markers-gc.js
@@ -5,17 +5,17 @@
  * Test that we get "GarbageCollection" markers.
  */
 "use strict";
 
 const MARKER_NAME = "GarbageCollection";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_force_gc.html");
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   let markers = await waitForMarkerType(front, MARKER_NAME);
   await front.stopRecording(rec);
 
   ok(markers.some(m => m.name === MARKER_NAME), `got some ${MARKER_NAME} markers`);
   ok(markers.every(({causeName}) => typeof causeName === "string"),
--- a/devtools/server/tests/browser/browser_markers-minor-gc.js
+++ b/devtools/server/tests/browser/browser_markers-minor-gc.js
@@ -7,17 +7,17 @@
  */
 "use strict";
 
 add_task(async function() {
   // This test runs very slowly on linux32 debug EC2 instances.
   requestLongerTimeout(2);
 
   const target = await addTabTarget(MAIN_DOMAIN + "doc_allocations.html");
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   const markers = await waitForMarkerType(front, ["MinorGC"]);
   await front.stopRecording(rec);
 
   ok(markers.some(m => m.name === "MinorGC" && m.causeName),
      "got some MinorGC markers");
--- a/devtools/server/tests/browser/browser_markers-parse-html.js
+++ b/devtools/server/tests/browser/browser_markers-parse-html.js
@@ -6,17 +6,17 @@
  */
 "use strict";
 
 const MARKER_NAME = "Parse HTML";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_innerHTML.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   const markers = await waitForMarkerType(front, MARKER_NAME);
   await front.stopRecording(rec);
 
   ok(markers.some(m => m.name === MARKER_NAME), `got some ${MARKER_NAME} markers`);
 
--- a/devtools/server/tests/browser/browser_markers-styles.js
+++ b/devtools/server/tests/browser/browser_markers-styles.js
@@ -6,17 +6,17 @@
  */
 "use strict";
 
 const MARKER_NAME = "Styles";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   const markers = await waitForMarkerType(front, MARKER_NAME);
 
   await front.stopRecording(rec);
 
   ok(markers.some(m => m.name === MARKER_NAME), `got some ${MARKER_NAME} markers`);
--- a/devtools/server/tests/browser/browser_markers-timestamp.js
+++ b/devtools/server/tests/browser/browser_markers-timestamp.js
@@ -8,17 +8,17 @@
 
 const { pmmConsoleMethod, pmmLoadFrameScripts, pmmClearFrameScripts }
   = require("devtools/client/performance/test/helpers/profiler-mm-utils");
 const MARKER_NAME = "TimeStamp";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
   const rec = await front.startRecording({ withMarkers: true });
 
   pmmLoadFrameScripts(gBrowser);
   pmmConsoleMethod("timeStamp");
   pmmConsoleMethod("timeStamp", "myLabel");
 
   const markers = await waitForMarkerType(front, MARKER_NAME, m => m.length >= 2);
--- a/devtools/server/tests/browser/browser_perf-allocation-data.js
+++ b/devtools/server/tests/browser/browser_perf-allocation-data.js
@@ -4,17 +4,17 @@
 /**
  * Test that we have allocation data coming from the front.
  */
 
 "use strict";
 
 add_task(async function() {
   const target  = await addTabTarget(MAIN_DOMAIN + "doc_allocations.html");
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   const rec = await front.startRecording(
     { withMarkers: true, withAllocations: true, withTicks: true });
 
   await waitUntil(() => rec.getAllocations().frames.length);
   await waitUntil(() => rec.getAllocations().timestamps.length);
   await waitUntil(() => rec.getAllocations().sizes.length);
--- a/devtools/server/tests/browser/browser_perf-profiler-01.js
+++ b/devtools/server/tests/browser/browser_perf-profiler-01.js
@@ -9,17 +9,17 @@
 
 "use strict";
 
 const { pmmIsProfilerActive, pmmLoadFrameScripts } = require("devtools/client/performance/test/helpers/profiler-mm-utils");
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   pmmLoadFrameScripts(gBrowser);
 
   ok(!(await pmmIsProfilerActive()),
     "The built-in profiler module should not have been automatically started.");
 
   let rec = await front.startRecording();
--- a/devtools/server/tests/browser/browser_perf-profiler-02.js
+++ b/devtools/server/tests/browser/browser_perf-profiler-02.js
@@ -7,25 +7,25 @@
  */
 
 "use strict";
 
 const { pmmIsProfilerActive, pmmLoadFrameScripts } = require("devtools/client/performance/test/helpers/profiler-mm-utils");
 
 add_task(async function() {
   const target1 = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
-  const firstFront = target1.getFront("performance");
+  const firstFront = await target1.getFront("performance");
   await firstFront.connect();
 
   pmmLoadFrameScripts(gBrowser);
 
   await firstFront.startRecording();
 
   const target2 = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
-  const secondFront = target2.getFront("performance");
+  const secondFront = await target2.getFront("performance");
   await secondFront.connect();
   pmmLoadFrameScripts(gBrowser);
 
   await secondFront.startRecording();
 
   // Manually teardown the tabs so we can check profiler status
   await secondFront.destroy();
   await target2.destroy();
--- a/devtools/server/tests/browser/browser_perf-profiler-03.js
+++ b/devtools/server/tests/browser/browser_perf-profiler-03.js
@@ -19,23 +19,23 @@ add_task(async function() {
   const interval = 1;
   const features = ["js"];
   await pmmStartProfiler({ entries, interval, features });
 
   ok((await pmmIsProfilerActive()),
     "The built-in profiler module should still be active.");
 
   const target1 = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
-  const firstFront = target1.getFront("performance");
+  const firstFront = await target1.getFront("performance");
   await firstFront.connect();
 
   await firstFront.startRecording();
 
   const target2 = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
-  const secondFront = target2.getFront("performance");
+  const secondFront = await target2.getFront("performance");
   await secondFront.connect();
 
   await secondFront.destroy();
   await target2.destroy();
   ok((await pmmIsProfilerActive()),
     "The built-in profiler module should still be active.");
 
   await firstFront.destroy();
--- a/devtools/server/tests/browser/browser_perf-realtime-markers.js
+++ b/devtools/server/tests/browser/browser_perf-realtime-markers.js
@@ -5,17 +5,17 @@
  * Test functionality of real time markers.
  */
 
 "use strict";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   let lastMemoryDelta = 0;
   let lastTickDelta = 0;
 
   const counters = {
     markers: [],
     memory: [],
--- a/devtools/server/tests/browser/browser_perf-recording-actor-01.js
+++ b/devtools/server/tests/browser/browser_perf-recording-actor-01.js
@@ -5,17 +5,17 @@
  * Tests the state of a recording rec from start to finish for recording,
  * completed, and rec data.
  */
 
 "use strict";
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   const rec = await front.startRecording(
     { withMarkers: true, withTicks: true, withMemory: true });
   ok(rec.isRecording(), "RecordingModel is recording when created");
   await busyWait(100);
   await waitUntil(() => rec.getMemory().length);
   ok(true, "RecordingModel populates memory while recording");
--- a/devtools/server/tests/browser/browser_perf-recording-actor-02.js
+++ b/devtools/server/tests/browser/browser_perf-recording-actor-02.js
@@ -8,17 +8,17 @@
 "use strict";
 
 var BUFFER_SIZE = 20000;
 var config = { bufferSize: BUFFER_SIZE };
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   await front.setProfilerStatusInterval(10);
   const model = await front.startRecording(config);
   const stats = await once(front, "profiler-status");
   is(stats.totalSize, BUFFER_SIZE,
     `profiler-status event has totalSize: ${stats.totalSize}`);
   ok(stats.position < BUFFER_SIZE,
--- a/devtools/server/tests/browser/browser_perf-samples-01.js
+++ b/devtools/server/tests/browser/browser_perf-samples-01.js
@@ -10,17 +10,17 @@
 
 // time in ms
 const WAIT_TIME = 1000;
 
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["privacy.reduceTimerPrecision", false]]});
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   // Perform the first recording...
 
   const firstRecording = await front.startRecording();
   const firstRecordingStartTime = firstRecording._startTime;
   info("Started profiling at: " + firstRecordingStartTime);
 
--- a/devtools/server/tests/browser/browser_perf-samples-02.js
+++ b/devtools/server/tests/browser/browser_perf-samples-02.js
@@ -10,17 +10,17 @@
 "use strict";
 
 // Time in ms
 const WAIT_TIME = 1000;
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "doc_perf.html");
 
-  const front = target.getFront("performance");
+  const front = await target.getFront("performance");
   await front.connect();
 
   const rec = await front.startRecording();
   // allow the profiler module to sample some cpu activity
   busyWait(WAIT_TIME);
 
   await front.stopRecording(rec);
   const profile = rec.getProfile();
--- a/devtools/server/tests/browser/browser_storage_updates.js
+++ b/devtools/server/tests/browser/browser_storage_updates.js
@@ -175,17 +175,17 @@ const TESTS = [
         },
       },
     },
   },
 ];
 
 add_task(async function() {
   const target = await addTabTarget(MAIN_DOMAIN + "storage-updates.html");
-  const front = target.getFront("storage");
+  const front = await target.getFront("storage");
 
   await front.listStores();
 
   for (let i = 0; i < TESTS.length; i++) {
     const test = TESTS[i];
     await runTest(test, front, i);
   }
 
--- a/devtools/server/tests/browser/browser_stylesheets_getTextEmpty.js
+++ b/devtools/server/tests/browser/browser_stylesheets_getTextEmpty.js
@@ -6,17 +6,17 @@
 
 // Test that StyleSheetActor.getText handles empty text correctly.
 
 const CONTENT = "<style>body { background-color: #f06; }</style>";
 const TEST_URI = "data:text/html;charset=utf-8," + encodeURIComponent(CONTENT);
 
 add_task(async function() {
   const target = await addTabTarget(TEST_URI);
-  const front = target.getFront("stylesheets");
+  const front = await target.getFront("stylesheets");
   ok(front, "The StyleSheetsFront was created.");
 
   const sheets = await front.getStyleSheets();
   ok(sheets, "getStyleSheets() succeeded");
   is(sheets.length, 1,
      "getStyleSheets() returned the correct number of sheets");
 
   const sheet = sheets[0];
--- a/devtools/server/tests/browser/browser_stylesheets_nested-iframes.js
+++ b/devtools/server/tests/browser/browser_stylesheets_nested-iframes.js
@@ -6,17 +6,17 @@
 
 // Test that StyleSheetsActor.getStyleSheets() works if an iframe does not have
 // a content document.
 
 add_task(async function() {
   info("Initialising the debugger server and client.");
   const target = await addTabTarget(MAIN_DOMAIN + "stylesheets-nested-iframes.html");
 
-  const front = target.getFront("stylesheets");
+  const front = await target.getFront("stylesheets");
   ok(front, "The StyleSheetsFront was created.");
 
   const sheets = await front.getStyleSheets();
   ok(sheets, "getStyleSheets() succeeded even with documentless iframes.");
 
   // Bug 285395 limits the number of nested iframes to 10. There's one sheet per
   // frame so we should get 10 sheets. However, the limit might change in the
   // future so it's better not to rely on the limit. Asserting > 2 ensures that
--- a/devtools/server/tests/browser/browser_webextension_inspected_window.js
+++ b/devtools/server/tests/browser/browser_webextension_inspected_window.js
@@ -25,17 +25,17 @@ async function setup(pageUrl) {
   const target = await addTabTarget(pageUrl);
 
   const { client, form } = target;
 
   const [, targetFront] = await client.attachTarget(form.actor);
 
   const [, consoleClient] = await client.attachConsole(form.consoleActor, []);
 
-  const inspectedWindowFront = target.getFront("webExtensionInspectedWindow");
+  const inspectedWindowFront = await target.getFront("webExtensionInspectedWindow");
 
   return {
     client, form,
     targetFront, consoleClient,
     inspectedWindowFront,
     extension, fakeExtCallerInfo,
   };
 }
--- a/devtools/server/tests/browser/head.js
+++ b/devtools/server/tests/browser/head.js
@@ -59,33 +59,33 @@ async function getTargetForTab(tab) {
   const target = await TargetFactory.forTab(tab);
   info("Attaching to the active tab.");
   await target.attach();
   return target;
 }
 
 async function initAnimationsFrontForUrl(url) {
   const { inspector, walker, target } = await initInspectorFront(url);
-  const animations = target.getFront("animations");
+  const animations = await target.getFront("animations");
 
   return {inspector, walker, animations, target};
 }
 
 async function initLayoutFrontForUrl(url) {
   const {inspector, walker, target} = await initInspectorFront(url);
   const layout = await walker.getLayoutInspector();
 
   return {inspector, walker, layout, target};
 }
 
 async function initAccessibilityFrontForUrl(url) {
   const target = await addTabTarget(url);
   const inspector = await target.getInspector();
   const walker = inspector.walker;
-  const accessibility = target.getFront("accessibility");
+  const accessibility = await target.getFront("accessibility");
 
   await accessibility.bootstrap();
 
   return {inspector, walker, accessibility, target};
 }
 
 function initDebuggerServer() {
   try {
--- a/devtools/server/tests/browser/storage-helpers.js
+++ b/devtools/server/tests/browser/storage-helpers.js
@@ -49,17 +49,17 @@ async function openTabAndSetupStorage(ur
     for (const win of windows) {
       if (win.setup) {
         await win.setup();
       }
     }
   });
   // selected tab is set in addTab
   const target = await getTargetForTab(gBrowser.selectedTab);
-  const front = target.getFront("storage");
+  const front = await target.getFront("storage");
   return { target, front };
 }
 
 async function clearStorage() {
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     /**
      * Get all windows including frames recursively.
      *
--- a/devtools/server/tests/mochitest/memory-helpers.js
+++ b/devtools/server/tests/mochitest/memory-helpers.js
@@ -18,17 +18,17 @@ SimpleTest.registerCleanupFunction(funct
 async function getTargetForSelectedTab() {
   const browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
   const target = await TargetFactory.forTab(browserWindow.gBrowser.selectedTab);
   return target;
 }
 
 async function startServerAndGetSelectedTabMemory() {
   const target = await getTargetForSelectedTab();
-  const memory = target.getFront("memory");
+  const memory = await target.getFront("memory");
   return {memory, target};
 }
 
 async function destroyServerAndFinish(target) {
   await target.destroy();
   SimpleTest.finish();
 }
 
--- a/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
+++ b/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
@@ -21,17 +21,17 @@ window.onload = function() {
 
   addTest(async function setup() {
     info("Setting up inspector and animation actors.");
 
     const url = document.getElementById("animationContent").href;
 
     const { target } = await attachURL(url);
     const inspector = await target.getInspector();
-    animationsFront = target.getFront("animations");
+    animationsFront = await target.getFront("animations");
     gWalker = inspector.walker;
     runNextTest();
   });
 
   addAsyncTest(async function testActorLifetime() {
     info("Testing animated node actor");
     const animatedNodeActor = await gWalker.querySelector(gWalker.rootNode,
       ".animated");
--- a/devtools/server/tests/mochitest/test_framerate_01.html
+++ b/devtools/server/tests/mochitest/test_framerate_01.html
@@ -12,17 +12,17 @@ Bug 1007200 - Create a framerate actor
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
 window.onload = async function() {
   const target = await getTargetForSelectedTab();
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
   const TICK = 1000;
 
   await waitFor(TICK);
   await front.startRecording();
   await waitFor(TICK);
   const rawData = await front.stopRecording();
   await onRecordingStopped(front, rawData);
   await target.destroy();
--- a/devtools/server/tests/mochitest/test_framerate_02.html
+++ b/devtools/server/tests/mochitest/test_framerate_02.html
@@ -12,17 +12,17 @@ Bug 1007200 - Create a framerate actor
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
 window.onload = async function() {
   const target = await getTargetForSelectedTab();
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
 
   const rawData = await front.stopRecording();
   ok(rawData, "There should be a recording available.");
   is(rawData.length, 0, "...but it should be empty.");
 
   const timeline = plotFPS(rawData);
   is(timeline.length, 2,
     "There should be one measurement plotted, with two entries.");
--- a/devtools/server/tests/mochitest/test_framerate_03.html
+++ b/devtools/server/tests/mochitest/test_framerate_03.html
@@ -16,17 +16,17 @@ Bug 1023018 - Tests whether or not the f
 "use strict";
 
 const START_TICK = 2000;
 const STOP_TICK = 3000;
 const TOTAL_TIME = 5000;
 
 window.onload = async function() {
   const target = await getTargetForSelectedTab();
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
 
   await front.startRecording();
   await waitFor(TOTAL_TIME);
   const rawData = await front.stopRecording(START_TICK, STOP_TICK);
   await onRecordingStopped(front, rawData);
   await target.destroy();
   SimpleTest.finish();
 };
--- a/devtools/server/tests/mochitest/test_framerate_04.html
+++ b/devtools/server/tests/mochitest/test_framerate_04.html
@@ -18,17 +18,17 @@ Bug 1023018 - Tests if the framerate act
 window.onload = async function() {
   // inspector-helpers doesnt wait for explicit finish
   SimpleTest.waitForExplicitFinish();
 
   const TICK = 1000;
   const url = document.getElementById("testContent").href;
   const { target, doc } = await attachURL(url);
   const contentWin = doc.defaultView;
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
 
   await front.startRecording();
   await waitFor(TICK);
   const firstBatch = await front.getPendingTicks();
   await waitFor(TICK);
 
   const onWillNavigate = target.once("will-navigate");
   contentWin.location.reload();
--- a/devtools/server/tests/mochitest/test_framerate_05.html
+++ b/devtools/server/tests/mochitest/test_framerate_05.html
@@ -12,17 +12,17 @@ Bug 1034648 - Tests whether a framerate 
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
 window.onload = async function() {
   const target = await getTargetForSelectedTab();
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
   const TICK = 1000;
 
   await front.startRecording();
   await waitFor(TICK);
 
   await front.cancelRecording();
   await waitFor(TICK);
 
--- a/devtools/server/tests/mochitest/test_framerate_06.html
+++ b/devtools/server/tests/mochitest/test_framerate_06.html
@@ -19,17 +19,17 @@ window.onload = async function() {
   // inspector-helpers doesnt wait for explicit finish
   SimpleTest.waitForExplicitFinish();
 
   const TICK = 1000;
   const url = document.getElementById("testContent").href;
   const { target, doc } = await attachURL(url);
   const contentWin = doc.defaultView;
 
-  const front = target.getFront("framerate");
+  const front = await target.getFront("framerate");
 
   await front.startRecording();
   await waitFor(TICK);
   const onWindowReady = waitForWindowReady();
   contentWin.location.reload();
 
   // Wait for the iframe to be loaded again
   await onWindowReady;
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -78,17 +78,17 @@ async function createTabMemoryFront() {
   const tab = findTab(tabs, "test_MemoryActor");
   const options = {
     form: tab,
     client,
     chrome: false,
   };
   const target = await TargetFactory.forRemoteTab(options);
 
-  const memoryFront = target.getFront("memory");
+  const memoryFront = await target.getFront("memory");
   await memoryFront.attach();
 
   return { client, memoryFront };
 }
 
 /**
  * Same as createTabMemoryFront but attaches the MemoryFront to the MemoryActor
  * scoped to the full runtime rather than to a tab.
@@ -104,17 +104,17 @@ async function createFullRuntimeMemoryFr
   const front = await client.mainRoot.getMainProcess();
   const options = {
     activeTab: front,
     client,
     chrome: true,
   };
   const target = await TargetFactory.forRemoteTab(options);
 
-  const memoryFront = target.getFront("memory");
+  const memoryFront = await target.getFront("memory");
   await memoryFront.attach();
 
   return { client, memoryFront };
 }
 
 function createTestGlobal(name) {
   const sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"]
                            .createInstance(Ci.nsIPrincipal));
--- a/devtools/shared/fronts/css-properties.js
+++ b/devtools/shared/fronts/css-properties.js
@@ -229,17 +229,17 @@ CssProperties.prototype = {
  */
 const initCssProperties = async function(toolbox) {
   const client = toolbox.target.client;
   if (cachedCssProperties.has(client)) {
     return cachedCssProperties.get(client);
   }
 
   // Get the list dynamically if the cssProperties actor exists.
-  const front = toolbox.target.getFront("cssProperties");
+  const front = await toolbox.target.getFront("cssProperties");
   const db = await front.getCSSDatabase();
 
   const cssProperties = new CssProperties(normalizeCssData(db));
   cachedCssProperties.set(client, {cssProperties, front});
   return {cssProperties, front};
 };
 
 /**
--- a/devtools/shared/layout/utils.js
+++ b/devtools/shared/layout/utils.js
@@ -816,8 +816,90 @@ function removeSheet(window, url, type =
   const windowUtils = utilsFor(window);
   try {
     windowUtils.removeSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
   } catch (e) {
     // The method fails if the url is already removed.
   }
 }
 exports.removeSheet = removeSheet;
+
+/**
+ * Get the untransformed coordinates for a node.
+ *
+ * @param  {DOMNode} node
+ *         The node for which the DOMQuad is to be returned.
+ * @param  {String} region
+ *         The box model region to return: "content", "padding", "border" or
+ *         "margin".
+ * @return {DOMQuad}
+ *         A DOMQuad representation of the node.
+ */
+function getUntransformedQuad(node, region = "border") {
+  // Get the inverse transformation matrix for the node.
+  const matrix = node.getTransformToViewport();
+  const inverse = matrix.inverse();
+  const win = node.ownerGlobal;
+
+  // Get the adjusted quads for the node (including scroll offsets).
+  const quads = getAdjustedQuads(win, node, region, {
+    ignoreZoom: true,
+  });
+
+  // Create DOMPoints from the transformed node position.
+  const p1 = new DOMPoint(quads[0].p1.x, quads[0].p1.y);
+  const p2 = new DOMPoint(quads[0].p2.x, quads[0].p2.y);
+  const p3 = new DOMPoint(quads[0].p3.x, quads[0].p3.y);
+  const p4 = new DOMPoint(quads[0].p4.x, quads[0].p4.y);
+
+  // Apply the inverse transformation matrix to the points to get the
+  // untransformed points.
+  const ip1 = inverse.transformPoint(p1);
+  const ip2 = inverse.transformPoint(p2);
+  const ip3 = inverse.transformPoint(p3);
+  const ip4 = inverse.transformPoint(p4);
+
+  // Save the results in a DOMQuad.
+  const quad = new DOMQuad(
+    { x: ip1.x, y: ip1.y },
+    { x: ip2.x, y: ip2.y },
+    { x: ip3.x, y: ip3.y },
+    { x: ip4.x, y: ip4.y }
+  );
+
+  // Remove the border offsets because we include them when calculating
+  // offsets in the while loop.
+  const style = win.getComputedStyle(node);
+  const leftAdjustment = parseInt(style.borderLeftWidth, 10) || 0;
+  const topAdjustment = parseInt(style.borderTopWidth, 10) || 0;
+
+  quad.p1.x -= leftAdjustment;
+  quad.p2.x -= leftAdjustment;
+  quad.p3.x -= leftAdjustment;
+  quad.p4.x -= leftAdjustment;
+  quad.p1.y -= topAdjustment;
+  quad.p2.y -= topAdjustment;
+  quad.p3.y -= topAdjustment;
+  quad.p4.y -= topAdjustment;
+
+  // Calculate offsets.
+  while (node) {
+    const nodeStyle = win.getComputedStyle(node);
+    const borderLeftWidth = parseInt(nodeStyle.borderLeftWidth, 10) || 0;
+    const borderTopWidth = parseInt(nodeStyle.borderTopWidth, 10) || 0;
+    const leftOffset = node.offsetLeft - node.scrollLeft + borderLeftWidth;
+    const topOffset = node.offsetTop - node.scrollTop + borderTopWidth;
+
+    quad.p1.x += leftOffset;
+    quad.p2.x += leftOffset;
+    quad.p3.x += leftOffset;
+    quad.p4.x += leftOffset;
+    quad.p1.y += topOffset;
+    quad.p2.y += topOffset;
+    quad.p3.y += topOffset;
+    quad.p4.y += topOffset;
+
+    node = node.offsetParent;
+  }
+
+  return quad;
+}
+exports.getUntransformedQuad = getUntransformedQuad;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -475,16 +475,18 @@ nsDocShell::Create(BrowsingContext* aBro
   rv = ds->mContentListener->Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   // If parent intercept is not enabled then we must forward to
   // the network controller from docshell.  We also enable if we're
   // in the parent process in order to support non-e10s configurations.
+  // Note: This check is duplicated in SharedWorkerInterfaceRequestor's
+  // constructor.
   if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
     ds->mInterceptController = new ServiceWorkerInterceptController();
   }
 
   // We want to hold a strong ref to the loadgroup, so it better hold a weak
   // ref to us...  use an InterfaceRequestorProxy to do this.
   nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(ds);
   ds->mLoadGroup->SetNotificationCallbacks(proxy);
@@ -759,16 +761,17 @@ nsDocShell::LoadURI(nsDocShellLoadState*
   MOZ_ASSERT(aLoadState->SHEntry() == nullptr,
              "SHEntry should be null when calling InternalLoad from LoadURI");
 
   return InternalLoad(aLoadState->URI(),
                       aLoadState->OriginalURI(),
                       resultPrincipalURI,
                       aLoadState->KeepResultPrincipalURIIfSet(),
                       aLoadState->LoadReplace(),
+                      aLoadState->GetIsFromProcessingFrameAttributes(),
                       aLoadState->Referrer(),
                       aLoadState->ReferrerPolicy(),
                       aLoadState->TriggeringPrincipal(),
                       aLoadState->PrincipalToInherit(),
                       aLoadState->DocShellInternalLoadFlags(),
                       aLoadState->Target(),
                       aLoadState->TypeHint(),
                       aLoadState->FileName(),
@@ -4809,17 +4812,18 @@ nsDocShell::LoadErrorPage(nsIURI* aError
 
   if (mLSHE) {
     // Abandon mLSHE's BFCache entry and create a new one.  This way, if
     // we go back or forward to another SHEntry with the same doc
     // identifier, the error page won't persist.
     mLSHE->AbandonBFCacheEntry();
   }
 
-  return InternalLoad(aErrorURI, nullptr, Nothing(), false, false, nullptr, RP_Unset,
+  return InternalLoad(aErrorURI, nullptr, Nothing(), false, false,
+                      false, nullptr, RP_Unset,
                       nsContentUtils::GetSystemPrincipal(), nullptr,
                       INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
                       VoidCString(), VoidString(), nullptr, nullptr,
                       LOAD_ERROR_PAGE, nullptr, true, VoidString(), this,
                       nullptr, nullptr, nullptr);
 }
 
 NS_IMETHODIMP
@@ -4909,16 +4913,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
     // Reload always rewrites result principal URI.
     Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
     emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
     rv = InternalLoad(currentURI,
                       originalURI,
                       emplacedResultPrincipalURI,
                       false,
                       loadReplace,
+                      false,           // IsFromProcessingFrameAttributes
                       referrerURI,
                       referrerPolicy,
                       triggeringPrincipal,
                       triggeringPrincipal,
                       flags,
                       EmptyString(),   // No window target
                       NS_LossyConvertUTF16toASCII(contentTypeHint),
                       VoidString(),    // No forced download
@@ -8997,16 +9002,17 @@ class InternalLoadEvent : public Runnabl
 {
 public:
   InternalLoadEvent(nsDocShell* aDocShell,
                     nsIURI* aURI,
                     nsIURI* aOriginalURI,
                     Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                     bool aKeepResultPrincipalURIIfSet,
                     bool aLoadReplace,
+                    bool aIsFromProcessingFrameAttributes,
                     nsIURI* aReferrer, uint32_t aReferrerPolicy,
                     nsIPrincipal* aTriggeringPrincipal,
                     nsIPrincipal* aPrincipalToInherit,
                     uint32_t aFlags,
                     const nsACString& aTypeHint,
                     nsIInputStream* aPostData,
                     nsIInputStream* aHeadersData,
                     uint32_t aLoadType,
@@ -9019,16 +9025,17 @@ public:
     , mTypeHint(aTypeHint)
     , mSrcdoc(aSrcdoc)
     , mDocShell(aDocShell)
     , mURI(aURI)
     , mOriginalURI(aOriginalURI)
     , mResultPrincipalURI(aResultPrincipalURI)
     , mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet)
     , mLoadReplace(aLoadReplace)
+    , mIsFromProcessingFrameAttributes(aIsFromProcessingFrameAttributes)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
     , mTriggeringPrincipal(aTriggeringPrincipal)
     , mPrincipalToInherit(aPrincipalToInherit)
     , mPostData(aPostData)
     , mHeadersData(aHeadersData)
     , mSHEntry(aSHEntry)
     , mFlags(aFlags)
@@ -9043,16 +9050,17 @@ public:
   Run() override
   {
 #ifndef ANDROID
     MOZ_ASSERT(mTriggeringPrincipal, "InternalLoadEvent: Should always have a principal here");
 #endif
     return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
                                    mKeepResultPrincipalURIIfSet,
                                    mLoadReplace,
+                                   mIsFromProcessingFrameAttributes,
                                    mReferrer,
                                    mReferrerPolicy,
                                    mTriggeringPrincipal, mPrincipalToInherit,
                                    mFlags, EmptyString(),
                                    mTypeHint,
                                    VoidString(), mPostData,
                                    mHeadersData, mLoadType, mSHEntry,
                                    mFirstParty, mSrcdoc, mSourceDocShell,
@@ -9065,16 +9073,17 @@ private:
   nsString mSrcdoc;
 
   RefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
   bool mKeepResultPrincipalURIIfSet;
   bool mLoadReplace;
+  bool mIsFromProcessingFrameAttributes;
   nsCOMPtr<nsIURI> mReferrer;
   uint32_t mReferrerPolicy;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
   nsCOMPtr<nsIInputStream> mPostData;
   nsCOMPtr<nsIInputStream> mHeadersData;
   nsCOMPtr<nsISHEntry> mSHEntry;
   uint32_t mFlags;
@@ -9101,16 +9110,17 @@ nsDocShell::JustStartedNetworkLoad()
 }
 
 NS_IMETHODIMP
 nsDocShell::InternalLoad(nsIURI* aURI,
                          nsIURI* aOriginalURI,
                          Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                          bool aKeepResultPrincipalURIIfSet,
                          bool aLoadReplace,
+                         bool aIsFromProcessingFrameAttributes,
                          nsIURI* aReferrer,
                          uint32_t aReferrerPolicy,
                          nsIPrincipal* aTriggeringPrincipal,
                          nsIPrincipal* aPrincipalToInherit,
                          uint32_t aFlags,
                          const nsAString& aWindowTarget,
                          const nsACString& aTypeHint,
                          const nsAString& aFileName,
@@ -9453,16 +9463,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     // window target name from to prevent recursive retargeting!
     //
     if (NS_SUCCEEDED(rv) && targetDocShell) {
       rv = targetDocShell->InternalLoad(aURI,
                                         aOriginalURI,
                                         aResultPrincipalURI,
                                         aKeepResultPrincipalURIIfSet,
                                         aLoadReplace,
+                                        aIsFromProcessingFrameAttributes,
                                         aReferrer,
                                         aReferrerPolicy,
                                         aTriggeringPrincipal,
                                         principalToInherit,
                                         aFlags,
                                         EmptyString(),   // No window target
                                         aTypeHint,
                                         VoidString(),    // No forced download
@@ -9551,17 +9562,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       }
 
       // Do this asynchronously
       nsCOMPtr<nsIRunnable> ev =
         new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
                               aKeepResultPrincipalURIIfSet,
-                              aLoadReplace, aReferrer, aReferrerPolicy,
+                              aLoadReplace, aIsFromProcessingFrameAttributes,
+                              aReferrer, aReferrerPolicy,
                               aTriggeringPrincipal, principalToInherit,
                               aFlags, aTypeHint, aPostData,
                               aHeadersData, aLoadType, aSHEntry, aFirstParty,
                               aSrcdoc, aSourceDocShell, aBaseURI);
       return DispatchToTabGroup(TaskCategory::Other, ev.forget());
     }
 
     // Just ignore this load attempt
@@ -10065,16 +10077,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   PredictorLearn(aURI, nullptr,
                  nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
   PredictorPredict(aURI, nullptr,
                    nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
 
   nsCOMPtr<nsIRequest> req;
   rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI,
                  aKeepResultPrincipalURIIfSet, aLoadReplace,
+                 aIsFromProcessingFrameAttributes,
                  loadFromExternal,
                  (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
                  (aFlags & INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC),
                  aReferrer,
                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                  aReferrerPolicy,
                  aTriggeringPrincipal, principalToInherit, aTypeHint,
                  aFileName, aPostData, aHeadersData,
@@ -10213,16 +10226,17 @@ IsConsideredSameOriginForUIR(nsIPrincipa
 }
 
 nsresult
 nsDocShell::DoURILoad(nsIURI* aURI,
                       nsIURI* aOriginalURI,
                       Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                       bool aKeepResultPrincipalURIIfSet,
                       bool aLoadReplace,
+                      bool aIsFromProcessingFrameAttributes,
                       bool aLoadFromExternal,
                       bool aForceAllowDataURI,
                       bool aOriginalFrameSrc,
                       nsIURI* aReferrerURI,
                       bool aSendReferrer,
                       uint32_t aReferrerPolicy,
                       nsIPrincipal* aTriggeringPrincipal,
                       nsIPrincipal* aPrincipalToInherit,
@@ -10388,17 +10402,17 @@ nsDocShell::DoURILoad(nsIURI* aURI,
 
   if (inheritPrincipal) {
     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
   if (isSandBoxed) {
     securityFlags |= nsILoadInfo::SEC_SANDBOXED;
   }
 
-  nsCOMPtr<nsILoadInfo> loadInfo =
+  RefPtr<LoadInfo> loadInfo =
     (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
       new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext,
                    securityFlags) :
       new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
                    securityFlags, aContentPolicyType);
 
   if (aPrincipalToInherit) {
     loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
@@ -10434,16 +10448,20 @@ nsDocShell::DoURILoad(nsIURI* aURI,
     return rv;
   }
 
   // Document loads should set the reload flag on the channel so that it
   // can be exposed on the service worker FetchEvent.
   rv = loadInfo->SetIsDocshellReload(mLoadType & LOAD_CMD_RELOAD);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (aIsFromProcessingFrameAttributes) {
+    loadInfo->SetIsFromProcessingFrameAttributes();
+  }
+
   if (!isSrcdoc) {
     rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                aURI,
                                loadInfo,
                                nullptr,   // PerformanceStorage
                                nullptr,   // loadGroup
                                static_cast<nsIInterfaceRequestor*>(this),
                                loadFlags);
@@ -12144,16 +12162,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
   // first created. bug 947716 has been created to address this issue.
   Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
   emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI));
   rv = InternalLoad(uri,
                     originalURI,
                     emplacedResultPrincipalURI,
                     false,
                     loadReplace,
+                    false,              // IsFromProcessingFrameAttributes
                     referrerURI,
                     referrerPolicy,
                     triggeringPrincipal,
                     principalToInherit,
                     flags,
                     EmptyString(),      // No window target
                     contentType,        // Type hint
                     VoidString(),       // No forced file download
@@ -13336,16 +13355,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
     flags |= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED;
   }
 
   nsresult rv = InternalLoad(aURI,                      // New URI
                              nullptr,                   // Original URI
                              Nothing(),                 // Let the protocol handler assign it
                              false,
                              false,                     // LoadReplace
+                             false,                     // IsFromProcessingFrameAttributes
                              referer,                   // Referer URI
                              refererPolicy,             // Referer policy
                              triggeringPrincipal,
                              aContent->NodePrincipal(),
                              flags,
                              target,                    // Window target
                              NS_LossyConvertUTF16toASCII(typeHint),
                              aFileName,                 // Download as file
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -527,16 +527,17 @@ private: // member functions
   // aOriginalURI will be set as the originalURI on the channel that does the
   // load. If aOriginalURI is null, aURI will be set as the originalURI.
   // If aLoadReplace is true, LOAD_REPLACE flag will be set to the nsIChannel.
   nsresult DoURILoad(nsIURI* aURI,
                      nsIURI* aOriginalURI,
                      mozilla::Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                      bool aKeepResultPrincipalURIIfSet,
                      bool aLoadReplace,
+                     bool aIsFromProcessingFrameAttributes,
                      bool aLoadFromExternal,
                      bool aForceAllowDataURI,
                      bool aOriginalFrameSrc,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
                      nsIPrincipal* aTriggeringPrincipal,
                      nsIPrincipal* aPrincipalToInherit,
--- a/docshell/base/nsDocShellLoadState.cpp
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -25,16 +25,17 @@ nsDocShellLoadState::nsDocShellLoadState
   , mReferrerPolicy(mozilla::net::RP_Unset)
   , mLoadType(LOAD_NORMAL)
   , mIsSrcdocLoad(false)
   , mLoadFlags(0)
   , mFirstParty(false)
   , mTypeHint(VoidCString())
   , mFileName(VoidString())
   , mDocShellInternalLoadFlags(0)
+  , mIsFromProcessingFrameAttributes(false)
 {
 }
 
 nsDocShellLoadState::~nsDocShellLoadState()
 {
 }
 
 nsIURI*
--- a/docshell/base/nsDocShellLoadState.h
+++ b/docshell/base/nsDocShellLoadState.h
@@ -160,16 +160,19 @@ public:
   // else if the principal should be set up later in the process (after loads).
   // See comments in function for more info on principal selection algorithm
   nsresult SetupInheritingPrincipal(uint32_t aItemType, const mozilla::OriginAttributes& aOriginAttributes);
 
   // If no triggering principal exists at the moment, create one using referrer
   // information and origin attributes.
   nsresult SetupTriggeringPrincipal(const mozilla::OriginAttributes& aOriginAttributes);
 
+  void SetIsFromProcessingFrameAttributes() { mIsFromProcessingFrameAttributes = true; }
+  bool GetIsFromProcessingFrameAttributes() { return mIsFromProcessingFrameAttributes; }
+
   // When loading a document through nsDocShell::LoadURI(), a special set of
   // flags needs to be set based on other values in nsDocShellLoadState. This
   // function calculates those flags, before the LoadState is passed to
   // nsDocShell::InternalLoad.
   void CalculateDocShellInternalLoadFlags();
 protected:
   // Destructor can't be defaulted or inlined, as header doesn't have all type
   // includes it needs to do so.
@@ -283,11 +286,15 @@ protected:
   // specified, but link should still trigger a download. If not a download,
   // mFileName.IsVoid() should return true.
   nsString mFileName;
 
   // LoadFlags calculated in nsDocShell::LoadURI and passed to
   // nsDocShell::InternalLoad, taken from the INTERNAL_LOAD consts in
   // nsIDocShell.idl
   uint32_t mDocShellInternalLoadFlags;
+
+  // This will be true if this load is triggered by attribute changes.
+  // See nsILoadInfo.isFromProcessingFrameAttributes
+  bool mIsFromProcessingFrameAttributes;
 };
 
 #endif /* nsDocShellLoadState_h__ */
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -132,16 +132,19 @@ interface nsIDocShell : nsIDocShellTreeI
    *                                       aResultPrincipalURI, but we do not want
    *                                       to overwrite the channel's
    *                                       ResultPrincipalURI, if it has already
    *                                       been set on the channel by a protocol
    *                                       handler.
    * @param aLoadReplace         - If set LOAD_REPLACE flag will be set on the
    *                               channel. aOriginalURI is null, this argument is
    *                               ignored.
+   * @param aIsFromProcessingFrameAttributes
+   *          - If this is a load triggered by changing frame attributes.
+   *            See nsILoadInfo.isFromProcessingFrameAttributes
    * @param aReferrer            - Referring URI
    * @param aReferrerPolicy      - Referrer policy
    * @param aTriggeringPrincipal - A non-null principal that initiated that load.
    *                               Please note that this is the principal that is
    *                               used for security checks. If the argument aURI
    *                               is provided by the web, then please do not pass
    *                               a SystemPrincipal as the triggeringPrincipal.
    * @param aPrincipalToInherit  - Principal to be inherited for that load. If this
@@ -179,16 +182,17 @@ interface nsIDocShell : nsIDocShellTreeI
    *                               srcdoc loads as it cannot otherwise be inferred
    *                               in certain situations such as view-source.
    */
   [noscript]void internalLoad(in nsIURI aURI,
                               in nsIURI aOriginalURI,
                               [const] in MaybeURI aResultPrincipalURI,
                               in bool aKeepResultPrincipalURIIfSet,
                               in boolean aLoadReplace,
+                              in boolean aIsFromProcessingFrameAttributes,
                               in nsIURI aReferrer,
                               in unsigned long aReferrerPolicy,
                               in nsIPrincipal aTriggeringPrincipal,
                               in nsIPrincipal aPrincipalToInherit,
                               in uint32_t aFlags,
                               in AString aWindowTarget,
                               in ACString aTypeHint,
                               in AString aFileName,
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -934,17 +934,16 @@ nsContentPermissionRequestProxy::Cancel(
   // being destroyed and PContentPermissionRequest will soon be.
   if (mParent->IsBeingDestroyed()) {
     return NS_ERROR_FAILURE;
   }
 
   nsTArray<PermissionChoice> emptyChoices;
 
   Unused << mParent->SendNotifyResult(false, emptyChoices);
-  mParent = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
 {
   if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
@@ -958,17 +957,16 @@ nsContentPermissionRequestProxy::Allow(J
 
   nsTArray<PermissionChoice> choices;
   nsresult rv = TranslateChoices(aChoices, mPermissionRequests, choices);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   Unused << mParent->SendNotifyResult(true, choices);
-  mParent = nullptr;
   return NS_OK;
 }
 
 void
 nsContentPermissionRequestProxy::NotifyVisibility(const bool& aIsVisible)
 {
   MOZ_ASSERT(mRequester);
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -459,16 +459,18 @@ nsFrameLoader::ReallyStartLoadingInterna
   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
 
   // Flags for browser frame:
   if (OwnerIsMozBrowserFrame()) {
     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
   }
 
+  loadState->SetIsFromProcessingFrameAttributes();
+
   // Kick off the load...
   bool tmpState = mNeedsAsyncDestroy;
   mNeedsAsyncDestroy = true;
   loadState->SetURI(mURIToLoad);
   loadState->SetLoadFlags(flags);
   loadState->SetFirstParty(false);
   rv = mDocShell->LoadURI(loadState);
   mNeedsAsyncDestroy = tmpState;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/unit/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/xpcshell-test",
+  ],
+};
new file mode 100644
--- /dev/null
+++ b/dom/base/test/unit_ipc/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/xpcshell-test",
+  ],
+};
new file mode 100644
--- /dev/null
+++ b/dom/file/tests/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+    "plugin:mozilla/xpcshell-test"
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/filesystem/tests/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/chrome-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/grid/test/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/chrome-test",
+  ]
+};
--- a/dom/html/reftests/reftest.list
+++ b/dom/html/reftests/reftest.list
@@ -39,17 +39,17 @@ skip-if(Android) == 649134-2.html 649134
 == image-load-shortcircuit-1.html image-load-shortcircuit-ref.html
 == image-load-shortcircuit-2.html image-load-shortcircuit-ref.html
 
 # Test that image documents taken into account CSS properties like
 # image-orientation when determining the size of the image.
 # (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
 # The vast majority of the fuzziness comes from Linux and WinXP.)
 fuzzy(0-1,0-149) == bug917595-iframe-1.html    bug917595-1-ref.html
-fuzzy(0-3,0-640) fuzzy-if(skiaContent,0-3,0-7544) fuzzy-if(webrender,2-3,3187-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
+fuzzy(0-3,0-640) fuzzy-if(skiaContent,0-3,0-7544) fuzzy-if(webrender,2-3,3092-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
 
 # Test support for SVG-as-image in <picture> elements.
 == bug1106522-1.html bug1106522-ref.html
 == bug1106522-2.html bug1106522-ref.html
 
 == href-attr-change-restyles.html href-attr-change-restyles-ref.html
 == figure.html figure-ref.html
 == pre-1.html pre-1-ref.html
new file mode 100644
--- /dev/null
+++ b/dom/html/test/.eslintrc.js
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/chrome-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/chrome-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/ipc/tests/.eslintrc.js
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/mochitest-test",
+    "plugin:mozilla/xpcshell-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/jsurl/test/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+  ]
+};
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -26,11 +26,11 @@ deprecation_learn_more=Learn More.
 
 # GMP Plugins
 gmp_license_info=License information
 gmp_privacy_info=Privacy Information
 
 openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
 openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit http://www.openh264.org/ to view the codec source code and learn more about the implementation.
 
-cdm_description=Play back protected web video.
+cdm_description2=This plugin enables playback of encrypted media in compliance with the Encrypted Media Extensions specification. Encrypted media is typically used by sites to protect against copying of premium media content. Visit https://www.w3.org/TR/encrypted-media/ for more information on Encrypted Media Extensions.
 
 widevine_description=Widevine Content Decryption Module provided by Google Inc.
new file mode 100644
--- /dev/null
+++ b/dom/manifest/test/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -699,16 +699,18 @@ void AudioBufferSourceNode::Start(double
   if (mBuffer) {
     SendOffsetAndDurationParametersToStream(ns);
   }
 
   // Don't set parameter unnecessarily
   if (aWhen > 0.0) {
     ns->SetDoubleParameter(START, aWhen);
   }
+
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void AudioBufferSourceNode::Start(double aWhen, ErrorResult& aRv) {
   Start(aWhen, 0 /* offset */, Optional<double>(), aRv);
 }
 
 void AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx) {
   AudioNodeStream* ns = mStream;
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -59,16 +59,17 @@
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
 #include "IIRFilterNode.h"
 #include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "MediaStreamAudioSourceNode.h"
 #include "MediaStreamGraph.h"
 #include "nsContentUtils.h"
+#include "nsIScriptError.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsRFPService.h"
 #include "OscillatorNode.h"
 #include "PannerNode.h"
 #include "PeriodicWave.h"
@@ -146,63 +147,96 @@ AudioContext::AudioContext(nsPIDOMWindow
       mSampleRate(GetSampleRateForAudioContext(aIsOffline, aSampleRate)),
       mAudioContextState(AudioContextState::Suspended),
       mNumberOfChannels(aNumberOfChannels),
       mIsOffline(aIsOffline),
       mIsStarted(!aIsOffline),
       mIsShutDown(false),
       mCloseCalled(false),
       mSuspendCalled(false),
-      mIsDisconnecting(false) {
+      mIsDisconnecting(false),
+      mWasAllowedToStart(true) {
   bool mute = aWindow->AddAudioContext(this);
 
   // Note: AudioDestinationNode needs an AudioContext that must already be
   // bound to the window.
-  bool allowedToStart = AutoplayPolicy::IsAllowedToPlay(*this);
+  const bool allowedToStart = AutoplayPolicy::IsAllowedToPlay(*this);
   mDestination = new AudioDestinationNode(this, aIsOffline, allowedToStart,
                                           aNumberOfChannels, aLength);
 
   // The context can't be muted until it has a destination.
   if (mute) {
     Mute();
   }
 
+  // If an AudioContext is not allowed to start, we would postpone its state
+  // transition from `suspended` to `running` until sites explicitly call
+  // AudioContext.resume() or AudioScheduledSourceNode.start().
   if (!allowedToStart) {
-    // Not allowed to start, delay the transition from `suspended` to `running`.
+    AUTOPLAY_LOG("AudioContext %p is not allowed to start", this);
+    mWasAllowedToStart = false;
     SuspendInternal(nullptr);
-    EnsureAutoplayRequested();
+    DispatchBlockedEvent();
   }
 
   FFTBlock::MainThreadInit();
 }
 
+void AudioContext::NotifyScheduledSourceNodeStarted() {
+  MOZ_ASSERT(NS_IsMainThread());
+  // Only try to start AudioContext when AudioContext was not allowed to start.
+  if (mWasAllowedToStart) {
+    return;
+  }
+
+  const bool isAllowedToPlay = AutoplayPolicy::IsAllowedToPlay(*this);
+  AUTOPLAY_LOG("Trying to start AudioContext %p, IsAllowedToPlay=%d",
+               this, isAllowedToPlay);
+  if (isAllowedToPlay) {
+    ResumeInternal();
+  } else {
+    EnsureAutoplayRequested();
+  }
+}
+
 void AudioContext::EnsureAutoplayRequested() {
   nsPIDOMWindowInner* parent = GetParentObject();
   if (!parent || !parent->AsGlobal()) {
     return;
   }
 
   RefPtr<AutoplayPermissionManager> request =
       AutoplayPolicy::RequestFor(*(parent->GetExtantDoc()));
   if (!request) {
     return;
   }
 
+  AUTOPLAY_LOG("AudioContext %p EnsureAutoplayRequested %p",
+               this, request.get());
   RefPtr<AudioContext> self = this;
   request->RequestWithPrompt()->Then(
       parent->AsGlobal()->AbstractMainThreadFor(TaskCategory::Other), __func__,
       [self, request](bool aApproved) {
         AUTOPLAY_LOG("%p Autoplay request approved request=%p", self.get(),
                      request.get());
+        self->mWasAllowedToStart = true;
         self->ResumeInternal();
       },
       [self, request](nsresult aError) {
         AUTOPLAY_LOG("%p Autoplay request denied request=%p", self.get(),
                      request.get());
+        self->mWasAllowedToStart = false;
         self->DispatchBlockedEvent();
+        nsIDocument* doc = self->GetParentObject() ?
+            self->GetParentObject()->GetExtantDoc() : nullptr;
+        nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                        NS_LITERAL_CSTRING("Media"),
+                                        doc,
+                                        nsContentUtils::eDOM_PROPERTIES,
+                                        "BlockAutoplayError");
       });
 }
 
 nsresult AudioContext::Init() {
   if (!mIsOffline) {
     nsresult rv = mDestination->CreateAudioChannelAgent();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -938,28 +972,30 @@ already_AddRefed<Promise> AudioContext::
   if (mAudioContextState == AudioContextState::Closed || mCloseCalled) {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
 
   mPendingResumePromises.AppendElement(promise);
 
   const bool isAllowedToPlay = AutoplayPolicy::IsAllowedToPlay(*this);
+  AUTOPLAY_LOG("Trying to resume AudioContext %p, IsAllowedToPlay=%d",
+               this, isAllowedToPlay);
   if (isAllowedToPlay) {
+    mWasAllowedToStart = true;
     ResumeInternal();
-  } else {
-    DispatchBlockedEvent();
+  } else if (!isAllowedToPlay && !mWasAllowedToStart) {
+    EnsureAutoplayRequested();
   }
 
-  AUTOPLAY_LOG("Resume AudioContext %p, IsAllowedToPlay=%d", this,
-               isAllowedToPlay);
   return promise.forget();
 }
 
 void AudioContext::ResumeInternal() {
+  AUTOPLAY_LOG("Allow to resume AudioContext %p", this);
   Destination()->Resume();
 
   nsTArray<MediaStream*> streams;
   // If mSuspendCalled is false then we already resumed all our streams,
   // so don't resume them again (since suspend(); resume(); resume(); should
   // be OK). But we still need to do ApplyAudioContextOperation
   // to ensure our new promise is resolved.
   if (mSuspendCalled) {
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -178,16 +178,20 @@ class AudioContext final : public DOMEve
   AudioListener* Listener();
 
   AudioContextState State() const { return mAudioContextState; }
 
   Worklet* GetAudioWorklet(ErrorResult& aRv);
 
   bool IsRunning() const;
 
+  // Called when an AudioScheduledSourceNode started, this method might resume
+  // the AudioContext if it was not allowed to start.
+  void NotifyScheduledSourceNodeStarted();
+
   // Those three methods return a promise to content, that is resolved when an
   // (possibly long) operation is completed on the MSG (and possibly other)
   // thread(s). To avoid having to match the calls and asychronous result when
   // the operation is completed, we keep a reference to the promises on the main
   // thread, and then send the promises pointers down the MSG thread, as a void*
   // (to make it very clear that the pointer is to merely be treated as an ID).
   // When back on the main thread, we can resolve or reject the promise, by
   // casting it back to a `Promise*` while asserting we're back on the main
@@ -357,16 +361,18 @@ class AudioContext final : public DOMEve
   bool mIsOffline;
   bool mIsStarted;
   bool mIsShutDown;
   // Close has been called, reject suspend and resume call.
   bool mCloseCalled;
   // Suspend has been called with no following resume.
   bool mSuspendCalled;
   bool mIsDisconnecting;
+  // This flag stores the value of previous status of `allowed-to-start`.
+  bool mWasAllowedToStart;
 };
 
 static const dom::AudioContext::AudioContextId NO_AUDIO_CONTEXT = 0;
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif
--- a/dom/media/webaudio/ConstantSourceNode.cpp
+++ b/dom/media/webaudio/ConstantSourceNode.cpp
@@ -219,16 +219,17 @@ void ConstantSourceNode::Start(double aW
   if (!mStream) {
     return;
   }
 
   mStream->SetStreamTimeParameter(ConstantSourceNodeEngine::START, Context(),
                                   aWhen);
 
   MarkActive();
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void ConstantSourceNode::Stop(double aWhen, ErrorResult& aRv) {
   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(NS_LITERAL_STRING("stop time"));
     return;
   }
 
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -483,16 +483,17 @@ void OscillatorNode::Start(double aWhen,
     return;
   }
 
   // TODO: Perhaps we need to do more here.
   mStream->SetStreamTimeParameter(OscillatorNodeEngine::START, Context(),
                                   aWhen);
 
   MarkActive();
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void OscillatorNode::Stop(double aWhen, ErrorResult& aRv) {
   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
new file mode 100644
--- /dev/null
+++ b/dom/notification/test/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/notification/test/chrome/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/chrome-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/notification/test/mochitest/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/.eslintrc.js
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/chrome-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/svg/test/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/system/tests/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/chrome-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+  ]
+};
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RemoteWorkerChild.h"
 #include "RemoteWorkerService.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/dom/ServiceWorkerInterceptController.h"
+#include "mozilla/dom/ServiceWorkerUtils.h"
 #include "mozilla/dom/workerinternals/ScriptLoader.h"
 #include "mozilla/dom/WorkerError.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "nsIConsoleReportCollector.h"
@@ -82,25 +83,29 @@ PopulatePrincipalContentSecurityPolicy(n
 }
 
 class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
 {
 public:
   NS_DECL_ISUPPORTS
 
   SharedWorkerInterfaceRequestor()
-    : mSWController(new ServiceWorkerInterceptController())
-  {}
+  {
+    // This check must match the code nsDocShell::Create.
+    if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
+      mSWController = new ServiceWorkerInterceptController();
+    }
+  }
 
   NS_IMETHOD
   GetInterface(const nsIID& aIID, void** aSink) override
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
+    if (mSWController && aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
       // If asked for the network intercept controller, ask the outer requestor,
       // which could be the docshell.
       RefPtr<ServiceWorkerInterceptController> swController = mSWController;
       swController.forget(aSink);
       return NS_OK;
     }
 
     return NS_NOINTERFACE;
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -137,18 +137,17 @@ WebRenderLayerScrollData::Dump(const Web
   printf_stderr("LayerScrollData(%p) descendants %d\n", this, mDescendantCount);
   for (size_t i : mScrollIds) {
     printf_stderr("  metadata: %s\n", Stringify(aOwner.GetScrollMetadata(i)).c_str());
   }
   printf_stderr("  ancestor transform: %s\n", Stringify(mAncestorTransform).c_str());
   printf_stderr("  transform: %s perspective: %d visible: %s\n",
     Stringify(mTransform).c_str(), mTransformIsPerspective,
     Stringify(mVisibleRegion).c_str());
-  printf_stderr("  event regions: %s override: 0x%x\n",
-    Stringify(mEventRegions).c_str(), mEventRegionsOverride);
+  printf_stderr("  event regions override: 0x%x\n", mEventRegionsOverride);
   if (mReferentId) {
     printf_stderr("  ref layers id: 0x%" PRIx64 "\n", uint64_t(*mReferentId));
   }
   printf_stderr("  scrollbar type: %d animation: %" PRIx64 "\n",
     (int)mScrollbarData.mScrollbarLayerType, mScrollbarAnimationId);
   printf_stderr("  fixed pos container: %" PRIu64 "\n",
     mFixedPosScrollContainerId);
 }
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -64,18 +64,17 @@ public:
 
   gfx::Matrix4x4 GetAncestorTransform() const { return mAncestorTransform; }
   void SetTransform(const gfx::Matrix4x4& aTransform) { mTransform = aTransform; }
   gfx::Matrix4x4 GetTransform() const { return mTransform; }
   CSSTransformMatrix GetTransformTyped() const;
   void SetTransformIsPerspective(bool aTransformIsPerspective) { mTransformIsPerspective = aTransformIsPerspective; }
   bool GetTransformIsPerspective() const { return mTransformIsPerspective; }
 
-  void AddEventRegions(const EventRegions& aRegions) { mEventRegions.OrWith(aRegions); }
-  EventRegions GetEventRegions() const { return mEventRegions; }
+  EventRegions GetEventRegions() const { return EventRegions(); }
   void SetEventRegionsOverride(const EventRegionsOverride& aOverride) { mEventRegionsOverride = aOverride; }
   EventRegionsOverride GetEventRegionsOverride() const { return mEventRegionsOverride; }
 
   void SetVisibleRegion(const LayerIntRegion& aRegion) { mVisibleRegion = aRegion; }
   const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   void SetReferentId(LayersId aReferentId) { mReferentId = Some(aReferentId); }
   Maybe<LayersId> GetReferentId() const { return mReferentId; }
 
@@ -108,17 +107,16 @@ private:
   nsTArray<size_t> mScrollIds;
 
   // Various data that we collect from the Layer in Initialize(), serialize
   // over IPC, and use on the parent side in APZ.
 
   gfx::Matrix4x4 mAncestorTransform;
   gfx::Matrix4x4 mTransform;
   bool mTransformIsPerspective;
-  EventRegions mEventRegions;
   LayerIntRegion mVisibleRegion;
   Maybe<LayersId> mReferentId;
   EventRegionsOverride mEventRegionsOverride;
   ScrollbarData mScrollbarData;
   uint64_t mScrollbarAnimationId;
   ScrollableLayerGuid::ViewID mFixedPosScrollContainerId;
   Maybe<uint64_t> mZoomAnimationId;
 };
@@ -229,17 +227,16 @@ struct ParamTraits<mozilla::layers::WebR
   static void
   Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mDescendantCount);
     WriteParam(aMsg, aParam.mScrollIds);
     WriteParam(aMsg, aParam.mAncestorTransform);
     WriteParam(aMsg, aParam.mTransform);
     WriteParam(aMsg, aParam.mTransformIsPerspective);
-    WriteParam(aMsg, aParam.mEventRegions);
     WriteParam(aMsg, aParam.mVisibleRegion);
     WriteParam(aMsg, aParam.mReferentId);
     WriteParam(aMsg, aParam.mEventRegionsOverride);
     WriteParam(aMsg, aParam.mScrollbarData);
     WriteParam(aMsg, aParam.mScrollbarAnimationId);
     WriteParam(aMsg, aParam.mFixedPosScrollContainerId);
     WriteParam(aMsg, aParam.mZoomAnimationId);
   }
@@ -247,17 +244,16 @@ struct ParamTraits<mozilla::layers::WebR
   static bool
   Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mDescendantCount)
         && ReadParam(aMsg, aIter, &aResult->mScrollIds)
         && ReadParam(aMsg, aIter, &aResult->mAncestorTransform)
         && ReadParam(aMsg, aIter, &aResult->mTransform)
         && ReadParam(aMsg, aIter, &aResult->mTransformIsPerspective)
-        && ReadParam(aMsg, aIter, &aResult->mEventRegions)
         && ReadParam(aMsg, aIter, &aResult->mVisibleRegion)
         && ReadParam(aMsg, aIter, &aResult->mReferentId)
         && ReadParam(aMsg, aIter, &aResult->mEventRegionsOverride)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarData)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarAnimationId)
         && ReadParam(aMsg, aIter, &aResult->mFixedPosScrollContainerId)
         && ReadParam(aMsg, aIter, &aResult->mZoomAnimationId);
   }
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -448,17 +448,18 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
       ipcInitialClientInfo,
       ipcController,
       aLoadInfo->CorsUnsafeHeaders(),
       aLoadInfo->GetForcePreflight(),
       aLoadInfo->GetIsPreflight(),
       aLoadInfo->GetLoadTriggeredFromExternal(),
       aLoadInfo->GetServiceWorkerTaintingSynthesized(),
       aLoadInfo->GetDocumentHasUserInteracted(),
-      aLoadInfo->GetDocumentHasLoaded()
+      aLoadInfo->GetDocumentHasLoaded(),
+      aLoadInfo->GetIsFromProcessingFrameAttributes()
       );
 
   return NS_OK;
 }
 
 nsresult
 LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
                        nsILoadInfo** outLoadInfo)
@@ -566,17 +567,17 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
                  initialClientInfo.isNothing(), NS_ERROR_UNEXPECTED);
 
   Maybe<ServiceWorkerDescriptor> controller;
   if (loadInfoArgs.controller().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     controller.emplace(ServiceWorkerDescriptor(
       loadInfoArgs.controller().get_IPCServiceWorkerDescriptor()));
   }
 
-  nsCOMPtr<nsILoadInfo> loadInfo =
+  RefPtr<mozilla::LoadInfo> loadInfo =
     new mozilla::LoadInfo(loadingPrincipal,
                           triggeringPrincipal,
                           principalToInherit,
                           sandboxedLoadingPrincipal,
                           topLevelPrincipal,
                           topLevelStorageAreaPrincipal,
                           resultPrincipalURI,
                           clientInfo,
@@ -614,16 +615,20 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
                           loadInfoArgs.forcePreflight(),
                           loadInfoArgs.isPreflight(),
                           loadInfoArgs.loadTriggeredFromExternal(),
                           loadInfoArgs.serviceWorkerTaintingSynthesized(),
                           loadInfoArgs.documentHasUserInteracted(),
                           loadInfoArgs.documentHasLoaded()
                           );
 
+  if (loadInfoArgs.isFromProcessingFrameAttributes()) {
+    loadInfo->SetIsFromProcessingFrameAttributes();
+  }
+
    loadInfo.forget(outLoadInfo);
    return NS_OK;
 }
 
 void
 LoadInfoToParentLoadInfoForwarder(nsILoadInfo* aLoadInfo,
                                   ParentLoadInfoForwarderArgs* aForwarderArgsOut)
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2316,16 +2316,17 @@ CASE(JSOP_LOOPHEAD)
     COUNT_COVERAGE();
     ADVANCE_AND_DISPATCH(1);
 }
 
 CASE(JSOP_LABEL)
 END_CASE(JSOP_LABEL)
 
 CASE(JSOP_LOOPENTRY)
+{
     COUNT_COVERAGE();
     // Attempt on-stack replacement with Baseline code.
     if (jit::IsBaselineEnabled(cx)) {
         jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp());
         if (status == jit::Method_Error) {
             goto error;
         }
         if (status == jit::Method_Compiled) {
@@ -2355,75 +2356,90 @@ CASE(JSOP_LOOPENTRY)
                 goto jit_return_pop_frame;
             }
             goto leave_on_safe_point;
         }
     }
     if (script->trackRecordReplayProgress()) {
         mozilla::recordreplay::AdvanceExecutionProgressCounter();
     }
+}
 END_CASE(JSOP_LOOPENTRY)
 
 CASE(JSOP_LINENO)
 END_CASE(JSOP_LINENO)
 
 CASE(JSOP_FORCEINTERPRETER)
 END_CASE(JSOP_FORCEINTERPRETER)
 
 CASE(JSOP_UNDEFINED)
+{
     // If this ever changes, change what JSOP_GIMPLICITTHIS does too.
     PUSH_UNDEFINED();
+}
 END_CASE(JSOP_UNDEFINED)
 
 CASE(JSOP_POP)
+{
     REGS.sp--;
+}
 END_CASE(JSOP_POP)
 
 CASE(JSOP_POPN)
+{
     MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
     REGS.sp -= GET_UINT16(REGS.pc);
+
+}
 END_CASE(JSOP_POPN)
 
 CASE(JSOP_DUPAT)
 {
     MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
     unsigned i = GET_UINT24(REGS.pc);
     const Value& rref = REGS.sp[-int(i + 1)];
     PUSH_COPY(rref);
 }
 END_CASE(JSOP_DUPAT)
 
 CASE(JSOP_SETRVAL)
+{
     POP_RETURN_VALUE();
+}
 END_CASE(JSOP_SETRVAL)
 
 CASE(JSOP_GETRVAL)
+{
     PUSH_COPY(REGS.fp()->returnValue());
+}
 END_CASE(JSOP_GETRVAL)
 
 CASE(JSOP_ENTERWITH)
 {
     ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
     REGS.sp--;
     ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
 
     if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
         goto error;
     }
 }
 END_CASE(JSOP_ENTERWITH)
 
 CASE(JSOP_LEAVEWITH)
+{
     REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
+}
 END_CASE(JSOP_LEAVEWITH)
 
 CASE(JSOP_RETURN)
+{
     POP_RETURN_VALUE();
     /* FALL THROUGH */
-
+}
 CASE(JSOP_RETRVAL)
 {
     /*
      * When the inlined frame exits with an exception or an error, ok will be
      * false after the inline_return label.
      */
     CHECK_BRANCH();
 
@@ -2473,18 +2489,20 @@ CASE(JSOP_RETRVAL)
         goto error;
     } else {
         MOZ_ASSERT(REGS.stackDepth() == 0);
     }
     goto exit;
 }
 
 CASE(JSOP_DEFAULT)
+{
     REGS.sp--;
     /* FALL THROUGH */
+}
 CASE(JSOP_GOTO)
 {
     BRANCH(GET_JUMP_OFFSET(REGS.pc));
 }
 
 CASE(JSOP_IFEQ)
 {
     bool cond = ToBoolean(REGS.stackHandleAt(-1));
@@ -2745,25 +2763,29 @@ CASE(JSOP_BITAND)
     if (!BitAnd(cx, lhs, rhs, res)) {
         goto error;
     }
     REGS.sp--;
 }
 END_CASE(JSOP_BITAND)
 
 CASE(JSOP_EQ)
+{
     if (!LooseEqualityOp<true>(cx, REGS)) {
         goto error;
     }
+}
 END_CASE(JSOP_EQ)
 
 CASE(JSOP_NE)
+{
     if (!LooseEqualityOp<false>(cx, REGS)) {
         goto error;
     }
+}
 END_CASE(JSOP_NE)
 
 #define STRICT_EQUALITY_OP(OP, COND)                                          \
     JS_BEGIN_MACRO                                                            \
         HandleValue lval = REGS.stackHandleAt(-2);                            \
         HandleValue rval = REGS.stackHandleAt(-1);                            \
         bool equal;                                                           \
         if (!StrictlyEqual(cx, lval, rval, &equal))                           \
@@ -2989,19 +3011,21 @@ CASE(JSOP_NEG)
     MutableHandleValue res = REGS.stackHandleAt(-1);
     if (!NegOperation(cx, &val, res)) {
         goto error;
     }
 }
 END_CASE(JSOP_NEG)
 
 CASE(JSOP_POS)
+{
     if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
         goto error;
     }
+}
 END_CASE(JSOP_POS)
 
 CASE(JSOP_DELNAME)
 {
     ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
     ReservedRooted<JSObject*> envObj(&rootObject0, REGS.fp()->environmentChain());
 
     PUSH_BOOLEAN(true);
@@ -3081,24 +3105,28 @@ END_CASE(JSOP_TOID)
 CASE(JSOP_TYPEOFEXPR)
 CASE(JSOP_TYPEOF)
 {
     REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
 }
 END_CASE(JSOP_TYPEOF)
 
 CASE(JSOP_VOID)
+{
     REGS.sp[-1].setUndefined();
+}
 END_CASE(JSOP_VOID)
 
 CASE(JSOP_FUNCTIONTHIS)
+{
     PUSH_NULL();
     if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
         goto error;
     }
+}
 END_CASE(JSOP_FUNCTIONTHIS)
 
 CASE(JSOP_GLOBALTHIS)
 {
     if (script->hasNonSyntacticScope()) {
         PUSH_NULL();
         GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(), REGS.stackHandleAt(-1));
     } else {
@@ -3376,20 +3404,22 @@ CASE(JSOP_STRICTEVAL)
     REGS.sp = args.spAfterCall();
     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 CASE(JSOP_SPREADNEW)
 CASE(JSOP_SPREADCALL)
 CASE(JSOP_SPREADSUPERCALL)
+{
     if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
         cx->geckoProfiler().updatePC(cx, script, REGS.pc);
     }
     /* FALL THROUGH */
+}
 
 CASE(JSOP_SPREADEVAL)
 CASE(JSOP_STRICTSPREADEVAL)
 {
     static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
                   "spreadeval and strictspreadeval must be the same size");
     bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW || JSOp(*REGS.pc) == JSOP_SPREADSUPERCALL;;
 
@@ -3639,42 +3669,52 @@ CASE(JSOP_GETINTRINSIC)
     }
 
     PUSH_COPY(rval);
     TypeScript::Monitor(cx, script, REGS.pc, rval);
 }
 END_CASE(JSOP_GETINTRINSIC)
 
 CASE(JSOP_UINT16)
+{
     PUSH_INT32((int32_t) GET_UINT16(REGS.pc));
+}
 END_CASE(JSOP_UINT16)
 
 CASE(JSOP_UINT24)
 CASE(JSOP_RESUMEINDEX)
+{
     PUSH_INT32((int32_t) GET_UINT24(REGS.pc));
+}
 END_CASE(JSOP_UINT24)
 
 CASE(JSOP_INT8)
+{
     PUSH_INT32(GET_INT8(REGS.pc));
+}
 END_CASE(JSOP_INT8)
 
 CASE(JSOP_INT32)
+{
     PUSH_INT32(GET_INT32(REGS.pc));
+}
 END_CASE(JSOP_INT32)
 
 CASE(JSOP_DOUBLE)
 {
     double dbl;
     LOAD_DOUBLE(0, dbl);
     PUSH_DOUBLE(dbl);
 }
 END_CASE(JSOP_DOUBLE)
 
 CASE(JSOP_STRING)
+{
     PUSH_STRING(script->getAtom(REGS.pc));
+}
 END_CASE(JSOP_STRING)
 
 CASE(JSOP_TOSTRING)
 {
     MutableHandleValue oper = REGS.stackHandleAt(-1);
 
     if (!oper.isString()) {
         JSString* operString = ToString<CanGC>(cx, oper);
@@ -3682,17 +3722,19 @@ CASE(JSOP_TOSTRING)
             goto error;
         }
         oper.setString(operString);
     }
 }
 END_CASE(JSOP_TOSTRING)
 
 CASE(JSOP_SYMBOL)
+{
     PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
+}
 END_CASE(JSOP_SYMBOL)
 
 CASE(JSOP_OBJECT)
 {
     ReservedRooted<JSObject*> ref(&rootObject0, script->getObject(REGS.pc));
     if (cx->realm()->creationOptions().cloneSingletons()) {
         JSObject* obj = DeepCloneObjectLiteral(cx, ref, TenuredObject);
         if (!obj) {
@@ -3730,33 +3772,43 @@ CASE(JSOP_REGEXP)
     if (!obj) {
         goto error;
     }
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_REGEXP)
 
 CASE(JSOP_ZERO)
+{
     PUSH_INT32(0);
+}
 END_CASE(JSOP_ZERO)
 
 CASE(JSOP_ONE)
+{
     PUSH_INT32(1);
+}
 END_CASE(JSOP_ONE)
 
 CASE(JSOP_NULL)
+{
     PUSH_NULL();
+}
 END_CASE(JSOP_NULL)
 
 CASE(JSOP_FALSE)
+{
     PUSH_BOOLEAN(false);
+}
 END_CASE(JSOP_FALSE)
 
 CASE(JSOP_TRUE)
+{
     PUSH_BOOLEAN(true);
+}
 END_CASE(JSOP_TRUE)
 
 CASE(JSOP_TABLESWITCH)
 {
     jsbytecode* pc2 = REGS.pc;
     int32_t len = GET_JUMP_OFFSET(pc2);
 
     /*
@@ -3783,28 +3835,30 @@ CASE(JSOP_TABLESWITCH)
     i = uint32_t(i) - uint32_t(low);
     if (uint32_t(i) < uint32_t(high - low + 1)) {
         len = script->tableSwitchCaseOffset(REGS.pc, uint32_t(i)) - script->pcToOffset(REGS.pc);
     }
     ADVANCE_AND_DISPATCH(len);
 }
 
 CASE(JSOP_ARGUMENTS)
+{
     if (!script->ensureHasAnalyzedArgsUsage(cx)) {
         goto error;
     }
     if (script->needsArgsObj()) {
         ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
         if (!obj) {
             goto error;
         }
         PUSH_COPY(ObjectValue(*obj));
     } else {
         PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
     }
+}
 END_CASE(JSOP_ARGUMENTS)
 
 CASE(JSOP_RUNONCE)
 {
     if (!RunOnceScriptPrologue(cx, script)) {
         goto error;
     }
 }
@@ -3900,17 +3954,19 @@ CASE(JSOP_INITGLEXICAL)
         lexicalEnv = &cx->global()->lexicalEnvironment();
     }
     HandleValue value = REGS.stackHandleAt(-1);
     InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
 }
 END_CASE(JSOP_INITGLEXICAL)
 
 CASE(JSOP_UNINITIALIZED)
+{
     PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL);
+}
 END_CASE(JSOP_UNINITIALIZED)
 
 CASE(JSOP_GETARG)
 {
     unsigned i = GET_ARGNO(REGS.pc);
     if (script->argsObjAliasesFormals()) {
         PUSH_COPY(REGS.fp()->argsObj().arg(i));
     } else {
@@ -4117,18 +4173,20 @@ CASE(JSOP_SETFUNNAME)
         goto error;
     }
 
     REGS.sp--;
 }
 END_CASE(JSOP_SETFUNNAME)
 
 CASE(JSOP_CALLEE)
+{
     MOZ_ASSERT(REGS.fp()->isFunctionFrame());
     PUSH_COPY(REGS.fp()->calleev());
+}
 END_CASE(JSOP_CALLEE)
 
 CASE(JSOP_INITPROP_GETTER)
 CASE(JSOP_INITHIDDENPROP_GETTER)
 CASE(JSOP_INITPROP_SETTER)
 CASE(JSOP_INITHIDDENPROP_SETTER)
 {
     MOZ_ASSERT(REGS.stackDepth() >= 2);
@@ -4160,17 +4218,19 @@ CASE(JSOP_INITHIDDENELEM_SETTER)
         goto error;
     }
 
     REGS.sp -= 2;
 }
 END_CASE(JSOP_INITELEM_GETTER)
 
 CASE(JSOP_HOLE)
+{
     PUSH_MAGIC(JS_ELEMENTS_HOLE);
+}
 END_CASE(JSOP_HOLE)
 
 CASE(JSOP_NEWINIT)
 {
     JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
 
     if (!obj) {
         goto error;
@@ -4347,17 +4407,19 @@ CASE(JSOP_EXCEPTION)
     MutableHandleValue res = REGS.stackHandleAt(-1);
     if (!GetAndClearException(cx, res)) {
         goto error;
     }
 }
 END_CASE(JSOP_EXCEPTION)
 
 CASE(JSOP_FINALLY)
+{
     CHECK_BRANCH();
+}
 END_CASE(JSOP_FINALLY)
 
 CASE(JSOP_THROW)
 {
     CHECK_BRANCH();
     ReservedRooted<Value> v(&rootValue0);
     POP_COPY_TO(v);
     MOZ_ALWAYS_FALSE(Throw(cx, v));
@@ -4692,18 +4754,20 @@ CASE(JSOP_SUPERBASE)
         goto error;
     }
 
     PUSH_OBJECT(*superBase);
 }
 END_CASE(JSOP_SUPERBASE)
 
 CASE(JSOP_NEWTARGET)
+{
     PUSH_COPY(REGS.fp()->newTarget());
     MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
+}
 END_CASE(JSOP_NEWTARGET)
 
 CASE(JSOP_IMPORTMETA)
 {
     ReservedRooted<JSObject*> module(&rootObject0, GetModuleObjectForScript(script));
     MOZ_ASSERT(module);
 
     JSObject* metaObject = GetOrCreateModuleMetaObject(cx, module);
@@ -4784,17 +4848,19 @@ CASE(JSOP_DEBUGCHECKSELFHOSTED)
     if (!Debug_CheckSelfHosted(cx, checkVal)) {
         goto error;
     }
 #endif
 }
 END_CASE(JSOP_DEBUGCHECKSELFHOSTED)
 
 CASE(JSOP_IS_CONSTRUCTING)
+{
     PUSH_MAGIC(JS_IS_CONSTRUCTING);
+}
 END_CASE(JSOP_IS_CONSTRUCTING)
 
 #ifdef ENABLE_BIGINT
 CASE(JSOP_BIGINT)
 {
     PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc)));
     MOZ_ASSERT(REGS.sp[-1].isBigInt());
 }
--- a/layout/reftests/backgrounds/gradient/reftest.list
+++ b/layout/reftests/backgrounds/gradient/reftest.list
@@ -1,3 +1,3 @@
 == scaled-color-stop-position.html scaled-color-stop-position-ref.html
-== color-stop-clamp-interpolation.html color-stop-clamp-interpolation-ref.html
+fuzzy-if(webrender&&winWidget,0-1,0-387) == color-stop-clamp-interpolation.html color-stop-clamp-interpolation-ref.html
 fuzzy-if(webrender&&cocoaWidget,1-1,191-191) == linear-gradient-repeated.html linear-gradient-repeated-ref.html
--- 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,0-1,0-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,975-986) == 470250-1.html 470250-1-ref.html
-fuzzy-if(webrender,15-233,975-1073) == 470250-2.html 470250-2-ref.html
+fuzzy-if(webrender,15-15,975-1000) == 470250-1.html 470250-1-ref.html
+fuzzy-if(webrender,15-233,975-1080) == 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) fuzzy-if(webrender&&cocoaWidget,1-1,3280-3280) == center-scaling-2.html center-scaling-2-ref.html # Android: very different scaling (blurriness) on some sides
 fails-if(Android) fails-if(usesRepeatResampling) fuzzy-if(webrender&&cocoaWidget,1-1,4752-4752) == 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
@@ -37,49 +37,49 @@ fails-if(Android) fails-if(usesRepeatRes
 == border-image-nofill-1.html border-image-nofill-1-ref.html
 == border-image-outset-resize-1.html border-image-outset-resize-1-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,0-140,0-514) fuzzy-if(winWidget,0-144,0-448) == border-image-outset-move-1.html border-image-outset-move-1-ref.html
 == border-image-style-none.html border-image-style-none-ref.html
 == border-image-style-none-length.html border-image-style-none-length-ref.html
 == border-image-style-none-auto.html border-image-style-none-auto-ref.html
 
 # border images with gradients
-fuzzy-if(webrender,1-1,1488-1804) == border-image-linear-gradient.html border-image-linear-gradient-ref.html
-fuzzy(0-1,0-98) fuzzy-if(skiaContent,0-1,0-350) fuzzy-if(webrender,1-2,37234-37537) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
-fuzzy(0-1,0-149) fuzzy-if(OSX,0-1,0-10595) fuzzy-if(webrender,1-3,24999-25121) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
-fuzzy(0-1,0-433) fuzzy-if(skiaContent,0-1,0-2500) fuzzy-if(webrender,1-3,84860-85584) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html
-fuzzy(0-1,0-177) fuzzy-if(OSX,0-1,0-25771) fuzzy-if(skiaContent&&!Android,0-1,0-400) fuzzy-if(Android,0-1,0-6093) fuzzy-if(webrender,1-3,57249-57433) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
-fuzzy(0-1,0-48)  fuzzy-if(OSX,0-5,0-1676) fuzzy-if(webrender,1-1,4464-4530) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html
-fuzzy(0-1,0-5000) fuzzy-if(OSX,0-1,0-15000) fuzzy-if(webrender,2-2,58629-58715) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html
-fuzzy(0-1,0-3000) fuzzy-if(OSX,0-1,0-6000) fuzzy-if(webrender,1-1,26067-26353) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html
-fuzzy(0-1,0-12) fuzzy-if(skiaContent,0-1,0-400) fuzzy-if(webrender,1-2,26394-26872) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html
-fuzzy(0-1,0-13) fuzzy-if(skiaContent,0-1,0-300) fuzzy-if(webrender,1-2,26265-27131) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html
-fuzzy-if(webrender,1-2,64826-66334) == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html
-fuzzy(0-1,0-576) fuzzy-if(skiaContent,0-1,0-2000) fuzzy-if(webrender,1-2,64575-66821) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html
-fuzzy(0-1,0-8533) fuzzy-if(webrender,1-2,84604-85925) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
-fuzzy(0-1,0-7161) fuzzy-if(webrender,2-3,92540-92746) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html
+fuzzy-if(webrender,1-3,1488-1804) == border-image-linear-gradient.html border-image-linear-gradient-ref.html
+fuzzy(0-1,0-98) fuzzy-if(skiaContent,0-1,0-350) fuzzy-if(webrender,1-2,37066-37537) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
+fuzzy(0-1,0-149) fuzzy-if(OSX,0-1,0-10595) fuzzy-if(webrender,1-3,24999-25136) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
+fuzzy(0-1,0-433) fuzzy-if(skiaContent,0-1,0-2500) fuzzy-if(webrender,1-3,84138-85584) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html
+fuzzy(0-1,0-177) fuzzy-if(OSX,0-1,0-25771) fuzzy-if(skiaContent&&!Android,0-1,0-400) fuzzy-if(Android,0-1,0-6093) fuzzy-if(webrender,1-3,57249-57464) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
+fuzzy(0-1,0-48)  fuzzy-if(OSX,0-5,0-1676) fuzzy-if(webrender,1-1,4464-4537) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html
+fuzzy(0-1,0-5000) fuzzy-if(OSX,0-1,0-15000) fuzzy-if(webrender,2-2,58629-58936) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html
+fuzzy(0-1,0-3000) fuzzy-if(OSX,0-1,0-6000) fuzzy-if(webrender,1-3,26067-26413) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html
+fuzzy(0-1,0-12) fuzzy-if(skiaContent,0-1,0-400) fuzzy-if(webrender,1-3,26195-26872) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html
+fuzzy(0-1,0-13) fuzzy-if(skiaContent,0-1,0-300) fuzzy-if(webrender,1-3,26168-27131) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html
+fuzzy-if(webrender,1-3,64826-67805) == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html
+fuzzy(0-1,0-576) fuzzy-if(skiaContent,0-1,0-2000) fuzzy-if(webrender,1-2,64575-68383) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html
+fuzzy(0-1,0-8533) fuzzy-if(webrender,1-3,84604-85925) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
+fuzzy(0-1,0-7161) fuzzy-if(webrender,2-3,92540-93290) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html
 
 fuzzy-if(webrender,0-1,0-2096) == border-image-radial-gradient.html border-image-radial-gradient-ref.html
 fuzzy(0-1,0-42) fuzzy-if(skiaContent,0-2,0-20) fuzzy-if(webrender,0-1,0-37818) == border-image-radial-gradient-slice-1.html border-image-radial-gradient-slice-1-ref.html
 fuzzy(0-1,0-46) fuzzy-if(OSX,0-2,0-4472) fuzzy-if(webrender,0-1,0-26363) == border-image-radial-gradient-slice-2.html border-image-radial-gradient-slice-2-ref.html
 fuzzy(0-1,0-105) fuzzy-if(webrender,0-1,0-90873) == border-image-radial-gradient-slice-fill-1.html border-image-radial-gradient-slice-fill-1-ref.html
 fuzzy(0-1,0-139) fuzzy-if(OSX,0-2,0-4478) fuzzy-if(skiaContent,0-2,0-120) fuzzy-if(webrender,0-1,0-61729) == border-image-radial-gradient-slice-fill-2.html border-image-radial-gradient-slice-fill-2-ref.html
 fuzzy-if(skiaContent,0-1,0-2) fuzzy-if(webrender,0-1,0-4894) == border-image-radial-gradient-width.html border-image-radial-gradient-width-ref.html
 fuzzy(0-1,0-9000) fuzzy-if(webrender,0-3,0-66698) == border-image-radial-gradient-slice-width.html border-image-radial-gradient-slice-width-ref.html
 
 # OS X failures tracked in bug 957025
-fuzzy-if(webrender,1-1,1766-1800) == border-image-repeating-linear-gradient.html border-image-repeating-linear-gradient-ref.html
+fuzzy-if(webrender,1-5,1766-1824) == border-image-repeating-linear-gradient.html border-image-repeating-linear-gradient-ref.html
 fuzzy(0-1,0-5608) fails-if(OSX) fuzzy-if(skiaContent,0-1,0-6093) fuzzy-if(webrender,0-3,0-95449) == border-image-repeating-linear-gradient-slice-fill-2.html border-image-repeating-linear-gradient-slice-fill-2-ref.html
-fuzzy(0-1,0-19200) fails-if(OSX) fuzzy-if(skiaContent,0-3,0-20000) fuzzy-if(webrender,3-3,18896-18896) fuzzy-if(webrender,0-2,0-112082) == border-image-repeating-linear-gradient-repeat-round-2.html border-image-repeating-linear-gradient-repeat-round-2-ref.html
+fuzzy(0-1,0-19200) fails-if(OSX) fuzzy-if(skiaContent,0-3,0-20000) fuzzy-if(webrender,3-3,18896-18896) fuzzy-if(webrender,0-4,0-112082) == border-image-repeating-linear-gradient-repeat-round-2.html border-image-repeating-linear-gradient-repeat-round-2-ref.html
 
 fuzzy(0-1,0-657) fuzzy-if(webrender,0-3,0-3008) == border-image-repeating-radial-gradient.html border-image-repeating-radial-gradient-ref.html
 fuzzy(0-1,0-510) fuzzy-if(skiaContent,0-3,0-362) fuzzy-if(webrender,0-3,0-62078) == border-image-repeating-radial-gradient-slice-1.html border-image-repeating-radial-gradient-slice-1-ref.html
 fuzzy(0-1,0-438) fuzzy-if(skiaContent,0-3,0-437) fuzzy-if(webrender,0-3,0-40536) == border-image-repeating-radial-gradient-slice-2.html border-image-repeating-radial-gradient-slice-2-ref.html
-fuzzy(0-1,0-1357) fuzzy-if(skiaContent,0-3,0-964) fuzzy-if(webrender,1-4,85720-85800) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
-fuzzy(0-1,0-1058) fails-if(OSX) fuzzy-if(skiaContent,0-3,0-887) fuzzy-if(webrender,1-4,57068-57193) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
+fuzzy(0-1,0-1357) fuzzy-if(skiaContent,0-3,0-964) fuzzy-if(webrender,1-4,85720-85915) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
+fuzzy(0-1,0-1058) fails-if(OSX) fuzzy-if(skiaContent,0-3,0-887) fuzzy-if(webrender,1-4,57068-57318) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
 fuzzy(0-1,0-602) fuzzy-if(webrender,0-3,0-7441) == border-image-repeating-radial-gradient-width.html border-image-repeating-radial-gradient-width-ref.html
 fuzzy(0-3,0-18000) fails-if(OSX) fuzzy-if(skiaContent,0-4,0-16462) fuzzy-if(webrender,0-5,0-99728) == border-image-repeating-radial-gradient-slice-width.html border-image-repeating-radial-gradient-slice-width-ref.html
 fuzzy-if(webrender,0-3,0-117768) == border-image-repeating-radial-gradient-repeat-repeat-2.html border-image-repeating-radial-gradient-repeat-repeat-2-ref.html
 fuzzy(0-1,0-1054) fails-if(OSX) fuzzy-if(skiaContent,0-2,0-952) fuzzy-if(webrender,0-3,0-116185) == border-image-repeating-radial-gradient-repeat-round-2.html border-image-repeating-radial-gradient-repeat-round-2-ref.html
 
 # border-image-source (-moz-)element
 fuzzy(0-125,0-5808) == border-image-element.html border-image-element-ref.html
 
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -44,17 +44,17 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(
 # Tests for clipping the contents of replaced elements and overflow!=visible
 != clipping-4-ref.html clipping-4-notref.html
 fuzzy-if(true,0-1,0-20) fuzzy-if(d2d,0-72,0-196) fuzzy-if(cocoaWidget,0-1,0-180) fuzzy-if(Android,0-140,0-237) fuzzy-if(webrender&&cocoaWidget,8-8,1-1) == clipping-4-canvas.html clipping-4-ref.html # bug 732535
 fuzzy-if(Android,0-5,0-54) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-12) fuzzy-if(skiaContent,0-1,0-172) == clipping-4-image.html clipping-4-ref.html
 fuzzy-if(skiaContent,0-1,0-77) == clipping-4-overflow-hidden.html clipping-4-ref.html
 == clipping-5-canvas.html clipping-5-refc.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-5) == clipping-5-image.html clipping-5-refi.html
 fuzzy-if(skiaContent,0-1,0-77) == clipping-5-overflow-hidden.html clipping-5-ref.html
-fuzzy-if(Android,0-5,0-21) fuzzy-if(skiaContent,0-1,0-97) == clipping-5-refi.html clipping-5-ref.html
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-4) fuzzy-if(Android,0-5,0-21) fuzzy-if(skiaContent,0-1,0-97) == clipping-5-refi.html clipping-5-ref.html
 fuzzy-if(true,0-1,0-7) fuzzy-if(d2d,0-55,0-95) fuzzy-if(cocoaWidget,0-1,0-99) fuzzy-if(Android,0-99,0-115) fuzzy-if(skiaContent,0-1,0-77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
 fuzzy-if(Android,0-8,0-469) fuzzy-if(skiaContent,0-21,0-76) fuzzy-if(winWidget,0-144,0-335) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical, bug 1392106
 fuzzy-if(true,0-2,0-29) fuzzy-if(d2d,0-46,0-71) fuzzy-if(Android,0-255,0-586) fuzzy-if(skiaContent,0-28,0-97) == 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),0-1,0-5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,0-1,0-4) fuzzy-if(d2d,0-59,0-342) fuzzy-if(d3d11&&advancedLayers&&!d2d,0-30,0-3) == 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,0-5,0-105) fuzzy-if(d2d,0-1,0-20) fuzzy-if(skiaContent,0-1,0-300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -9,17 +9,17 @@ random != boxshadow-blur-2.html boxshado
 == tableboxshadow-trshadow.html tableboxshadow-trshadow-ref.html
 == tableboxshadow-tdshadow.html tableboxshadow-tdshadow-ref.html
 == boxshadow-rounding.html boxshadow-rounding-ref.html
 # One uses old path, one uses WR box shadow.
 fails-if(Android) == boxshadow-button.html boxshadow-button-ref.html
 fuzzy-if(OSX==1010,0-1,0-24) fuzzy-if(d2d,0-16,0-999) fuzzy-if(skiaContent,0-1,0-12) fuzzy-if(webrender,5-9,1560-1680) == 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(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-98,0-152) fuzzy-if(skiaContent,0-13,0-28) fuzzy-if(webrender,19-19,50-52) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-98,0-152) fuzzy-if(skiaContent,0-13,0-28) fuzzy-if(webrender,19-19,49-52) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
 fuzzy-if(skiaContent,0-1,0-17) random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
 fuzzy-if(skiaContent,0-1,0-17) == boxshadow-mixed-2.html boxshadow-mixed-2-ref.html
 random-if(d2d) fuzzy-if(skiaContent,0-1,0-212) fuzzy-if(webrender,0-127,0-3528) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
 fuzzy-if(skiaContent,0-1,0-50) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
 random-if(d2d) fuzzy-if(skiaContent,0-1,0-14) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
 random-if(d2d) fuzzy-if(skiaContent,0-1,0-22) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
 random-if(d2d) fuzzy-if(skiaContent,0-1,0-36) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
 fuzzy(0-2,0-440) fails-if(webrender&&gtkWidget) == boxshadow-skiprect.html boxshadow-skiprect-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1997,18 +1997,18 @@ random-if(!winWidget) == 1273154-2.html 
 fuzzy(0-8,0-1900) fails-if(webrender) == 1291528.html 1291528-ref.html
 # Buttons in 2 pages have different position and the rendering result can be
 # different, but they should use the same button style and the background color
 # should be same.  |fuzzy()| here allows the difference in border, but not
 # background color.
 fuzzy(0-255,0-1000) skip-if(!cocoaWidget) == 1294102-1.html 1294102-1-ref.html
 random-if(Android) fuzzy-if(skiaContent,0-15,0-50) == 1295466-1.xhtml 1295466-1-ref.xhtml #bug 982547
 fuzzy-if(Android,0-27,0-874) fuzzy-if(!Android,0-14,0-43) == 1313772.xhtml 1313772-ref.xhtml # Bug 1128229, Bug 1389319
-fuzzy(0-2,0-320000) == 1315113-1.html 1315113-1-ref.html
-fuzzy(0-2,0-20000) == 1315113-2.html 1315113-2-ref.html
+fuzzy(0-3,0-320000) == 1315113-1.html 1315113-1-ref.html
+fuzzy(0-3,0-20000) == 1315113-2.html 1315113-2-ref.html
 == 1315632-1.html 1315632-1-ref.html
 fuzzy(0-2,0-40000) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-13,0-40000) == 1316719-1a.html 1316719-1-ref.html
 fuzzy(0-13,0-40000) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-13,0-40000) == 1316719-1b.html 1316719-1-ref.html
 fuzzy(0-13,0-40000) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-13,0-40000) == 1316719-1c.html 1316719-1-ref.html
 skip-if(Android) != 1318769-1.html 1318769-1-ref.html
 == 1322512-1.html 1322512-1-ref.html
 skip-if(isDebugBuild&&winWidget) == 1330051.svg 1330051-ref.svg
 == 1348481-1.html 1348481-ref.html
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -75,17 +75,17 @@ random != text-emoji.html text-emoji-not
 == dash-sanity.html data:text/html,<body>Pass
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia||skiaContent,0-9,0-470) random-if(Android) == dash-1.html dash-1-ref.svg  # Bug 668412 (really is android-specific, not IPC-specific)
 
 == ctm-sanity.html data:text/html,<body>Pass
 == ctm-singular-sanity.html data:text/html,<body>Pass
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-45) == ctm-1.html ctm-1-ref.html
 
 == 672646-alpha-radial-gradient.html 672646-alpha-radial-gradient-ref.html
-skip-if(verify&&/^Windows\x20NT\x2010\.0/.test(http.oscpu)) == 674003-alpha-radial-gradient-superlum.html 674003-alpha-radial-gradient-superlum-ref.html
+skip-if(verify&&/^Windows\x20NT\x2010\.0/.test(http.oscpu)) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-45) == 674003-alpha-radial-gradient-superlum.html 674003-alpha-radial-gradient-superlum-ref.html
 
 != 693610-1.html 693610-1-notref.html # bug 693610: multiple glyph runs should not be overprinted
 
 == 726951-shadow-clips.html 726951-shadow-clips-ref.html
 
 == transformed-clip.html transformed-clip-ref.html
 fuzzy-if(azureSkia,0-1,0-15) fuzzy-if(skiaContent,0-1,0-20) == transformed-gradient.html transformed-gradient-ref.html
 == transformed-path.html transformed-path.html
--- a/layout/reftests/css-blending/reftest.list
+++ b/layout/reftests/css-blending/reftest.list
@@ -1,22 +1,22 @@
 pref(layout.css.mix-blend-mode.enabled,true) == blend-canvas.html blend-canvas-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-constant-background-color.html blend-constant-background-color-ref.html
-pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
+pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender,1-3,1313-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-image.html blend-image-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html
 
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-10000) fuzzy-if(skiaContent,0-1,0-30000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-alpha.html background-blending-alpha-ref.html
-pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
-fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-1,3938-23663) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html
-fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-1,1312-7887) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
+pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,1-3,1313-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
+fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-5,3938-23663) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html
+fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-1,1288-7887) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
 fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-10000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-jpg.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-png.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg.html background-blending-image-color-ref.html
-fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-1,1411-7888) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-gradient.html background-blending-gradient-color-ref.html
+fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1313-7888) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-gradient.html background-blending-gradient-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-image.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation.html background-blending-isolation-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-list-repeat.html background-blending-list-repeat-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-multiple-images.html background-blending-multiple-images-ref.html
 
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-color-burn.html background-blending-color-burn-ref.svg
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-color-dodge.html background-blending-color-dodge-ref.svg
 # need to investigate why these tests are fuzzy - first suspect is a possible color space conversion on some platforms; same for mix-blend-mode tests
@@ -82,18 +82,18 @@ pref(layout.css.background-blend-mode.en
 # Test plan 5.3.10 background-blend-mode for an element with background-origin
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-origin-border-box.html background-blending-background-origin-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-origin-content-box.html background-blending-background-origin-ref.html
 
 # Test plan 5.3.11 background-blend-mode for an element with background-attachement
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-attachement-fixed.html background-blending-background-attachement-fixed-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html
 
-pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-16408) fuzzy-if(Android,0-4,0-768) fuzzy-if(gtkWidget,0-1,0-132) fuzzy-if(skiaContent,0-1,0-800) fuzzy-if(d2d,0-1,0-33208) pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html
+pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,0-1,0-49710) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-16408) fuzzy-if(Android,0-4,0-768) fuzzy-if(gtkWidget,0-1,0-132) fuzzy-if(skiaContent,0-1,0-800) fuzzy-if(d2d,0-1,0-33208) pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,0-1,0-78472) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html
 
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-moz-element.html background-blending-moz-element-ref.html
 
 fuzzy(0-1,0-40000) pref(layout.css.background-blend-mode.enabled,true) == mix-blend-mode-soft-light.html mix-blend-mode-soft-light-ref.html
 
 # Test plan 4.4.2 element with isolation:isolate creates an isolated group for blended children
 pref(layout.css.isolation.enabled,true) == blend-isolation.html blend-isolation-ref.html
 
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -1,26 +1,26 @@
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-4,0-88500) fuzzy-if(azureSkiaGL||skiaContent,0-4,0-89700) == linear-1a.html linear-1-ref.html
-fuzzy-if(!contentSameGfxBackendAsCanvas,0-2,0-88500) fuzzy-if(azureSkiaGL,0-2,0-89997) fuzzy-if(skiaContent,0-1,0-16000) fuzzy-if(webrender,0-1,0-23918) == linear-keywords-1a.html linear-keywords-1-ref.html
+fuzzy-if(!contentSameGfxBackendAsCanvas,0-2,0-88500) fuzzy-if(azureSkiaGL,0-2,0-89997) fuzzy-if(skiaContent,0-1,0-16000) fuzzy-if(webrender,0-2,0-23918) == linear-keywords-1a.html linear-keywords-1-ref.html
 == linear-diagonal-1a.html linear-diagonal-1-ref.html
 == linear-diagonal-2a.html linear-diagonal-2-ref.html
 == linear-diagonal-3a.html linear-diagonal-3-ref.html
 == linear-diagonal-4a.html linear-diagonal-4-ref.html
 == linear-premul.html linear-premul-ref.html
 
 fuzzy(0-1,0-800000) == linear-flipped-1.html linear-flipped-1-ref.html
 == linear-position-1a.html linear-position-1-ref.html
 == linear-repeat-1a.html linear-repeat-1-ref.html
 fails-if(d2d&&!webrender) == linear-repeat-1b.html linear-repeat-1-ref.html # bug 582236
 == linear-repeat-1c.html linear-repeat-1-ref.html
 fails-if(d2d&&!webrender) == linear-repeat-1d.html linear-repeat-1-ref.html # bug 582236
 == linear-repeat-1e.html linear-repeat-1-ref.html
 fails-if(d2d&&!webrender) == linear-repeat-1f.html linear-repeat-1-ref.html # bug 582236
 fails-if(d2d&&!webrender) == linear-repeat-1g.html linear-repeat-1-ref.html # bug 582236
-fuzzy-if(skiaContent,0-1,0-500) == linear-rotated-1.html linear-rotated-1-ref.html
+fuzzy-if(skiaContent,0-1,0-500) fuzzy-if(webrender&&winWidget,0-2,0-100) == linear-rotated-1.html linear-rotated-1-ref.html
 fuzzy-if(winWidget,0-1,0-37800) fuzzy-if(skiaContent,0-1,0-45000) == linear-size-1a.html linear-size-1-ref.html
 == linear-stops-1a.html linear-stops-1-ref.html
 == linear-stops-1b.html linear-stops-1-ref.html
 == linear-stops-1c.html linear-stops-1-ref.html
 == linear-stops-1d.html linear-stops-1-ref.html
 == linear-stops-1e.html linear-stops-1-ref.html
 == linear-stops-1f.html linear-stops-1-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-88500) fuzzy-if(azureSkiaGL||skiaContent,0-3,0-89700) == linear-vertical-1a.html linear-vertical-1-ref.html
@@ -41,18 +41,18 @@ fuzzy-if(cocoaWidget,0-1,0-28) fuzzy-if(
 fuzzy-if(cocoaWidget,0-4,0-22317) fuzzy-if(Android,0-8,0-771) == radial-shape-closest-corner-1a.html radial-shape-closest-corner-1-ref.html
 fuzzy(0-1,0-238) fuzzy-if(cocoaWidget,0-4,0-22608) fuzzy-if((/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\./.test(http.oscpu))&&d2d,0-1,0-336) fuzzy-if(Android,0-8,0-787) fuzzy-if(skiaContent,0-2,0-300) == radial-shape-closest-corner-1b.html radial-shape-closest-corner-1-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),0-1,0-5) fuzzy-if(Android,0-17,0-3880) == radial-shape-closest-side-1a.html radial-shape-closest-side-1-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),0-1,0-5) fuzzy-if(Android,0-17,0-3880) == radial-shape-closest-side-1b.html radial-shape-closest-side-1-ref.html
 fuzzy-if(Android,0-8,0-771) == radial-shape-farthest-corner-1a.html radial-shape-farthest-corner-1-ref.html
 fails-if(gtkWidget&&/x86_64-/.test(xulRuntime.XPCOMABI)) fuzzy(0-1,0-1622) fuzzy-if(cocoaWidget,0-2,0-41281) fuzzy-if(Android,0-8,0-1091) fuzzy-if(skiaContent,0-2,0-500) == radial-shape-farthest-corner-1b.html radial-shape-farthest-corner-1-ref.html
 fuzzy-if(Android,0-17,0-13320) == radial-shape-farthest-side-1a.html radial-shape-farthest-side-1-ref.html
 fuzzy-if(Android,0-17,0-13320) == radial-shape-farthest-side-1b.html radial-shape-farthest-side-1-ref.html
-fuzzy-if(webrender,1-2,2-9) == radial-size-1a.html radial-size-1-ref.html
-fuzzy-if(webrender,1-2,2-9) == radial-size-1b.html radial-size-1-ref.html
+fuzzy-if(webrender,1-2,2-10) == radial-size-1a.html radial-size-1-ref.html
+fuzzy-if(webrender,1-2,2-10) == radial-size-1b.html radial-size-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1a.html radial-zero-length-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1b.html radial-zero-length-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1c.html radial-zero-length-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1d.html radial-zero-length-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1e.html radial-zero-length-1-ref.html
 fuzzy-if(Android,0-4,0-248) == radial-zero-length-1f.html radial-zero-length-1-ref.html
 == radial-premul.html radial-premul-ref.html
 == repeated-final-stop-1.html repeated-final-stop-1-ref.html
@@ -68,39 +68,39 @@ fuzzy-if(d2d,0-127,0-2612) == repeating-
 fuzzy-if(skiaContent,0-18,0-600) == twostops-1a.html twostops-1-ref.html
 fuzzy-if(skiaContent,0-18,0-600) == twostops-1b.html twostops-1-ref.html
 fuzzy-if(skiaContent,0-226,0-600) == twostops-1c.html twostops-1-ref.html
 fuzzy-if(skiaContent,0-141,0-300) == twostops-1d.html twostops-1-ref.html
 fuzzy-if(skiaContent,0-73,0-900) == twostops-1e.html twostops-1-ref.html
 
 # from http://www.xanthir.com/:4bhipd by way of http://a-ja.net/newgrad.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-20000) fuzzy-if(azureSkiaGL||skiaContent&&layersGPUAccelerated,0-8,0-20000) == aja-linear-1a.html aja-linear-1-ref.html
-fails-if(!d2d&&!skiaContent) fuzzy-if(webrender,0-1,0-10125) fuzzy-if(skiaContent,0-1,0-20000) == aja-linear-1b.html aja-linear-1-ref.html # bug 526694
+fails-if(!d2d&&!skiaContent) fuzzy-if(skiaContent,0-1,0-20000) fuzzy-if(webrender&&winWidget&&isDebugBuild,1-2,11550-11789) == aja-linear-1b.html aja-linear-1-ref.html # bug 526694
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-1c.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-1d.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-1e.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-1f.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-2,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-2.html aja-linear-2-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-2,0-19999) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-3a.html aja-linear-3-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-2,0-19999) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-3b.html aja-linear-3-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-4,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-4a.html aja-linear-4-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,0-4,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-4b.html aja-linear-4-ref.html 
-fuzzy-if(!contentSameGfxBackendAsCanvas,0-4,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) == aja-linear-5a.html aja-linear-5-ref.html 
+fuzzy-if(!contentSameGfxBackendAsCanvas,0-4,0-20000) fuzzy-if(azureSkiaGL||skiaContent,0-8,0-20000) fuzzy-if(webrender&&winWidget,4-9,15926-16125) == aja-linear-5a.html aja-linear-5-ref.html 
 fuzzy-if(Android,0-6,0-10576) == height-dependence-1.html height-dependence-1-ref.html
 fuzzy-if(cocoaWidget,0-1,0-40000) fuzzy-if(Android,0-6,0-10576) == height-dependence-2.html height-dependence-2-ref.html
 fuzzy-if(Android,0-6,0-10576) == height-dependence-3.html height-dependence-3-ref.html
 
 == linear-onestopposition-1.html linear-onestopposition-1-ref.html
-fuzzy-if(d2d,0-47,0-400) == linear-onestopposition-1.html linear-onestopposition-1-ref2.html # d2d interpolates the hard stop
+fuzzy-if(d2d,0-47,0-400) fuzzy-if(webrender&&winWidget,0-1,0-1375) == linear-onestopposition-1.html linear-onestopposition-1-ref2.html # d2d interpolates the hard stop
 == radial-onestopposition-1a.html radial-onestopposition-1-ref.html
 == radial-onestopposition-1b.html radial-onestopposition-1-ref.html
-== repeating-linear-onestopposition-1.html orange-square.html
-== repeating-radial-onestopposition-1a.html orange-square.html
-== repeating-radial-onestopposition-1b.html orange-square.html
-== bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
+fuzzy-if(webrender&&winWidget,0-1,0-1875) == repeating-linear-onestopposition-1.html orange-square.html
+fuzzy-if(webrender&&winWidget,0-1,0-1875) == repeating-radial-onestopposition-1a.html orange-square.html
+fuzzy-if(webrender&&winWidget,0-1,0-1875) == repeating-radial-onestopposition-1b.html orange-square.html
+fuzzy-if(webrender&&winWidget,0-1,0-2925) == bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
 fuzzy(0-1,0-800000) == large-gradient-1.html large-gradient-1-ref.html
 fuzzy-if(Android,0-4,0-1) == large-gradient-2.html large-gradient-2-ref.html # Bug 1182082
 fuzzy(0-1,0-800000) == large-gradient-3.html large-gradient-3-ref.html
 == large-gradient-4.html large-gradient-4-ref.html
 fuzzy(0-2,0-800000) == large-gradient-5.html large-gradient-5-ref.html
 == 1224761-1.html 1224761-1-ref.html
 
 fuzzy(0-1,0-800000) == mask-gradient-translucent-end-color-1.html mask-gradient-translucent-end-color-1-ref.html
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -15,26 +15,26 @@ fuzzy-if(webrender&&!gtkWidget,117-129,4
 random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref.html # bug 587133
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),0-16,0-90) == element-paint-background-size-01.html element-paint-background-size-01-ref.html
 == element-paint-background-size-02.html element-paint-background-size-02-ref.html
 fuzzy-if(skiaContent,0-255,0-4) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html # Bug 1475907
 fuzzy-if(d2d,0-255,0-24) == element-paint-transform-03.html element-paint-transform-03-ref.html
 fuzzy-if(asyncPan,0-2,0-140) fuzzy-if(skiaContent,0-3,0-106) fuzzy-if(webrender&&!gtkWidget,134-222,1197-1588) == element-paint-native-widget.html element-paint-native-widget-ref.html   # in -ref the scrollframe is active and layerized differently with APZ
 fails-if(usesRepeatResampling&&!(webrender&&winWidget)) == element-paint-subimage-sampling-restriction.html about:blank
 == element-paint-clippath.html element-paint-clippath-ref.html
-fuzzy-if(webrender,36-36,702-702) == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
+fuzzy-if(webrender,36-36,702-704) == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
 fuzzy-if(skiaContent,0-1,0-326) == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
-fuzzy-if(webrender,36-36,702-702) == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
+fuzzy-if(webrender,36-36,702-704) == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
 == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
 == element-paint-sharpness-02b.html element-paint-sharpness-02c.html
 == element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01-ref.html
 fuzzy-if(skiaContent,0-187,0-1191) == element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02-ref.html # Linux32 from GCC update
-== element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01-ref.html
-== element-paint-multiple-backgrounds-01b.html element-paint-multiple-backgrounds-01-ref.html
-== element-paint-multiple-backgrounds-01c.html element-paint-multiple-backgrounds-01-ref.html
+fuzzy-if(webrender,0-1,0-625) == element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01-ref.html
+fuzzy-if(webrender,0-1,0-625) == element-paint-multiple-backgrounds-01b.html element-paint-multiple-backgrounds-01-ref.html
+fuzzy-if(webrender,0-1,0-625) == element-paint-multiple-backgrounds-01c.html element-paint-multiple-backgrounds-01-ref.html
 == gradient-html-01.html gradient-html-01-ref.svg
 == gradient-html-02.html gradient-html-02-ref.svg
 random-if(!cocoaWidget) == gradient-html-03.html gradient-html-03-ref.svg
 == gradient-html-04.html gradient-html-04-ref.html
 == gradient-html-05.html gradient-html-05-ref.html
 fuzzy(0-1,0-9674) random-if(!cocoaWidget) fuzzy-if(webrender&&cocoaWidget,1-1,44200-444200) == gradient-html-06a.html gradient-html-06b.html
 fuzzy(0-1,0-9674) random-if(!cocoaWidget) fuzzy-if(webrender&&cocoaWidget,1-1,44200-444200) == gradient-html-06b.html gradient-html-06c.html
 == gradient-html-06c.html gradient-html-06d.html
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -1,17 +1,17 @@
 HTTP == deferred-anchor.xhtml#d deferred-anchor-ref.xhtml#d
 fuzzy-if(xulRuntime.widgetToolkit=="gtk3",0-1,0-23) == deferred-anchor2.xhtml deferred-anchor-ref.xhtml#d # bug 1182632
 HTTP == fixed-1.html fixed-1.html?ref
 fuzzy-if(skiaContent,0-1,0-32200) HTTP == fixed-table-1.html fixed-table-1.html?ref
 HTTP == fixed-opacity-1.html fixed-opacity-1.html?ref
 HTTP == fixed-opacity-2.html fixed-opacity-2.html?ref
 random-if(gtkWidget) fuzzy-if(Android,0-3,0-60) HTTP == fixed-text-1.html fixed-text-1.html?ref
 HTTP == fixed-text-2.html fixed-text-2.html?ref
-random-if(Android) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-12) == iframe-border-radius.html iframe-border-radius-ref.html # bug 760269
+random-if(Android) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-12) fuzzy-if(webrender&&winWidget,0-1,0-31) == iframe-border-radius.html iframe-border-radius-ref.html # bug 760269
 random-if(Android) HTTP == image-1.html image-1.html?ref
 random-if(Android) HTTP == opacity-mixed-scrolling-1.html opacity-mixed-scrolling-1.html?ref # bug 760269
 random-if(cocoaWidget) HTTP == opacity-mixed-scrolling-2.html opacity-mixed-scrolling-2.html?ref # see bug 625357
 fails-if(Android) == percent-height-overflowing-image-1.html percent-height-overflowing-image-1-ref.html # bug 1494132
 
 pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-1.html scroll-behavior-1.html?ref
 pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-2.html scroll-behavior-2.html?ref
 pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-3.html scroll-behavior-3.html?ref
--- a/layout/reftests/svg/as-image/reftest.list
+++ b/layout/reftests/svg/as-image/reftest.list
@@ -41,17 +41,17 @@ include zoom/reftest.list
 == canvas-drawImage-scale-1b.html lime100x100-ref.html
 == canvas-drawImage-scale-1c.html lime100x100-ref.html
 
 fuzzy(0-1,0-2) fuzzy-if(skiaContent,0-1,0-529) == canvas-drawImage-scale-2a.html canvas-drawImage-scale-2-ref.html
 fuzzy(0-1,0-2) fuzzy-if(skiaContent,0-1,0-529) == canvas-drawImage-scale-2b.html canvas-drawImage-scale-2-ref.html
 
 fuzzy-if(winWidget&&!d2d,0-1,0-10000) fuzzy-if(azureSkia,0-1,0-10000) fuzzy-if(Android,0-1,0-10000) == canvas-drawImage-alpha-1.html canvas-drawImage-alpha-1-ref.html
 #Same as scale-2a but with globalAlpha:
-fuzzy(0-1,0-2) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-7018) fuzzy-if(azureSkia,0-1,0-40000) fuzzy-if(webrender&&winWidget,1-1,39743-39743) == canvas-drawImage-alpha-2.html canvas-drawImage-alpha-2-ref.html
+fuzzy(0-1,0-2) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-7018) fuzzy-if(azureSkia,0-1,0-40000) fuzzy-if(webrender&&winWidget,1-1,32679-39743) == canvas-drawImage-alpha-2.html canvas-drawImage-alpha-2-ref.html
 
 == canvas-drawImage-slice-1a.html lime100x100-ref.html
 == canvas-drawImage-slice-1b.html lime100x100-ref.html
 
 == canvas-drawImage-origin-clean-1.html lime100x100-ref.html
 == canvas-drawImage-transform-restored.html canvas-drawImage-transform-restored-ref.html
 
 # Context paint tests (this feature is currently not part of any spec.)
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -11,46 +11,46 @@
 == 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,0-1,0-20) fuzzy-if(webrender&&gtkWidget,8-8,20-20) fails-if(webrender&&!gtkWidget) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
 
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-001.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-002.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-003.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-004.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-005.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-006.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-007.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-008.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-009.html clip-path-circle-003-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-010.html clip-path-circle-004-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-011.html clip-path-circle-005-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-012.html clip-path-circle-006-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-013.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-014.html clip-path-circle-007-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-015.html clip-path-circle-008-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-016.html clip-path-circle-009-ref.html
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-16,0-9) fuzzy-if(webrender,35-35,703-703) == clip-path-circle-017.html clip-path-circle-007-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-018.html clip-path-circle-010-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-019.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,35-35,703-703) == clip-path-circle-020.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-001.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-002.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-003.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-004.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-005.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-006.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-007.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-008.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-009.html clip-path-circle-003-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-010.html clip-path-circle-004-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-011.html clip-path-circle-005-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-012.html clip-path-circle-006-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-013.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-014.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-015.html clip-path-circle-008-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-016.html clip-path-circle-009-ref.html
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-16,0-9) fuzzy-if(webrender,35-35,699-703) == clip-path-circle-017.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-018.html clip-path-circle-010-ref.html
+fuzzy-if(webrender,35-35,699-703) == clip-path-circle-019.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,35-35,699-703) == 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,36-36,1100-1100) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
-fuzzy-if(webrender,36-36,1100-1100) == clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
 
 == clip-path-inset-001a.html clip-path-inset-001-ref.html
 == clip-path-inset-001b.html clip-path-inset-001-ref.html
 == clip-path-inset-001c.html clip-path-inset-001-ref.html
 # Anti-aliasing behavior for masking and borders is different
 fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002a.html clip-path-inset-002-ref.html
 fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002b.html clip-path-inset-002-ref.html
 fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002c.html clip-path-inset-002-ref.html
--- a/layout/reftests/w3c-css/submitted/background/reftest.list
+++ b/layout/reftests/w3c-css/submitted/background/reftest.list
@@ -16,18 +16,18 @@
 == background-repeat-round-1c.html background-repeat-round-1-ref.html
 == background-repeat-round-1d.html background-repeat-round-1-ref.html
 == background-repeat-round-1e.html background-repeat-round-1-ref.html
 == background-repeat-round-2.html background-repeat-round-2-ref.html
 == background-repeat-round-3.html background-repeat-round-3-ref.html
 == background-repeat-round-4.html background-repeat-round-4-ref.html
 
 #border-image test cases
-fuzzy-if(webrender,9-10,572-576) == border-image-repeat-round-1.html border-image-repeat-round-1-ref.html
-fuzzy-if(webrender,7-7,216-224) == border-image-repeat-round-2.html border-image-repeat-round-2-ref.html
+fuzzy-if(webrender,9-10,572-620) == border-image-repeat-round-1.html border-image-repeat-round-1-ref.html
+fuzzy-if(webrender,7-7,216-232) == border-image-repeat-round-2.html border-image-repeat-round-2-ref.html
 == border-image-repeat-space-1.html border-image-repeat-space-1-ref.html
 == border-image-repeat-space-2.html border-image-repeat-space-2-ref.html
 == border-image-repeat-space-3.html border-image-repeat-space-3-ref.html
 == border-image-repeat-space-4.html border-image-repeat-space-4-ref-1.html
 == border-image-repeat-space-4-ref-1.html border-image-repeat-space-4-ref-2.html
 == border-image-repeat-space-5.html border-image-repeat-space-5-ref-1.html
 == border-image-repeat-space-5-ref-1.html border-image-repeat-space-5-ref-2.html
 == border-image-repeat-space-6.html border-image-repeat-space-6-ref.html
--- a/layout/reftests/w3c-css/submitted/masking/reftest.list
+++ b/layout/reftests/w3c-css/submitted/masking/reftest.list
@@ -16,17 +16,17 @@ fuzzy-if(skiaContent,0-1,0-30000) == mas
 fuzzy-if(skiaContent,0-1,0-30000) == mask-mode-d.html mask-mode-ref.html
 fuzzy-if(skiaContent,0-1,0-30000) fuzzy-if(d2d,0-1,0-30000) == mask-mode-to-mask-type.html mask-mode-to-mask-type-ref.html
 
 # mask-image test cases
 == mask-image-1a.html mask-image-1-ref.html
 == mask-image-1b.html mask-image-1-ref.html
 random-if(gtkWidget) skip-if(winWidget&&/^Windows\x20NT\x2010\.0/.test(http.oscpu)) == mask-image-1c.html mask-image-1-ref.html # bug 1365177
 == mask-image-1d.html mask-image-1-ref.html
-fuzzy-if(skiaContent||winWidget,0-1,0-20000) == mask-image-2.html mask-image-2-ref.html
+fuzzy-if(skiaContent||winWidget,0-1,0-20000) fuzzy-if(webrender,0-2,0-6823) == mask-image-2.html mask-image-2-ref.html
 == mask-image-3a.html mask-image-3-ref.html
 == mask-image-3b.html mask-image-3-ref.html
 fuzzy-if(skiaContent||winWidget,0-1,0-43) == mask-image-3c.html mask-image-3-ref.html
 fuzzy-if(skiaContent||winWidget,0-1,0-43) == mask-image-3d.html mask-image-3-ref.html
 == mask-image-3e.html mask-image-3-ref.html
 # Due to SVG luminance, see bug 1372577, parent process doesn't use d2d for luminance.
 fuzzy-if(skiaContent||winWidget,0-50,0-85) fuzzy-if(webrender,0-1,0-126) == mask-image-3f.html mask-image-3-ref.html
 fuzzy-if(skiaContent||winWidget,0-50,0-85) fuzzy-if(webrender,0-1,0-126) == mask-image-3g.html mask-image-3-ref.html
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -583,16 +583,18 @@ public class GeckoViewActivity extends A
         @Override
         public void onContentPermissionRequest(final GeckoSession session, final String uri,
                                              final int type, final Callback callback) {
             final int resId;
             if (PERMISSION_GEOLOCATION == type) {
                 resId = R.string.request_geolocation;
             } else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
                 resId = R.string.request_notification;
+            } else if (PERMISSION_AUTOPLAY_MEDIA == type) {
+                resId = R.string.request_autoplay;
             } else {
                 Log.w(LOGTAG, "Unknown permission: " + type);
                 callback.reject();
                 return;
             }
 
             final String title = getString(resId, Uri.parse(uri).getAuthority());
             final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
--- a/mobile/android/geckoview_example/src/main/res/values/strings.xml
+++ b/mobile/android/geckoview_example/src/main/res/values/strings.xml
@@ -1,15 +1,16 @@
 <resources>
     <string name="app_name">GeckoView Example</string>
     <string name="activity_label">GeckoView Example</string>
     <string name="location_hint">Enter URL or search keywords...</string>
     <string name="username">Username</string>
     <string name="password">Password</string>
     <string name="clear_field">Clear</string>
+    <string name="request_autoplay">Allow media to play on "%1$s"?</string>
     <string name="request_geolocation">Share location with "%1$s"?</string>
     <string name="request_notification">Allow notifications for "%1$s"?</string>
     <string name="request_video">Share video with "%1$s"</string>
     <string name="request_audio">Share audio with "%1$s"</string>
     <string name="request_media">Share video and audio with "%1$s"</string>
     <string name="media_back_camera">Back camera</string>
     <string name="media_front_camera">Front camera</string>
     <string name="media_microphone">Microphone</string>
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -89,16 +89,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mForcePreflight(false)
   , mIsPreflight(false)
   , mLoadTriggeredFromExternal(false)
   , mServiceWorkerTaintingSynthesized(false)
   , mIsTracker(false)
   , mIsTrackerBlocked(false)
   , mDocumentHasUserInteracted(false)
   , mDocumentHasLoaded(false)
+  , mIsFromProcessingFrameAttributes(false)
 {
   MOZ_ASSERT(mLoadingPrincipal);
   MOZ_ASSERT(mTriggeringPrincipal);
 
 #ifdef DEBUG
   // TYPE_DOCUMENT loads initiated by javascript tests will go through
   // nsIOService and use the wrong constructor.  Don't enforce the
   // !TYPE_DOCUMENT check in those cases
@@ -361,16 +362,17 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   , mForcePreflight(false)
   , mIsPreflight(false)
   , mLoadTriggeredFromExternal(false)
   , mServiceWorkerTaintingSynthesized(false)
   , mIsTracker(false)
   , mIsTrackerBlocked(false)
   , mDocumentHasUserInteracted(false)
   , mDocumentHasLoaded(false)
+  , mIsFromProcessingFrameAttributes(false)
 {
   // Top-level loads are never third-party
   // Grab the information we can out of the window.
   MOZ_ASSERT(aOuterWindow);
   MOZ_ASSERT(mTriggeringPrincipal);
 
   // if the load is sandboxed, we can not also inherit the principal
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
@@ -463,16 +465,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mIsPreflight(rhs.mIsPreflight)
   , mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal)
   // mServiceWorkerTaintingSynthesized must be handled specially during redirect
   , mServiceWorkerTaintingSynthesized(false)
   , mIsTracker(rhs.mIsTracker)
   , mIsTrackerBlocked(rhs.mIsTrackerBlocked)
   , mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted)
   , mDocumentHasLoaded(rhs.mDocumentHasLoaded)
+  , mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes)
 {
 }
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsIPrincipal* aPrincipalToInherit,
                    nsIPrincipal* aSandboxedLoadingPrincipal,
                    nsIPrincipal* aTopLevelPrincipal,
@@ -557,16 +560,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mForcePreflight(aForcePreflight)
   , mIsPreflight(aIsPreflight)
   , mLoadTriggeredFromExternal(aLoadTriggeredFromExternal)
   , mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized)
   , mIsTracker(false)
   , mIsTrackerBlocked(false)
   , mDocumentHasUserInteracted(aDocumentHasUserInteracted)
   , mDocumentHasLoaded(aDocumentHasLoaded)
+  , mIsFromProcessingFrameAttributes(false)
 {
   // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
   MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT);
   MOZ_ASSERT(mTriggeringPrincipal);
 
   mRedirectChainIncludingInternalRedirects.SwapElements(
     aRedirectChainIncludingInternalRedirects);
 
@@ -1445,16 +1449,30 @@ LoadInfo::SetDocumentHasLoaded(bool aDoc
 NS_IMETHODIMP
 LoadInfo::GetIsTopLevelLoad(bool *aResult)
 {
   *aResult = mFrameOuterWindowID ? mFrameOuterWindowID == mOuterWindowID
                                  : mParentOuterWindowID == mOuterWindowID;
   return NS_OK;
 }
 
+void
+LoadInfo::SetIsFromProcessingFrameAttributes()
+{
+  mIsFromProcessingFrameAttributes = true;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetIsFromProcessingFrameAttributes(bool *aIsFromProcessingFrameAttributes)
+{
+  MOZ_ASSERT(aIsFromProcessingFrameAttributes);
+  *aIsFromProcessingFrameAttributes = mIsFromProcessingFrameAttributes;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 LoadInfo::GetResultPrincipalURI(nsIURI **aURI)
 {
   NS_IF_ADDREF(*aURI = mResultPrincipalURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -82,16 +82,17 @@ public:
   // separate request. I.e. not for a redirect or an inner channel, but
   // when a separate request is made with the same security properties.
   already_AddRefed<nsILoadInfo> CloneForNewRequest() const;
 
   void SetIsPreflight();
   void SetUpgradeInsecureRequests();
   void SetBrowserUpgradeInsecureRequests();
   void SetBrowserWouldUpgradeInsecureRequests();
+  void SetIsFromProcessingFrameAttributes();
 
 private:
   // private constructor that is only allowed to be called from within
   // HttpChannelParent and FTPChannelParent declared as friends undeneath.
   // In e10s we can not serialize nsINode, hence we store the innerWindowID.
   // Please note that aRedirectChain uses swapElements.
   LoadInfo(nsIPrincipal* aLoadingPrincipal,
            nsIPrincipal* aTriggeringPrincipal,
@@ -214,15 +215,20 @@ private:
   bool                             mIsPreflight;
   bool                             mLoadTriggeredFromExternal;
   bool                             mServiceWorkerTaintingSynthesized;
 
   bool                             mIsTracker;
   bool                             mIsTrackerBlocked;
   bool                             mDocumentHasUserInteracted;
   bool                             mDocumentHasLoaded;
+
+  // Is true if this load was triggered by processing the attributes of the
+  // browsing context container.
+  // See nsILoadInfo.isFromProcessingFrameAttributes
+  bool                             mIsFromProcessingFrameAttributes;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_LoadInfo_h
 
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -1063,9 +1063,16 @@ interface nsILoadInfo : nsISupports
   [infallible] attribute boolean documentHasLoaded;
 
   /**
     * The object in charged to receive CSP violation events. It can be null.
     * This attribute will be merged into the CSP object eventually.
     * See bug 1500908.
     */
   attribute nsICSPEventListener cspEventListener;
+
+  /**
+   * This attribute will be true if this is a load triggered by
+   * https://html.spec.whatwg.org/multipage/iframe-embed-object.html#process-the-iframe-attributes
+   * or https://html.spec.whatwg.org/multipage/obsolete.html#process-the-frame-attributes
+   */
+  [infallible] readonly attribute boolean isFromProcessingFrameAttributes;
 };
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -130,18 +130,16 @@ protected:
     // When the record is no longer valid (it's time of expiration)
     mozilla::TimeStamp mValidEnd;
 
     // When the record enters its grace period. This must be before mValidEnd.
     // If a record is in its grace period (and not expired), it will be used
     // but a request to refresh it will be made.
     mozilla::TimeStamp mGraceStart;
 
-    const nsCString mOriginSuffix;
-
     mozilla::net::ResolverMode mResolverMode;
 
     uint16_t  mResolving;  // counter of outstanding resolving calls
 
     uint8_t negative : 1;   /* True if this record is a cache of a failed lookup.
                                Negative cache entries are valid just like any other
                                (though never for more than 60 seconds), but a use
                                of that negative entry forces an asynchronous refresh. */
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -105,16 +105,17 @@ struct LoadInfoArgs
 
   nsCString[]                 corsUnsafeHeaders;
   bool                        forcePreflight;
   bool                        isPreflight;
   bool                        loadTriggeredFromExternal;
   bool                        serviceWorkerTaintingSynthesized;
   bool                        documentHasUserInteracted;
   bool                        documentHasLoaded;
+  bool                        isFromProcessingFrameAttributes;
 };
 
 /**
  * Not every channel necessarily has a loadInfo attached.
  */
 union OptionalLoadInfoArgs
 {
   void_t;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -4408,24 +4408,27 @@ HttpBaseChannel::GetPerformanceStorage()
   }
 
   nsCOMPtr<nsIDocument> loadingDocument;
   mLoadInfo->GetLoadingDocument(getter_AddRefs(loadingDocument));
   if (!loadingDocument) {
     return nullptr;
   }
 
-  // We only add to the document's performance object if it has the same
-  // principal as the one triggering the load. This is to prevent navigations
-  // triggered _by_ the iframe from showing up in the parent document's
-  // performance entries if they have different origins.
   if (!mLoadInfo->TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) {
     return nullptr;
   }
 
+  if (mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT &&
+      !mLoadInfo->GetIsFromProcessingFrameAttributes()) {
+    // We only report loads caused by processing the attributes of the
+    // browsing context container.
+    return nullptr;
+  }
+
   nsCOMPtr<nsPIDOMWindowInner> innerWindow = loadingDocument->GetInnerWindow();
   if (!innerWindow) {
     return nullptr;
   }
 
   mozilla::dom::Performance* performance = innerWindow->GetPerformance();
   if (!performance) {
     return nullptr;
--- a/security/sandbox/linux/SandboxFilterUtil.cpp
+++ b/security/sandbox/linux/SandboxFilterUtil.cpp
@@ -58,64 +58,66 @@ SandboxPolicyBase::EvaluateSyscall(int a
         if (thisCase) {
           acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
         }
       }
       return acc->Default(InvalidSyscall());
     }
 #endif // ANDROID
 #endif // __NR_socketcall
-#define DISPATCH_SOCKETCALL(sysnum, socketnum)                       \
-    case sysnum:                                                     \
-      return EvaluateSocketCall(socketnum, true).valueOr(InvalidSyscall())
+// clang-format off
+#define DISPATCH_SOCKETCALL(sysnum, socketnum) \
+  case sysnum:                                 \
+    return EvaluateSocketCall(socketnum, true).valueOr(InvalidSyscall())
 #ifdef __NR_socket
       DISPATCH_SOCKETCALL(__NR_socket,      SYS_SOCKET);
       DISPATCH_SOCKETCALL(__NR_bind,        SYS_BIND);
       DISPATCH_SOCKETCALL(__NR_connect,     SYS_CONNECT);
       DISPATCH_SOCKETCALL(__NR_listen,      SYS_LISTEN);
 #ifdef __NR_accept
       DISPATCH_SOCKETCALL(__NR_accept,      SYS_ACCEPT);
 #endif
       DISPATCH_SOCKETCALL(__NR_getsockname, SYS_GETSOCKNAME);
       DISPATCH_SOCKETCALL(__NR_getpeername, SYS_GETPEERNAME);
       DISPATCH_SOCKETCALL(__NR_socketpair,  SYS_SOCKETPAIR);
 #ifdef __NR_send
       DISPATCH_SOCKETCALL(__NR_send,        SYS_SEND);
       DISPATCH_SOCKETCALL(__NR_recv,        SYS_RECV);
-#endif // __NR_send
+#endif  // __NR_send
       DISPATCH_SOCKETCALL(__NR_sendto,      SYS_SENDTO);
       DISPATCH_SOCKETCALL(__NR_recvfrom,    SYS_RECVFROM);
       DISPATCH_SOCKETCALL(__NR_shutdown,    SYS_SHUTDOWN);
       DISPATCH_SOCKETCALL(__NR_setsockopt,  SYS_SETSOCKOPT);
       DISPATCH_SOCKETCALL(__NR_getsockopt,  SYS_GETSOCKOPT);
       DISPATCH_SOCKETCALL(__NR_sendmsg,     SYS_SENDMSG);
       DISPATCH_SOCKETCALL(__NR_recvmsg,     SYS_RECVMSG);
       DISPATCH_SOCKETCALL(__NR_accept4,     SYS_ACCEPT4);
       DISPATCH_SOCKETCALL(__NR_recvmmsg,    SYS_RECVMMSG);
       DISPATCH_SOCKETCALL(__NR_sendmmsg,    SYS_SENDMMSG);
-#endif // __NR_socket
+#endif  // __NR_socket
 #undef DISPATCH_SOCKETCALL
 #ifndef __NR_socketcall
 #ifndef ANDROID
-#define DISPATCH_SYSVCALL(sysnum, ipcnum)         \
-    case sysnum:                                  \
-      return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
+#define DISPATCH_SYSVCALL(sysnum, ipcnum) \
+  case sysnum:                            \
+    return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
       DISPATCH_SYSVCALL(__NR_semop,       SEMOP);
       DISPATCH_SYSVCALL(__NR_semget,      SEMGET);
       DISPATCH_SYSVCALL(__NR_semctl,      SEMCTL);
       DISPATCH_SYSVCALL(__NR_semtimedop,  SEMTIMEDOP);
       DISPATCH_SYSVCALL(__NR_msgsnd,      MSGSND);
       DISPATCH_SYSVCALL(__NR_msgrcv,      MSGRCV);
       DISPATCH_SYSVCALL(__NR_msgget,      MSGGET);
       DISPATCH_SYSVCALL(__NR_msgctl,      MSGCTL);
       DISPATCH_SYSVCALL(__NR_shmat,       SHMAT);
       DISPATCH_SYSVCALL(__NR_shmdt,       SHMDT);
       DISPATCH_SYSVCALL(__NR_shmget,      SHMGET);
       DISPATCH_SYSVCALL(__NR_shmctl,      SHMCTL);
 #undef DISPATCH_SYSVCALL
-#endif // ANDROID
-#endif // __NR_socketcall
+#endif  // ANDROID
+#endif  // __NR_socketcall
+// clang-format on
   default:
     return InvalidSyscall();
   }
 }
 
 }
--- a/testing/marionette/modal.js
+++ b/testing/marionette/modal.js
@@ -58,19 +58,18 @@ modal.addHandler = function(handler) {
  * @return {modal.Dialog}
  *     Returns instance of the Dialog class, or `null` if no modal dialog
  *     is present.
  */
 modal.findModalDialogs = function(context) {
   // First check if there is a modal dialog already present for the
   // current browser window.
   for (let win of Services.wm.getEnumerator(null)) {
-    // Modal dialogs which do not have an opener set, we cannot detect
-    // as long as GetZOrderDOMWindowEnumerator doesn't work on Linux
-    // (Bug 156333).
+    // TODO: Use BrowserWindowTracker.getTopWindow for modal dialogs without
+    // an opener.
     if (win.document.documentURI === COMMON_DIALOG &&
         win.opener && win.opener === context.window) {
       return new modal.Dialog(() => context, Cu.getWeakReference(win));
     }
   }
 
   // If no modal dialog has been found, also check if there is an open
   // tab modal dialog present for the current tab.
deleted file mode 100644
--- a/testing/web-platform/meta/resource-timing/resource_subframe_self_navigation.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[resource_subframe_self_navigation.html]
-  [Subsequent <iframe> navigations don't appear in the resource-timing buffer.]
-    expected: FAIL
-
-  [Subsequent <frame> navigations don't appear in the resource-timing buffer.]
-    expected: FAIL
-
-  [Subsequent <embed> navigations don't appear in the resource-timing buffer.]
-    expected: FAIL
-
-  [Subsequent <object> navigations don't appear in the resource-timing buffer.]
-    expected: FAIL
-
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -441,16 +441,17 @@ TagAutoCompleteSearch.prototype = {
         searchString = searchString.slice(m[0].length);
       }
     }
 
     // Create a new result to add eventual matches.  Note we need a result
     // regardless having matches.
     let result = Cc["@mozilla.org/autocomplete/simple-result;1"]
                    .createInstance(Ci.nsIAutoCompleteSimpleResult);
+    result.setDefaultIndex(0);
     result.setSearchString(searchString);
 
     let count = 0;
     if (!searchString.length) {
       this.notifyResult(result, count, listener, false);
       return;
     }
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -824,21 +824,24 @@
     "kind": "linear",
     "high": 100,
     "n_buckets": 50,
     "bug_numbers": [1485299],
     "description": "The percentage of nursery objects that were promoted to tenured heap."
   },
   "GEOLOCATION_ACCURACY_EXPONENTIAL": {
     "record_in_processes": ["main", "content"],
-    "expires_in_version": "default",
-    "kind": "exponential",
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "releaseChannelCollection": "opt-out",
+    "bug_numbers": [1507925],
     "high": 100000,
     "n_buckets": 50,
-    "description": "Location accuracy"
+    "description": "Geolocation results' accuracy radius in meters. Smaller radius is more accurate.",
+    "alert_emails": ["shong@mozilla.com"]
   },
   "GEOLOCATION_ERROR": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Has seen location error"
   },
   "GEOLOCATION_GETCURRENTPOSITION_SECURE_ORIGIN" : {
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -182,17 +182,16 @@
     "FX_THUMBNAILS_BG_CAPTURE_SERVICE_TIME_MS",
     "FX_THUMBNAILS_BG_QUEUE_SIZE_ON_CAPTURE",
     "FX_THUMBNAILS_CAPTURE_TIME_MS",
     "FX_THUMBNAILS_HIT_OR_MISS",
     "FX_THUMBNAILS_STORE_TIME_MS",
     "FX_TOTAL_TOP_VISITS",
     "FX_TOUCH_USED",
     "GDI_INITFONTLIST_TOTAL",
-    "GEOLOCATION_ACCURACY_EXPONENTIAL",
     "GEOLOCATION_ERROR",
     "GEOLOCATION_OSX_SOURCE_IS_MLS",
     "GEOLOCATION_WIN8_SOURCE_IS_MLS",
     "HISTORY_LASTVISITED_TREE_QUERY_TIME_MS",
     "HTTPCONNMGR_TOTAL_SPECULATIVE_CONN",
     "HTTPCONNMGR_UNUSED_SPECULATIVE_CONN",
     "HTTPCONNMGR_USED_SPECULATIVE_CONN",
     "HTTP_CACHE_DISPOSITION_2_V2",
@@ -721,17 +720,16 @@
     "GC_REASON_2",
     "GC_RESET",
     "GC_SCC_SWEEP_MAX_PAUSE_MS",
     "GC_SCC_SWEEP_TOTAL_MS",
     "GC_SLICE_MS",
     "GC_SLOW_PHASE",
     "GC_SWEEP_MS",
     "GDI_INITFONTLIST_TOTAL",
-    "GEOLOCATION_ACCURACY_EXPONENTIAL",
     "GEOLOCATION_ERROR",
     "GEOLOCATION_OSX_SOURCE_IS_MLS",
     "GEOLOCATION_WIN8_SOURCE_IS_MLS",
     "GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE",
     "GFX_CRASH",
     "GHOST_WINDOWS",
     "GRAPHICS_DRIVER_STARTUP_TEST",
     "GRAPHICS_SANITY_TEST",
@@ -1342,17 +1340,16 @@
     "NEWTAB_PAGE_BLOCKED_SITES_COUNT",
     "FX_SESSION_RESTORE_NUMBER_OF_TABS_RESTORED",
     "WEAVE_START_COUNT",
     "HTTP_DISK_CACHE_OVERHEAD",
     "FX_SESSION_RESTORE_CORRUPT_FILE",
     "FX_TAB_CLICK_MS",
     "LOCALDOMSTORAGE_GETVALUE_BLOCKING_MS",
     "PDF_VIEWER_DOCUMENT_VERSION",
-    "GEOLOCATION_ACCURACY_EXPONENTIAL",
     "FX_SESSION_RESTORE_READ_FILE_MS",
     "CHANGES_OF_DETECTED_LANGUAGE",
     "OSFILE_WORKER_READY_MS",
     "PDF_VIEWER_FORM",
     "FX_SESSION_RESTORE_AUTO_RESTORE_DURATION_UNTIL_EAGER_TABS_RESTORED_MS",
     "FX_SESSION_RESTORE_COLLECT_DATA_MS",
     "FX_SESSION_RESTORE_FILE_SIZE_BYTES",
     "DATA_STORAGE_ENTRIES",
--- a/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
@@ -8,16 +8,17 @@ ChromeUtils.import("resource:///modules/
 
 const VIDEO_PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
 
 add_task(() => {
   return SpecialPowers.pushPrefEnv({"set": [
     ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.PROMPT],
     ["media.autoplay.enabled.user-gestures-needed", true],
     ["media.autoplay.ask-permission", true],
+    ["media.autoplay.block-webaudio", true],
     ["media.autoplay.block-event.enabled", true],
   ]});
 });
 
 async function testAutoplayExistingPermission(args) {
   info("- Starting '" + args.name + "' -");
   await BrowserTestUtils.withNewTab({
     gBrowser,
@@ -199,19 +200,28 @@ add_task(async () => {
     name: "Unknown permission click block call play and no check check-box",
     button: "block",
     shouldPlay: false,
     mode: "call play",
     checkbox: false,
   });
 });
 
-// Test that if playback starts while the permission prompt is shown,
-// that the prompt is hidden.
-add_task(async () => {
+async function testIgnorePrompt({name, type, isAudible}) {
+  info(`- Starting test '${name}' -`);
+  if (type == "MediaElement") {
+    await testIgnorePromptAndPlayMediaElement(isAudible);
+  } else if (type == "WebAudio") {
+    await testIgnorePromptAndPlayWebAudio(isAudible);
+  } else {
+    ok(false, `undefined test type.`);
+  }
+}
+
+async function testIgnorePromptAndPlayMediaElement(isAudible) {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: VIDEO_PAGE,
   }, async (browser) => {
     info("- Started test prompt hides upon play -");
     let promptShowing = () =>
       PopupNotifications.getNotification("autoplay-media", browser);
 
@@ -229,36 +239,130 @@ add_task(async () => {
     // Check that the video didn't start playing.
     await ContentTask.spawn(browser, null,
       async () => {
         let video = content.document.getElementById("v1");
         ok(video.paused && !video.didPlay, "Video should not be playing");
       });
 
     let popuphidden = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
-
-    await ContentTask.spawn(browser, null,
-      async () => {
+    await ContentTask.spawn(browser, isAudible,
+      async (isAudible) => {
         // Gesture activate the document, i.e. simulate a click in the document,
         // to unblock autoplay,
         content.document.notifyUserGestureActivation();
         let video = content.document.getElementById("v1");
+        video.muted = !isAudible;
         // Gesture activating in itself should not cause the previous pending
         // play to proceed.
         ok(video.paused && !video.didPlay, "Video should not have played yet");
         // But trying to play again now that we're gesture activated will work...
         let played = await video.play().then(() => true, () => false);
         ok(played, "Should have played as now gesture activated");
         // And because we started playing, the previous promise returned in the
         // first call to play() above should also resolve too.
         await video.didPlayPromise;
         ok(video.didPlay, "Existing promise should resolve when media starts playing");
       });
 
-    info("Awaiting popuphidden");
-    await popuphidden;
-    ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
+    if (isAudible) {
+      info("Awaiting popuphidden");
+      await popuphidden;
+      ok(!promptShowing(), "Permission prompt should have hidden when media started playing");
+    } else {
+      ok(promptShowing(), `doorhanger would only be dismissed when audible media starts`);
+    }
 
     // Reset permission.
     SitePermissions.remove(browser.currentURI, "autoplay-media");
     info("- Finished test prompt hides upon play -");
   });
+}
+
+async function testIgnorePromptAndPlayWebAudio(isAudible) {
+  function createAudioContext() {
+    content.ac = new content.AudioContext();
+    content.ac.notAllowedToStart = new Promise(resolve => {
+      content.ac.addEventListener("blocked", function() {
+        resolve();
+      }, {once: true});
+    });
+  }
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: VIDEO_PAGE,
+  }, async (browser) => {
+    info(`- set the 'autoplay-media' permission to UNKNOWN -`);
+    const promptShowing = () =>
+      PopupNotifications.getNotification("autoplay-media", browser);
+    SitePermissions.set(browser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
+    ok(!promptShowing(), "Should not be showing permission prompt");
+
+    info(`- create AudioContext which should not start until user approves -`);
+    loadFrameScript(browser, createAudioContext);
+    await ContentTask.spawn(browser, null, async () => {
+      await content.ac.notAllowedToStart;
+      ok(content.ac.state === "suspended", `AudioContext is not started yet.`);
+    });
+
+    info(`- try to start AudioContext and show doorhanger to ask for user's approval -`);
+    const popupShow = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    await ContentTask.spawn(browser, null, () => {
+      content.ac.resume();
+    });
+    await popupShow;
+    ok(promptShowing(), `should now be showing permission prompt`);
+
+    info(`- simulate user activate the page -`);
+    await ContentTask.spawn(browser, null, () => {
+      content.document.notifyUserGestureActivation();
+    });
+
+    if (isAudible) {
+      info(`- ignore doorhanger, connect audible node and start node -`);
+      const popupHide = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+      await ContentTask.spawn(browser, null, () => {
+        const ac = content.ac;
+        let node = ac.createOscillator();
+        node.connect(ac.destination);
+        node.start();
+      });
+      await popupHide;
+      ok(true, `doorhanger should dismiss after AudioContext starts audible`);
+    } else {
+      info(`- ignore doorhanger and resume AudioContext without connecting audible node -`);
+      await ContentTask.spawn(browser, null, async () => {
+        await content.ac.resume();
+        ok(true, `successfully resume AudioContext.`);
+      });
+      ok(promptShowing(),
+         `doorhanger would only be dismissed when audible media starts`);
+    }
+
+    SitePermissions.remove(browser.currentURI, "autoplay-media");
+  });
+}
+
+// Test that the prompt would dismiss when audible media starts, but not dismiss
+// when inaudible media starts.
+add_task(async () => {
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play audible media element",
+    type: "MediaElement",
+    isAudible: true,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play inaudible media element",
+    type: "MediaElement",
+    isAudible: false,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play audible web audio",
+    type: "WebAudio",
+    isAudible: true,
+  });
+  await testIgnorePrompt({
+    name: "ignore doorhanger and play inaudible web audio",
+    type: "WebAudio",
+    isAudible: false,
+  });
 });
--- a/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
@@ -40,162 +40,155 @@ function createAudioContext() {
     }, {once: true});
   });
 }
 
 async function checkIfAudioContextIsAllowedToStart(isAllowedToStart) {
   const ac = content.ac;
   if (isAllowedToStart) {
     await ac.allowedToStart;
-    ok(true, `AudioContext is running.`);
+    ok(ac.state === "running", `AudioContext is running.`);
   } else {
     await ac.notAllowedToStart;
-    ok(true, `AudioContext is not started yet.`);
+    ok(ac.state === "suspended", `AudioContext is not started yet.`);
   }
 }
 
 async function resumeAudioContext(isAllowedToStart) {
   const ac = content.ac;
   const resumePromise = ac.resume();
   const blockedPromise = new Promise(resolve => {
     ac.addEventListener("blocked", function() {
       resolve();
     }, {once: true});
   });
 
   if (isAllowedToStart) {
     await resumePromise;
-    ok(ac.state === "running", `AudioContext is running.`);
+    ok(true, `successfully resume AudioContext.`);
   } else {
     await blockedPromise;
-    ok(ac.state === "suspended", `AudioContext is suspended.`);
+    ok(true, `resume is blocked because AudioContext is not allowed to start.`);
   }
 }
 
-function checkAudioContextState(state) {
-  ok(content.ac.state === state,
-     `AudioContext state is ${content.ac.state}, expected state is ${state}`);
+function startAudioContext(method) {
+  const ac = content.ac;
+  if (method == "AudioContext") {
+    info(`using AudioContext.resume() to start AudioContext`);
+    ac.resume();
+    return;
+  }
+  info(`using ${method}.start() to start AudioContext`);
+  let node;
+  switch (method) {
+    case "AudioBufferSourceNode":
+      node = ac.createBufferSource();
+      break;
+    case "ConstantSourceNode":
+      node = ac.createConstantSource();
+      break;
+    case "OscillatorNode":
+      node = ac.createOscillator();
+      break;
+    default:
+      ok(false, "undefined AudioScheduledSourceNode type");
+      return;
+  }
+  node.connect(ac.destination);
+  node.start();
 }
 
-function connectAudibleNodeToContext() {
-  info(`- connect audible node to context graph -`);
-  const ac = content.ac;
-  const dest = ac.destination;
-  const osc = ac.createOscillator();
-  osc.connect(dest);
-  osc.start();
-}
-
-async function testAutoplayExistingPermission(args) {
-  info(`- starting \"${args.name}\" -`);
+async function testAutoplayExistingPermission({name, permission}) {
+  info(`- starting \"${name}\" -`);
   const tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, PAGE);
   const browser = tab.linkedBrowser;
 
-  info(`- set the permission -`);
+  info(`- set the 'autoplay-media' permission -`);
   const promptShow = () =>
     PopupNotifications.getNotification("autoplay-media", browser);
-  SitePermissions.set(browser.currentURI, "autoplay-media", args.permission);
+  SitePermissions.set(browser.currentURI, "autoplay-media", permission);
   ok(!promptShow(), `should not be showing permission prompt yet`);
 
   info(`- create audio context -`);
-  // We want the same audio context to be used across different content
-  // tasks, so it needs to be loaded by a frame script.
-  const mm = tab.linkedBrowser.messageManager;
-  mm.loadFrameScript("data:,(" + createAudioContext.toString() + ")();", false);
+  loadFrameScript(browser, createAudioContext);
 
   info(`- check AudioContext status -`);
-  const isAllowedToStart = args.permission === SitePermissions.ALLOW;
+  const isAllowedToStart = permission === SitePermissions.ALLOW;
   await ContentTask.spawn(browser, isAllowedToStart,
                           checkIfAudioContextIsAllowedToStart);
   await ContentTask.spawn(browser, isAllowedToStart,
                           resumeAudioContext);
 
   info(`- remove tab -`);
   SitePermissions.remove(browser.currentURI, "autoplay-media");
   await BrowserTestUtils.removeTab(tab);
 }
 
-async function testAutoplayUnknownPermission(args) {
-  info(`- starting \"${args.name}\" -`);
+async function testAutoplayUnknownPermission({name, button, method}) {
+  info(`- starting \"${name}\" -`);
   const tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, PAGE);
   const browser = tab.linkedBrowser;
 
-  info(`- set the 'autoplay-media' permission -`);
+  info(`- set the 'autoplay-media' permission to UNKNOWN -`);
   const promptShow = () =>
     PopupNotifications.getNotification("autoplay-media", browser);
   SitePermissions.set(browser.currentURI, "autoplay-media", SitePermissions.UNKNOWN);
   ok(!promptShow(), `should not be showing permission prompt yet`);
 
-  info(`- create audio context -`);
+  info(`- create AudioContext which should not start until user approves -`);
+  loadFrameScript(browser, createAudioContext);
+  await ContentTask.spawn(browser, false, checkIfAudioContextIsAllowedToStart);
+
+  info(`- try to start AudioContext and show doorhanger to ask for user's approval -`);
   const popupShow = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
-  // We want the same audio context to be used across different content
-  // tasks, so it needs to be loaded by a frame script.
-  const mm = tab.linkedBrowser.messageManager;
-  mm.loadFrameScript("data:,(" + createAudioContext.toString() + ")();", false);
+  await ContentTask.spawn(browser, method, startAudioContext);
   await popupShow;
   ok(promptShow(), `should now be showing permission prompt`);
 
-  info(`- AudioContext should not be started before user responds to doorhanger -`);
-  await ContentTask.spawn(browser, "suspended",
-                          checkAudioContextState);
-
-  if (args.ignoreDoorhanger) {
-    const popupHide = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
-    await ContentTask.spawn(browser, null, () => {
-      info(`- user ingores the doorhanger and interacts with page directly -`);
-      content.document.notifyUserGestureActivation();
-    });
+  info(`- simulate clicking button on doorhanger -`);
+  if (button == "allow") {
+    PopupNotifications.panel.firstElementChild.button.click();
+  } else if (button == "block") {
+    PopupNotifications.panel.firstChild.secondaryButton.click();
+  } else {
+    ok(false, `invalid button field`);
+  }
 
-    await ContentTask.spawn(browser, true,
-                            resumeAudioContext);
-    ok(promptShow(), `doorhanger would only be dismissed when audible media starts`);
-    await ContentTask.spawn(browser, null,
-                            connectAudibleNodeToContext);
-    await popupHide;
-    ok(true, `doorhanger should dismiss after AudioContext starts audible`);
-  } else {
-    info(`- simulate clicking button on doorhanger-`);
-    if (args.button == "allow") {
-      PopupNotifications.panel.firstElementChild.button.click();
-    } else if (args.button == "block") {
-      PopupNotifications.panel.firstChild.secondaryButton.click();
-    } else {
-      ok(false, `Invalid button field`);
-    }
-
-    info(`- check AudioContext status -`);
-    const isAllowedToStart = args.button === "allow";
-    await ContentTask.spawn(browser, isAllowedToStart,
-                            checkIfAudioContextIsAllowedToStart);
-    await ContentTask.spawn(browser, isAllowedToStart,
-                            resumeAudioContext);
-  }
+  info(`- check AudioContext status -`);
+  const isAllowedToStart = button === "allow";
+  await ContentTask.spawn(browser, isAllowedToStart,
+                          checkIfAudioContextIsAllowedToStart);
+  await ContentTask.spawn(browser, isAllowedToStart,
+                          resumeAudioContext);
 
   info(`- remove tab -`);
   SitePermissions.remove(browser.currentURI, "autoplay-media");
   await BrowserTestUtils.removeTab(tab);
 }
 
-add_task(async function start_test() {
+add_task(async function start_tests() {
   info("- setup test preference -");
   await setup_test_preference();
 
   await testAutoplayExistingPermission({
     name: "Prexisting allow permission",
     permission: SitePermissions.ALLOW,
   });
   await testAutoplayExistingPermission({
     name: "Prexisting block permission",
     permission: SitePermissions.BLOCK,
   });
-  await testAutoplayUnknownPermission({
-    name: "Unknown permission and click allow button on doorhanger",
-    button: "allow",
-  });
-  await testAutoplayUnknownPermission({
-    name: "Unknown permission and click block button on doorhanger",
-    button: "block",
-  });
-  await testAutoplayUnknownPermission({
-    name: "Unknown permission and ignore doorhanger",
-    ignoreDoorhanger: true,
-  });
+  const startMethods = ["AudioContext", "AudioBufferSourceNode",
+                        "ConstantSourceNode", "OscillatorNode"];
+  for (let method of startMethods) {
+    await testAutoplayUnknownPermission({
+      name: "Unknown permission and click allow button on doorhanger",
+      button: "allow",
+      method,
+    });
+    await testAutoplayUnknownPermission({
+      name: "Unknown permission and click block button on doorhanger",
+      button: "block",
+      method,
+    });
+  }
 });
--- a/toolkit/content/tests/browser/head.js
+++ b/toolkit/content/tests/browser/head.js
@@ -293,8 +293,15 @@ function checkVideoDidPlay(browser, args
     let video = content.document.getElementById("v1");
     await video.didPlayPromise;
     is(video.didPlay, args.shouldPlay,
       args.name + " should " + (!args.shouldPlay ? "not " : "") + "be able to autoplay");
     video.src = "";
     content.document.body.remove(video);
   });
 }
+
+// The JS content loaded by frame script can be used across different content
+// tasks.
+function loadFrameScript(browser, fn) {
+  const mm = browser.messageManager;
+  mm.loadFrameScript("data:,(" + fn.toString() + ")();", false);
+}
--- a/toolkit/mozapps/extensions/internal/GMPProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/GMPProvider.jsm
@@ -49,17 +49,17 @@ const GMP_PLUGINS = [
     // localisation.
     licenseURL:      "chrome://mozapps/content/extensions/OpenH264-license.txt",
     homepageURL:     "http://www.openh264.org/",
   },
   {
     id:              WIDEVINE_ID,
     name:            "widevine_description",
     // Describe the purpose of both CDMs in the same way.
-    description:     "cdm_description",
+    description:     "cdm_description2",
     licenseURL:      "https://www.google.com/policies/privacy/",
     homepageURL:     "https://www.widevine.com/",
     isEME:           true,
   }];
 XPCOMUtils.defineConstant(this, "GMP_PLUGINS", GMP_PLUGINS);
 
 XPCOMUtils.defineLazyGetter(this, "pluginsBundle",
   () => Services.strings.createBundle("chrome://global/locale/plugins.properties"));
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -7,21 +7,21 @@
 @namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 *|*:root {
   --in-content-page-color: #0c0c0d;
   --in-content-page-background: #f9f9fa;
   --in-content-text-color: #0c0c0d;
   --in-content-selected-text: #fff;
   --in-content-box-background: #fff;
-  --in-content-box-background-odd: #f3f6fa;
-  --in-content-box-background-hover: #ebebeb;
-  --in-content-box-background-active: #dadada;
-  --in-content-box-border-color: #d7d7db;
-  --in-content-item-hover: rgba(0,149,221,0.25);
+  --in-content-box-background-odd: rgba(12, 12, 13, 0.05); /* grey 90 a05 */
+  --in-content-box-background-hover: #ededf0; /* grey 20 */
+  --in-content-box-background-active: #d7d7db; /* grey 30 */
+  --in-content-box-border-color: #d7d7db; /* grey 30 */
+  --in-content-item-hover: rgba(69, 161, 255, 0.2); /* blue 40 a20 */
   --in-content-item-selected: #0a84ff;
   --in-content-border-highlight: #0a84ff;
   --in-content-border-focus: #0a84ff;
   --in-content-border-color: #d7d7db;
   --in-content-category-outline-focus: 1px dotted #0a84ff;
   --in-content-category-text: rgba(12,12,13);
   --in-content-category-text-selected: #0a84ff;
   --in-content-category-text-selected-active: #0060df;
--- a/toolkit/themes/windows/global/in-content/common.css
+++ b/toolkit/themes/windows/global/in-content/common.css
@@ -1,18 +1,14 @@
 /* - 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 ../../../shared/in-content/common.inc.css
 
-:root {
-  --in-content-box-background-odd: transparent;
-}
-
 xul|*.menulist-dropmarker {
   margin-top: 1px;
   margin-bottom: 1px;
 }
 
 xul|checkbox,
 xul|radio {
   padding-inline-start: 0;
--- a/tools/rewriting/ThirdPartyPaths.txt
+++ b/tools/rewriting/ThirdPartyPaths.txt
@@ -37,17 +37,17 @@ gfx/sfntly/
 gfx/skia/
 gfx/vr/service/openvr/
 gfx/webrender/
 gfx/webrender_api/
 gfx/wrench/
 gfx/ycbcr/
 intl/hyphenation/hyphen/
 intl/icu/
-ipc/chromium/
+ipc/chromium/src/third_party/
 js/src/ctypes/libffi/
 js/src/dtoa.c
 js/src/jit/arm64/vixl/
 js/src/vtune/disable_warnings.h
 js/src/vtune/ittnotify.h
 js/src/vtune/ittnotify_config.h
 js/src/vtune/ittnotify_static.c
 js/src/vtune/ittnotify_static.h
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -3930,23 +3930,25 @@ nsWindow::Create(nsIWidget* aParent,
          */
         GtkStyleContext* style = gtk_widget_get_style_context(mShell);
         drawToContainer =
             !mIsX11Display ||
             (mCSDSupportLevel == CSD_SUPPORT_CLIENT) ||
             gtk_style_context_has_class(style, "csd");
         eventWidget = (drawToContainer) ? container : mShell;
 
-        gtk_widget_add_events(eventWidget, kEvents);
-        if (drawToContainer)
-            gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
-
         // Prevent GtkWindow from painting a background to avoid flickering.
         gtk_widget_set_app_paintable(eventWidget, TRUE);
 
+        gtk_widget_add_events(eventWidget, kEvents);
+        if (drawToContainer) {
+            gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
+            gtk_widget_set_app_paintable(mShell, TRUE);
+        }
+
         // If we draw to mContainer window then configure it now because
         // gtk_container_add() realizes the child widget.
         gtk_widget_set_has_window(container, drawToContainer);
 
         gtk_container_add(GTK_CONTAINER(mShell), container);
         gtk_widget_realize(container);
 
         // make sure this is the focus widget in the container
--- a/widget/reftests/reftest.list
+++ b/widget/reftests/reftest.list
@@ -1,5 +1,5 @@
 == progressbar-fallback-default-style.html progressbar-fallback-default-style-ref.html
-fuzzy-if(Android,0-17,0-1120) fuzzy-if(webrender&&winWidget,1-1,5-5) == meter-native-style.html meter-native-style-ref.html
+fuzzy-if(Android,0-17,0-1120) fuzzy-if(webrender&&winWidget,0-1,0-5) == meter-native-style.html meter-native-style-ref.html
 skip-if(!cocoaWidget) == meter-vertical-native-style.html meter-vertical-native-style-ref.html # dithering
 == meter-fallback-default-style.html meter-fallback-default-style-ref.html
 load 664925.xhtml
--- a/xpcom/base/nsCOMPtr.h
+++ b/xpcom/base/nsCOMPtr.h
@@ -549,17 +549,16 @@ public:
   }
 
   nsCOMPtr(nsCOMPtr<T>&& aSmartPtr)
     : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
   {
     assert_validity();
     aSmartPtr.mRawPtr = nullptr;
     NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
-    NSCAP_ASSERT_NO_QUERY_NEEDED();
   }
 
   template <class U>
   MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
     : NSCAP_CTOR_BASE(aSmartPtr.forget().template downcast<T>().take())
   {
     // Make sure that U actually inherits from T
     static_assert(mozilla::IsBaseOf<T, U>::value,
@@ -728,17 +727,16 @@ public:
                   "U should be a subclass of T");
     assign_with_AddRef(static_cast<T*>(aRhs.get()));
     return *this;
   }
 
   nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs)
   {
     assign_assuming_AddRef(aRhs.forget().take());
-    NSCAP_ASSERT_NO_QUERY_NEEDED();
     return *this;
   }
 
   template<class U>
   nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs)
   {
     // Make sure that U actually inherits from T
     static_assert(mozilla::IsBaseOf<T, U>::value,
--- a/xpfe/appshell/nsAppShellWindowEnumerator.cpp
+++ b/xpfe/appshell/nsAppShellWindowEnumerator.cpp
@@ -320,55 +320,16 @@ nsWindowInfo *nsASXULWindowEarlyToLateEn
       return info;
     info = info->mYounger;
   }
 
   return nullptr;
 }
 
 //
-// nsASDOMWindowFrontToBackEnumerator
-//
-
-nsASDOMWindowFrontToBackEnumerator::nsASDOMWindowFrontToBackEnumerator(
-    const char16_t *aTypeString,
-    nsWindowMediator &aMediator) :
-      nsASDOMWindowEnumerator(aTypeString, aMediator)
-{
-  mCurrentPosition = aMediator.mTopmostWindow;
-  AdjustInitialPosition();
-}
-
-nsASDOMWindowFrontToBackEnumerator::~nsASDOMWindowFrontToBackEnumerator()
-{
-}
-
-nsWindowInfo *nsASDOMWindowFrontToBackEnumerator::FindNext()
-{
-  nsWindowInfo *info,
-               *listEnd;
-  bool          allWindows = mType.IsEmpty();
-
-  // see nsXULWindowEarlyToLateEnumerator::FindNext
-  if (!mCurrentPosition)
-    return nullptr;
-
-  info = mCurrentPosition->mLower;
-  listEnd = mWindowMediator->mTopmostWindow;
-
-  while (info != listEnd) {
-    if (allWindows || info->TypeEquals(mType))
-      return info;
-    info = info->mLower;
-  }
-
-  return nullptr;
-}
-
-//
 // nsASXULWindowFrontToBackEnumerator
 //
 
 nsASXULWindowFrontToBackEnumerator::nsASXULWindowFrontToBackEnumerator(
     const char16_t *aTypeString,
     nsWindowMediator &aMediator) :
       nsASXULWindowEnumerator(aTypeString, aMediator)
 {
@@ -398,58 +359,16 @@ nsWindowInfo *nsASXULWindowFrontToBackEn
       return info;
     info = info->mLower;
   }
 
   return nullptr;
 }
 
 //
-// nsASDOMWindowBackToFrontEnumerator
-//
-
-nsASDOMWindowBackToFrontEnumerator::nsASDOMWindowBackToFrontEnumerator(
-    const char16_t *aTypeString,
-    nsWindowMediator &aMediator) :
-  nsASDOMWindowEnumerator(aTypeString, aMediator)
-{
-  mCurrentPosition = aMediator.mTopmostWindow ?
-                     aMediator.mTopmostWindow->mHigher : nullptr;
-  AdjustInitialPosition();
-}
-
-nsASDOMWindowBackToFrontEnumerator::~nsASDOMWindowBackToFrontEnumerator()
-{
-}
-
-nsWindowInfo *nsASDOMWindowBackToFrontEnumerator::FindNext()
-{
-  nsWindowInfo *info,
-               *listEnd;
-  bool          allWindows = mType.IsEmpty();
-
-  // see nsXULWindowEarlyToLateEnumerator::FindNext
-  if (!mCurrentPosition)
-    return nullptr;
-
-  info = mCurrentPosition->mHigher;
-  listEnd = mWindowMediator->mTopmostWindow;
-  if (listEnd)
-    listEnd = listEnd->mHigher;
-
-  while (info != listEnd) {
-    if (allWindows || info->TypeEquals(mType))
-      return info;
-    info = info->mHigher;
-  }
-
-  return nullptr;
-}
-
-//
 // nsASXULWindowBackToFrontEnumerator
 //
 
 nsASXULWindowBackToFrontEnumerator::nsASXULWindowBackToFrontEnumerator(
     const char16_t *aTypeString,
     nsWindowMediator &aMediator) :
       nsASXULWindowEnumerator(aTypeString, aMediator)
 {
--- a/xpfe/appshell/nsAppShellWindowEnumerator.h
+++ b/xpfe/appshell/nsAppShellWindowEnumerator.h
@@ -110,52 +110,28 @@ public:
                                      nsWindowMediator& inMediator);
 
   virtual ~nsASXULWindowEarlyToLateEnumerator();
 
 protected:
   virtual nsWindowInfo *FindNext() override;
 };
 
-class nsASDOMWindowFrontToBackEnumerator : public nsASDOMWindowEnumerator {
-
-public:
-  nsASDOMWindowFrontToBackEnumerator(const char16_t* aTypeString,
-                                     nsWindowMediator& inMediator);
-
-  virtual ~nsASDOMWindowFrontToBackEnumerator();
-
-protected:
-  virtual nsWindowInfo *FindNext() override;
-};
-
 class nsASXULWindowFrontToBackEnumerator : public nsASXULWindowEnumerator {
 
 public:
   nsASXULWindowFrontToBackEnumerator(const char16_t* aTypeString,
                                      nsWindowMediator& inMediator);
 
   virtual ~nsASXULWindowFrontToBackEnumerator();
 
 protected:
   virtual nsWindowInfo *FindNext() override;
 };
 
-class nsASDOMWindowBackToFrontEnumerator : public nsASDOMWindowEnumerator {
-
-public:
-  nsASDOMWindowBackToFrontEnumerator(const char16_t* aTypeString,
-                                     nsWindowMediator& inMediator);
-
-  virtual ~nsASDOMWindowBackToFrontEnumerator();
-
-protected:
-  virtual nsWindowInfo *FindNext() override;
-};
-
 class nsASXULWindowBackToFrontEnumerator : public nsASXULWindowEnumerator {
 
 public:
   nsASXULWindowBackToFrontEnumerator(const char16_t* aTypeString,
                                      nsWindowMediator& inMediator);
 
   virtual ~nsASXULWindowBackToFrontEnumerator();
 
--- a/xpfe/appshell/nsIWindowMediator.idl
+++ b/xpfe/appshell/nsIWindowMediator.idl
@@ -46,22 +46,16 @@ interface nsIWindowMediator: nsISupports
     * no requirement that a window couldn't be revisited if windows
     * are re-ordered while z-order enumerators are active.
     * @param  aWindowType the returned enumerator will enumerate only
     *                     windows of this type. ("type" is the
     *                     |windowtype| attribute of the XML <window> element.)
     *                     If null, all windows will be enumerated.
     * @param  aFrontToBack if true, the enumerator enumerates windows in order
     *                      from front to back. back to front if false.
-    * @return an enumerator of nsIDOMWindows
-    */
-  nsISimpleEnumerator getZOrderDOMWindowEnumerator(in wstring aWindowType,
-                        in boolean aFrontToBack);
-
-  /** Identical to getZOrderDOMWindowEnumerator except:
     * @return an enumerator of nsIXULWindows
     */
   nsISimpleEnumerator getZOrderXULWindowEnumerator(in wstring aWindowType,
                         in boolean aFrontToBack);
 
   /** This is a shortcut for simply fetching the first window in
     * front to back order.
     * @param  aWindowType return the topmost window of this type.
--- a/xpfe/appshell/nsWindowMediator.cpp
+++ b/xpfe/appshell/nsWindowMediator.cpp
@@ -200,35 +200,16 @@ nsWindowMediator::GetXULWindowEnumerator
   NS_ENSURE_STATE(mReady);
 
   RefPtr<nsAppShellWindowEnumerator> enumerator = new nsASXULWindowEarlyToLateEnumerator(inType, *this);
   enumerator.forget(outEnumerator);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWindowMediator::GetZOrderDOMWindowEnumerator(
-            const char16_t *aWindowType, bool aFrontToBack,
-            nsISimpleEnumerator **_retval)
-{
-  MOZ_RELEASE_ASSERT(NS_IsMainThread());
-  NS_ENSURE_ARG_POINTER(_retval);
-  NS_ENSURE_STATE(mReady);
-
-  RefPtr<nsAppShellWindowEnumerator> enumerator;
-  if (aFrontToBack)
-    enumerator = new nsASDOMWindowFrontToBackEnumerator(aWindowType, *this);
-  else
-    enumerator = new nsASDOMWindowBackToFrontEnumerator(aWindowType, *this);
-
-  enumerator.forget(_retval);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsWindowMediator::GetZOrderXULWindowEnumerator(
             const char16_t *aWindowType, bool aFrontToBack,
             nsISimpleEnumerator **_retval)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   NS_ENSURE_ARG_POINTER(_retval);
   NS_ENSURE_STATE(mReady);
 
--- a/xpfe/appshell/nsWindowMediator.h
+++ b/xpfe/appshell/nsWindowMediator.h
@@ -12,34 +12,30 @@
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsWeakReference.h"
 #include "nsTObserverArray.h"
 
 class nsAppShellWindowEnumerator;
 class nsASXULWindowEarlyToLateEnumerator;
 class nsASDOMWindowEarlyToLateEnumerator;
-class nsASDOMWindowFrontToBackEnumerator;
 class nsASXULWindowFrontToBackEnumerator;
-class nsASDOMWindowBackToFrontEnumerator;
 class nsASXULWindowBackToFrontEnumerator;
 class nsIWindowMediatorListener;
 struct nsWindowInfo;
 
 class nsWindowMediator :
   public nsIWindowMediator,
   public nsIObserver,
   public nsSupportsWeakReference
 {
 friend class nsAppShellWindowEnumerator;
 friend class nsASXULWindowEarlyToLateEnumerator;
 friend class nsASDOMWindowEarlyToLateEnumerator;
-friend class nsASDOMWindowFrontToBackEnumerator;
 friend class nsASXULWindowFrontToBackEnumerator;
-friend class nsASDOMWindowBackToFrontEnumerator;
 friend class nsASXULWindowBackToFrontEnumerator;
 
 protected:
   virtual ~nsWindowMediator();
 
 public:
   nsWindowMediator();