Merge mozilla-central to mozilla-inbound.
authorCosmin Sabou <csabou@mozilla.com>
Fri, 04 Jan 2019 18:38:34 +0200
changeset 509699 1d867d35ae2da5e2633daf89b7384f92870b445e
parent 509698 d29920edc7bb0e90b72bf5d90ecbc345ef254301 (current diff)
parent 509644 619d084f08917d63aab65a8a42f1c4b40d909542 (diff)
child 509700 9d85a82d43054cf502c91705800180a21651d999
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone66.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 mozilla-inbound.
dom/base/ChromeUtils.cpp
dom/base/ChromeUtils.h
dom/chrome-webidl/ChromeUtils.webidl
modules/libpref/init/all.js
toolkit/modules/Task.jsm
toolkit/modules/tests/modules/Task.jsm
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -109,17 +109,16 @@ const startupPhases = {
   // be blacklisted here.
   "before becoming idle": {blacklist: {
     components: new Set([
       "UnifiedComplete.js",
     ]),
     modules: new Set([
       "resource://gre/modules/AsyncPrefs.jsm",
       "resource://gre/modules/LoginManagerContextMenu.jsm",
-      "resource://gre/modules/Task.jsm",
       "resource://pdf.js/PdfStreamConverter.jsm",
     ]),
   }},
 };
 
 if (Services.prefs.getBoolPref("browser.startup.blankWindow") &&
     Services.prefs.getCharPref("lightweightThemes.selectedThemeID") ==
       "default-theme@mozilla.org") {
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -2123,64 +2123,61 @@ file, You can obtain one at http://mozil
       <method name="_openAutocompletePopup">
         <parameter name="aInput"/>
         <parameter name="aElement"/>
         <body><![CDATA[
           if (this.mPopupOpen) {
             return;
           }
 
-          // Set the direction of the popup based on the textbox (bug 649840).
-          let popupDirection = this.style.direction = (RTL_UI ? "rtl" : "ltr");
-
           // Make the popup span the width of the window.  First, set its width.
           let documentRect =
             window.windowUtils
                 .getBoundsWithoutFlushing(window.document.documentElement);
           let width = documentRect.right - documentRect.left;
           this.setAttribute("width", width);
 
           // Now make its starting margin negative so that its leading edge
           // aligns with the window border.
           let elementRect =
             window.windowUtils.getBoundsWithoutFlushing(aElement);
-          if (popupDirection == "rtl") {
+          if (RTL_UI) {
             let offset = elementRect.right - documentRect.right;
             this.style.marginRight = offset + "px";
           } else {
             let offset = documentRect.left - elementRect.left;
             this.style.marginLeft = offset + "px";
           }
 
           // Keep the popup items' site icons aligned with the urlbar's identity
           // icon if it's not too far from the edge of the window.  We define
           // "too far" as "more than 30% of the window's width AND more than
           // 250px".  Do this *before* adding any items because when the new
           // value of the margins are different from the previous value, over-
           // and underflow must be handled for each item already in the popup.
           let needsHandleOverUnderflow = false;
-          let boundToCheck = popupDirection == "rtl" ? "right" : "left";
+          let boundToCheck = RTL_UI ? "right" : "left";
           let inputRect = window.windowUtils.getBoundsWithoutFlushing(aInput);
           let startOffset = Math.abs(inputRect[boundToCheck] - documentRect[boundToCheck]);
           let alignSiteIcons = startOffset / width <= 0.3 || startOffset <= 250;
           if (alignSiteIcons) {
             // Calculate the end margin if we have a start margin.
-            let boundToCheckEnd = popupDirection == "rtl" ? "left" : "right";
+            let boundToCheckEnd = RTL_UI ? "left" : "right";
             let endOffset = Math.abs(inputRect[boundToCheckEnd] -
                                      documentRect[boundToCheckEnd]);
             if (endOffset > startOffset * 2) {
               // Provide more space when aligning would result in an unbalanced
               // margin. This allows the location bar to be moved to the start
               // of the navigation toolbar to reclaim space for results.
               endOffset = startOffset;
             }
             let identityIcon = document.getElementById("identity-icon");
             let identityRect =
               window.windowUtils.getBoundsWithoutFlushing(identityIcon);
-            let start = popupDirection == "rtl" ?
+            let start = RTL_UI ?
                         documentRect.right - identityRect.right :
                         identityRect.left;
             if (!this.margins || start != this.margins.start ||
                                  endOffset != this.margins.end ||
                                  width != this.margins.width) {
               this.margins = { start, end: endOffset, width };
               needsHandleOverUnderflow = true;
             }
@@ -2204,17 +2201,17 @@ file, You can obtain one at http://mozil
               // Update the impressions count on real popupshown, since there's
               // no guarantee openPopup will be respected by the platform.
               // Though, we must ensure the handled event is the expected one.
               let impressionId = this._searchSuggestionsImpressionId = {};
               this.addEventListener("popupshown", () => {
                 if (this._searchSuggestionsImpressionId == impressionId)
                   aInput.updateSearchSuggestionsNotificationImpressions(whichNotification);
               }, {once: true});
-              this._showSearchSuggestionsNotification(whichNotification, popupDirection);
+              this._showSearchSuggestionsNotification(whichNotification);
             } else if (this.classList.contains("showSearchSuggestionsNotification")) {
               this._hideSearchSuggestionsNotification();
             }
           } catch (ex) {
             // Not critical for the urlbar functionality, just report the error.
             Cu.reportError(ex);
           }
 
@@ -2320,17 +2317,16 @@ file, You can obtain one at http://mozil
             }, this.shrinkDelay);
           }
           ]]>
         </body>
       </method>
 
       <method name="_showSearchSuggestionsNotification">
         <parameter name="whichNotification"/>
-        <parameter name="popupDirection"/>
         <body>
           <![CDATA[
           if (whichNotification == "opt-out") {
             if (this.margins) {
               this.searchSuggestionsNotification.style.paddingInlineStart =
                 this.margins.start + "px";
             } else {
               this.searchSuggestionsNotification.style.removeProperty("padding-inline-start");
--- a/browser/components/urlbar/UrlbarController.jsm
+++ b/browser/components/urlbar/UrlbarController.jsm
@@ -160,27 +160,31 @@ class UrlbarController {
         event.ctrlKey &&
         (event.key == "n" || event.key == "p")) {
       this.view.selectNextItem({ reverse: event.key == "p" });
       event.preventDefault();
       return;
     }
 
     switch (event.keyCode) {
+      case KeyEvent.DOM_VK_ESCAPE:
+        this.input.handleRevert();
+        event.preventDefault();
+        break;
       case KeyEvent.DOM_VK_RETURN:
         if (AppConstants.platform == "macosx" &&
             event.metaKey) {
           // Prevent beep on Mac.
           event.preventDefault();
         }
         // TODO: We may have an autoFill entry, so we should use that instead.
         // TODO: We should have an input bufferrer so that we can use search results
         // if appropriate.
         this.input.handleCommand(event);
-        return;
+        break;
       case KeyEvent.DOM_VK_TAB:
         if (this.view.isOpen) {
           this.view.selectNextItem({ reverse: event.shiftKey });
           event.preventDefault();
         }
         break;
       case KeyEvent.DOM_VK_DOWN:
       case KeyEvent.DOM_VK_UP:
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -246,16 +246,24 @@ class UrlbarInput {
         }
       });
       return;
     }
 
     this._loadURL(url, where, openParams);
   }
 
+  handleRevert() {
+    this.window.gBrowser.userTypedValue = null;
+    this.window.URLBarSetURI(null, true);
+    if (this.value && this.focused) {
+      this.select();
+    }
+  }
+
   /**
    * Called by the view when a result is picked.
    *
    * @param {Event} event The event that picked the result.
    * @param {UrlbarMatch} result The result that was picked.
    */
   pickResult(event, result) {
     this.setValueFromResult(result);
@@ -268,18 +276,17 @@ class UrlbarInput {
     let where = this._whereToOpen(event);
     let openParams = {
       postData: null,
       allowInheritPrincipal: false,
     };
 
     switch (result.type) {
       case UrlbarUtils.MATCH_TYPE.TAB_SWITCH: {
-        // TODO: Implement handleRevert or equivalent on the input.
-        // this.input.handleRevert();
+        this.handleRevert();
         let prevTab = this.window.gBrowser.selectedTab;
         let loadOpts = {
           adoptIntoActiveWindow: UrlbarPrefs.get("switchTabs.adoptIntoActiveWindow"),
         };
 
         if (this.window.switchToTabHavingURI(Services.io.newURI(result.payload.url), false, loadOpts) &&
             prevTab.isEmpty) {
           this.window.gBrowser.removeTab(prevTab);
@@ -585,28 +592,26 @@ class UrlbarInput {
     }
 
     // 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();
+      this.handleRevert();
     }
 
     try {
       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();
+        this.handleRevert();
       }
     }
 
     // TODO This should probably be handed via input.
     // Ensure the start of the URL is visible for usability reasons.
     // this.selectionStart = this.selectionEnd = 0;
 
     this.closePopup();
--- a/devtools/client/aboutdebugging-new/aboutdebugging.js
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.js
@@ -73,23 +73,22 @@ const AboutDebugging = {
               fluentBundles: l10n.getBundles(),
             }
           )
         )
       ),
       this.mount
     );
 
-    this.actions.updateNetworkLocations(getNetworkLocations());
-
+    this.onNetworkLocationsUpdated();
     addNetworkLocationsObserver(this.onNetworkLocationsUpdated);
 
     // Listen to USB runtime updates and retrieve the initial list of runtimes.
+    this.onUSBRuntimesUpdated();
     addUSBRuntimesObserver(this.onUSBRuntimesUpdated);
-    getUSBRuntimes();
 
     adbAddon.on("update", this.onAdbAddonUpdated);
     this.onAdbAddonUpdated();
 
     // Remove deprecated remote debugging extensions.
     await adbAddon.uninstallUnsupportedExtensions();
 
     addMultiE10sListener(this.onMultiE10sUpdated);
--- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js
+++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Actions = require("./index");
 
 const {
+  getAllRuntimes,
   getCurrentRuntime,
   findRuntimeById,
 } = require("../modules/runtimes-state-helper");
 const { isSupportedDebugTarget } = require("../modules/debug-target-support");
 
 const { createClientForRuntime } = require("../modules/runtime-client-factory");
 
 const { remoteClientManager } =
@@ -20,25 +21,25 @@ const { remoteClientManager } =
 const {
   CONNECT_RUNTIME_FAILURE,
   CONNECT_RUNTIME_START,
   CONNECT_RUNTIME_SUCCESS,
   DEBUG_TARGETS,
   DISCONNECT_RUNTIME_FAILURE,
   DISCONNECT_RUNTIME_START,
   DISCONNECT_RUNTIME_SUCCESS,
+  REMOTE_RUNTIMES_UPDATED,
   RUNTIME_PREFERENCE,
   RUNTIMES,
   UNWATCH_RUNTIME_FAILURE,
   UNWATCH_RUNTIME_START,
   UNWATCH_RUNTIME_SUCCESS,
   UPDATE_CONNECTION_PROMPT_SETTING_FAILURE,
   UPDATE_CONNECTION_PROMPT_SETTING_START,
   UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS,
-  USB_RUNTIMES_UPDATED,
   WATCH_RUNTIME_FAILURE,
   WATCH_RUNTIME_START,
   WATCH_RUNTIME_SUCCESS,
 } = require("../constants");
 
 async function getRuntimeInfo(runtime, clientWrapper) {
   const { type } = runtime;
   const { name, channel, deviceName, version } =
@@ -190,48 +191,99 @@ function unwatchRuntime(id) {
 
       dispatch({ type: UNWATCH_RUNTIME_SUCCESS });
     } catch (e) {
       dispatch({ type: UNWATCH_RUNTIME_FAILURE, error: e });
     }
   };
 }
 
-function updateUSBRuntimes(runtimes) {
+function updateNetworkRuntimes(locations) {
+  const runtimes = locations.map(location => {
+    const [ host, port ] = location.split(":");
+    return {
+      id: location,
+      extra: {
+        connectionParameters: { host, port: parseInt(port, 10) },
+      },
+      isUnknown: false,
+      name: location,
+      type: RUNTIMES.NETWORK,
+    };
+  });
+  return updateRemoteRuntimes(runtimes, RUNTIMES.NETWORK);
+}
+
+function updateUSBRuntimes(adbRuntimes) {
+  const runtimes = adbRuntimes.map(adbRuntime => {
+    // Set connectionParameters only for known runtimes.
+    const socketPath = adbRuntime._socketPath;
+    const deviceId = adbRuntime.deviceId;
+    const connectionParameters = adbRuntime.isUnknown() ? null : { deviceId, socketPath };
+    return {
+      id: adbRuntime.id,
+      extra: {
+        connectionParameters,
+        deviceName: adbRuntime.deviceName,
+      },
+      isUnknown: adbRuntime.isUnknown(),
+      name: adbRuntime.shortName,
+      type: RUNTIMES.USB,
+    };
+  });
+  return updateRemoteRuntimes(runtimes, RUNTIMES.USB);
+}
+
+function updateRemoteRuntimes(runtimes, type) {
   return async (dispatch, getState) => {
     const currentRuntime = getCurrentRuntime(getState().runtimes);
 
     if (currentRuntime &&
-        currentRuntime.type === RUNTIMES.USB &&
+        currentRuntime.type === type &&
         !runtimes.find(runtime => currentRuntime.id === runtime.id)) {
       // Since current USB runtime was invalid, move to this firefox page.
       // This case is considered as followings and so on:
       // * Remove ADB addon
       // * (Physically) Disconnect USB runtime
       //
       // The reason why we call selectPage before USB_RUNTIMES_UPDATED was fired is below.
       // Current runtime can not be retrieved after USB_RUNTIMES_UPDATED action, since
       // that updates runtime state. So, before that we fire selectPage action so that to
       // transact unwatchRuntime correctly.
 
       await dispatch(Actions.selectPage(RUNTIMES.THIS_FIREFOX, RUNTIMES.THIS_FIREFOX));
     }
 
+    // Retrieve runtimeDetails from existing runtimes.
+    runtimes.forEach(runtime => {
+      const existingRuntime = findRuntimeById(runtime.id, getState().runtimes);
+      runtime.runtimeDetails = existingRuntime ? existingRuntime.runtimeDetails : null;
+    });
+
     // Disconnect runtimes that were no longer valid
     const validIds = runtimes.map(r => r.id);
-    const existingRuntimes = getState().runtimes.usbRuntimes;
-    const invalidRuntimes = existingRuntimes.filter(r => !validIds.includes(r.id));
+    const existingRuntimes = getAllRuntimes(getState().runtimes);
+    const invalidRuntimes = existingRuntimes.filter(r => {
+      return r.type === type && !validIds.includes(r.id);
+    });
 
     for (const invalidRuntime of invalidRuntimes) {
-      await dispatch(disconnectRuntime(invalidRuntime.id));
+      const isConnected = !!invalidRuntime.runtimeDetails;
+      if (isConnected) {
+        await dispatch(disconnectRuntime(invalidRuntime.id));
+      }
     }
 
-    dispatch({ type: USB_RUNTIMES_UPDATED, runtimes });
+    dispatch({ type: REMOTE_RUNTIMES_UPDATED, runtimes, runtimeType: type });
 
-    for (const runtime of getState().runtimes.usbRuntimes) {
+    for (const runtime of getAllRuntimes(getState().runtimes)) {
+      if (runtime.type !== type) {
+        continue;
+      }
+
       const isConnected = !!runtime.runtimeDetails;
       const hasConnectedClient = remoteClientManager.hasClient(runtime.id, runtime.type);
       if (!isConnected && hasConnectedClient) {
         await dispatch(connectRuntime(runtime.id));
       }
     }
   };
 }
@@ -254,11 +306,12 @@ function removeRuntimeListeners() {
 }
 
 module.exports = {
   connectRuntime,
   disconnectRuntime,
   removeRuntimeListeners,
   unwatchRuntime,
   updateConnectionPromptSetting,
+  updateNetworkRuntimes,
   updateUSBRuntimes,
   watchRuntime,
 };
--- a/devtools/client/aboutdebugging-new/src/actions/ui.js
+++ b/devtools/client/aboutdebugging-new/src/actions/ui.js
@@ -75,17 +75,20 @@ function removeNetworkLocation(location)
   };
 }
 
 function updateAdbAddonStatus(adbAddonStatus) {
   return { type: ADB_ADDON_STATUS_UPDATED, adbAddonStatus };
 }
 
 function updateNetworkLocations(locations) {
-  return { type: NETWORK_LOCATIONS_UPDATED, locations };
+  return (dispatch, getState) => {
+    dispatch(Actions.updateNetworkRuntimes(locations));
+    dispatch({ type: NETWORK_LOCATIONS_UPDATED, locations });
+  };
 }
 
 function installAdbAddon() {
   return async (dispatch, getState) => {
     dispatch({ type: ADB_ADDON_INSTALL_START });
 
     try {
       // "aboutdebugging" will be forwarded to telemetry as the installation source
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -17,16 +17,17 @@ const actionTypes = {
   CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS",
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED: "DEBUG_TARGET_COLLAPSIBILITY_UPDATED",
   DISCONNECT_RUNTIME_FAILURE: "DISCONNECT_RUNTIME_FAILURE",
   DISCONNECT_RUNTIME_START: "DISCONNECT_RUNTIME_START",
   DISCONNECT_RUNTIME_SUCCESS: "DISCONNECT_RUNTIME_SUCCESS",
   MULTI_E10S_UPDATED: "MULTI_E10S_UPDATED",
   NETWORK_LOCATIONS_UPDATED: "NETWORK_LOCATIONS_UPDATED",
   PAGE_SELECTED: "PAGE_SELECTED",
+  REMOTE_RUNTIMES_UPDATED: "REMOTE_RUNTIMES_UPDATED",
   REQUEST_EXTENSIONS_FAILURE: "REQUEST_EXTENSIONS_FAILURE",
   REQUEST_EXTENSIONS_START: "REQUEST_EXTENSIONS_START",
   REQUEST_EXTENSIONS_SUCCESS: "REQUEST_EXTENSIONS_SUCCESS",
   REQUEST_TABS_FAILURE: "REQUEST_TABS_FAILURE",
   REQUEST_TABS_START: "REQUEST_TABS_START",
   REQUEST_TABS_SUCCESS: "REQUEST_TABS_SUCCESS",
   REQUEST_WORKERS_FAILURE: "REQUEST_WORKERS_FAILURE",
   REQUEST_WORKERS_START: "REQUEST_WORKERS_START",
@@ -37,17 +38,16 @@ const actionTypes = {
   UNWATCH_RUNTIME_FAILURE: "UNWATCH_RUNTIME_FAILURE",
   UNWATCH_RUNTIME_START: "UNWATCH_RUNTIME_START",
   UNWATCH_RUNTIME_SUCCESS: "UNWATCH_RUNTIME_SUCCESS",
   UPDATE_CONNECTION_PROMPT_SETTING_FAILURE: "UPDATE_CONNECTION_PROMPT_SETTING_FAILURE",
   UPDATE_CONNECTION_PROMPT_SETTING_START: "UPDATE_CONNECTION_PROMPT_SETTING_START",
   UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS: "UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS",
   USB_RUNTIMES_SCAN_START: "USB_RUNTIMES_SCAN_START",
   USB_RUNTIMES_SCAN_SUCCESS: "USB_RUNTIMES_SCAN_SUCCESS",
-  USB_RUNTIMES_UPDATED: "USB_RUNTIMES_UPDATED",
   WATCH_RUNTIME_FAILURE: "WATCH_RUNTIME_FAILURE",
   WATCH_RUNTIME_START: "WATCH_RUNTIME_START",
   WATCH_RUNTIME_SUCCESS: "WATCH_RUNTIME_SUCCESS",
 };
 
 const DEBUG_TARGETS = {
   EXTENSION: "EXTENSION",
   TAB: "TAB",
--- a/devtools/client/aboutdebugging-new/src/modules/runtimes-state-helper.js
+++ b/devtools/client/aboutdebugging-new/src/modules/runtimes-state-helper.js
@@ -24,21 +24,25 @@ exports.getCurrentRuntimeInfo = getCurre
 
 function getCurrentConnectionPromptSetting(runtimesState) {
   const runtimeDetails = getCurrentRuntimeDetails(runtimesState);
   return runtimeDetails ? runtimeDetails.connectionPromptEnabled : false;
 }
 exports.getCurrentConnectionPromptSetting = getCurrentConnectionPromptSetting;
 
 function findRuntimeById(id, runtimesState) {
-  const allRuntimes = [
+  return getAllRuntimes(runtimesState).find(r => r.id === id);
+}
+exports.findRuntimeById = findRuntimeById;
+
+function getAllRuntimes(runtimesState) {
+  return [
     ...runtimesState.networkRuntimes,
     ...runtimesState.thisFirefoxRuntimes,
     ...runtimesState.usbRuntimes,
   ];
-  return allRuntimes.find(r => r.id === id);
 }
-exports.findRuntimeById = findRuntimeById;
+exports.getAllRuntimes = getAllRuntimes;
 
 function getCurrentRuntimeDetails(runtimesState) {
   const runtime = getCurrentRuntime(runtimesState);
   return runtime ? runtime.runtimeDetails : null;
 }
--- a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js
+++ b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js
@@ -2,21 +2,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
   CONNECT_RUNTIME_SUCCESS,
   DISCONNECT_RUNTIME_SUCCESS,
-  NETWORK_LOCATIONS_UPDATED,
   RUNTIMES,
   UNWATCH_RUNTIME_SUCCESS,
   UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS,
-  USB_RUNTIMES_UPDATED,
+  REMOTE_RUNTIMES_UPDATED,
   WATCH_RUNTIME_SUCCESS,
 } = require("../constants");
 
 const {
   findRuntimeById,
 } = require("../modules/runtimes-state-helper");
 
 const { remoteClientManager } =
@@ -80,72 +79,35 @@ function runtimesReducer(state = Runtime
     }
 
     case DISCONNECT_RUNTIME_SUCCESS: {
       const { id, type } = action.runtime;
       remoteClientManager.removeClient(id, type);
       return _updateRuntimeById(id, { runtimeDetails: null }, state);
     }
 
-    case NETWORK_LOCATIONS_UPDATED: {
-      const { locations } = action;
-      const networkRuntimes = locations.map(location => {
-        const [ host, port ] = location.split(":");
-        return {
-          id: location,
-          extra: {
-            connectionParameters: { host, port: parseInt(port, 10) },
-          },
-          isUnknown: false,
-          name: location,
-          type: RUNTIMES.NETWORK,
-        };
-      });
-      return Object.assign({}, state, { networkRuntimes });
-    }
-
     case UNWATCH_RUNTIME_SUCCESS: {
       return Object.assign({}, state, { selectedRuntimeId: null });
     }
 
     case UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS: {
       const { connectionPromptEnabled } = action;
       const { id: runtimeId } = action.runtime;
       const runtime = findRuntimeById(runtimeId, state);
       const runtimeDetails =
         Object.assign({}, runtime.runtimeDetails, { connectionPromptEnabled });
       return _updateRuntimeById(runtimeId, { runtimeDetails }, state);
     }
 
-    case USB_RUNTIMES_UPDATED: {
-      const { runtimes } = action;
-      const usbRuntimes = runtimes.map(runtime => {
-        // Retrieve runtimeDetails from existing runtimes.
-        const existingRuntime = findRuntimeById(runtime.id, state);
-        const runtimeDetails = existingRuntime ? existingRuntime.runtimeDetails : null;
-
-        // Set connectionParameters only for known runtimes.
-        const socketPath = runtime._socketPath;
-        const deviceId = runtime.deviceId;
-        const connectionParameters =
-          runtime.isUnknown() ? null : { deviceId, socketPath };
-
-        return {
-          id: runtime.id,
-          extra: {
-            connectionParameters,
-            deviceName: runtime.deviceName,
-          },
-          isUnknown: runtime.isUnknown(),
-          name: runtime.shortName,
-          runtimeDetails,
-          type: RUNTIMES.USB,
-        };
+    case REMOTE_RUNTIMES_UPDATED: {
+      const { runtimes, runtimeType } = action;
+      const key = TYPE_TO_RUNTIMES_KEY[runtimeType];
+      return Object.assign({}, state, {
+        [key]: runtimes,
       });
-      return Object.assign({}, state, { usbRuntimes });
     }
 
     case WATCH_RUNTIME_SUCCESS: {
       const { id } = action.runtime;
       return Object.assign({}, state, { selectedRuntimeId: id });
     }
 
     default:
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_persist_connection.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_persist_connection.js
@@ -1,49 +1,72 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const RUNTIME_ID = "test-runtime-id";
-const RUNTIME_DEVICE_NAME = "test device name";
-const RUNTIME_APP_NAME = "TestApp";
+const NETWORK_RUNTIME_HOST = "localhost:6080";
+const NETWORK_RUNTIME_APP_NAME = "TestNetworkApp";
+const USB_RUNTIME_ID = "test-runtime-id";
+const USB_DEVICE_NAME = "test device name";
+const USB_APP_NAME = "TestApp";
 
 /* import-globals-from head-mocks.js */
 Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "head-mocks.js", this);
 
 // Test that remote runtime connections are persisted across about:debugging reloads.
 add_task(async function() {
   const mocks = new Mocks();
 
-  let { document, tab } = await openAboutDebugging();
+  info("Test with a USB runtime");
+  const usbClient = mocks.createUSBRuntime(USB_RUNTIME_ID, {
+    name: USB_APP_NAME,
+    deviceName: USB_DEVICE_NAME,
+  });
+
+  await testRemoteClientPersistConnection(mocks, {
+    client: usbClient,
+    id: USB_RUNTIME_ID,
+    runtimeName: USB_APP_NAME,
+    sidebarName: USB_DEVICE_NAME,
+  });
 
-  const usbClient = mocks.createUSBRuntime(RUNTIME_ID, {
-    name: RUNTIME_APP_NAME,
-    deviceName: RUNTIME_DEVICE_NAME,
+  info("Test with a network runtime");
+  const networkClient = mocks.createNetworkRuntime(NETWORK_RUNTIME_HOST, {
+    name: NETWORK_RUNTIME_APP_NAME,
   });
-  mocks.emitUSBUpdate();
 
-  await connectToRuntime(RUNTIME_DEVICE_NAME, document);
-  await selectRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
+  await testRemoteClientPersistConnection(mocks, {
+    client: networkClient,
+    id: NETWORK_RUNTIME_HOST,
+    runtimeName: NETWORK_RUNTIME_APP_NAME,
+    sidebarName: NETWORK_RUNTIME_HOST,
+  });
+});
+
+async function testRemoteClientPersistConnection(mocks,
+  { client, id, runtimeName, sidebarName }) {
+  info("Open about:debugging and connect to the test runtime");
+  let { document, tab } = await openAboutDebugging();
+  await connectToRuntime(sidebarName, document);
+  await selectRuntime(sidebarName, runtimeName, document);
 
   info("Reload about:debugging");
   document = await reloadAboutDebugging(tab);
-  mocks.emitUSBUpdate();
 
   info("Wait until the remote runtime appears as connected");
   await waitUntil(() => {
-    const sidebarItem = findSidebarItemByText(RUNTIME_DEVICE_NAME, document);
+    const sidebarItem = findSidebarItemByText(sidebarName, document);
     return sidebarItem && !sidebarItem.querySelector(".js-connect-button");
   });
 
   // Remove the runtime without emitting an update.
   // This is what happens today when we simply close Firefox for Android.
-  info("Remove the runtime from the list of USB runtimes");
-  mocks.removeUSBRuntime(RUNTIME_ID);
+  info("Remove the runtime from the list of remote runtimes");
+  mocks.removeRuntime(id);
 
   info("Emit 'closed' on the client and wait for the sidebar item to disappear");
-  usbClient._eventEmitter.emit("closed");
-  await waitUntil(() => !findSidebarItemByText(RUNTIME_DEVICE_NAME, document));
+  client._eventEmitter.emit("closed");
+  await waitUntil(() => !findSidebarItemByText(sidebarName, document));
 
   info("Remove the tab");
   await removeTab(tab);
-});
+}
--- a/devtools/client/aboutdebugging-new/test/browser/head-mocks.js
+++ b/devtools/client/aboutdebugging-new/test/browser/head-mocks.js
@@ -146,9 +146,17 @@ class Mocks {
 
     return mockUsbClient;
   }
 
   removeUSBRuntime(id) {
     this._usbRuntimes = this._usbRuntimes.filter(runtime => runtime.id !== id);
     delete this._clients[RUNTIMES.USB][id];
   }
+
+  removeRuntime(id) {
+    if (this._clients[RUNTIMES.USB][id]) {
+      this.removeUSBRuntime(id);
+    } else if (this._clients[RUNTIMES.NETWORK][id]) {
+      this.removeNetworkRuntime(id);
+    }
+  }
 }
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -9352,60 +9352,36 @@ exports.PSEUDO_ELEMENTS = [
 ];
 
 /**
  * A list of the preferences keys for whether a CSS property is enabled or not. This is
  * exposed for testing purposes.
  */
 exports.PREFERENCES = [
   [
-    "box-decoration-break",
-    "layout.css.box-decoration-break.enabled"
-  ],
-  [
-    "color-adjust",
-    "layout.css.color-adjust.enabled"
-  ],
-  [
     "column-span",
     "layout.css.column-span.enabled"
   ],
   [
     "contain",
     "layout.css.contain.enabled"
   ],
   [
     "font-optical-sizing",
     "layout.css.font-variations.enabled"
   ],
   [
-    "image-orientation",
-    "layout.css.image-orientation.enabled"
-  ],
-  [
     "initial-letter",
     "layout.css.initial-letter.enabled"
   ],
   [
-    "isolation",
-    "layout.css.isolation.enabled"
-  ],
-  [
-    "mix-blend-mode",
-    "layout.css.mix-blend-mode.enabled"
-  ],
-  [
     "-moz-osx-font-smoothing",
     "layout.css.osx-font-smoothing.enabled"
   ],
   [
-    "scroll-behavior",
-    "layout.css.scroll-behavior.property-enabled"
-  ],
-  [
     "scrollbar-width",
     "layout.css.scrollbar-width.enabled"
   ],
   [
     "text-justify",
     "layout.css.text-justify.enabled"
   ],
   [
@@ -9436,20 +9412,16 @@ exports.PREFERENCES = [
     "scroll-snap-type-x",
     "layout.css.scroll-snap.enabled"
   ],
   [
     "scroll-snap-type-y",
     "layout.css.scroll-snap.enabled"
   ],
   [
-    "background-blend-mode",
-    "layout.css.background-blend-mode.enabled"
-  ],
-  [
     "font-variation-settings",
     "layout.css.font-variations.enabled"
   ],
   [
     "offset-path",
     "layout.css.motion-path.enabled"
   ],
   [
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/Base64.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/PerformanceMetricsCollector.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/IdleDeadline.h"
+#include "mozilla/dom/JSWindowActorService.h"
 #include "mozilla/dom/ReportingHeader.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/WindowBinding.h"  // For IdleRequestCallback/Options
 #include "IOActivityMonitor.h"
 #include "nsThreadUtils.h"
 #include "mozJSComponentLoader.h"
 #include "GeckoProfiler.h"
 #include "nsIException.h"
@@ -792,12 +793,20 @@ constexpr auto kSkipSelfHosted = JS::Sav
       MOZ_CRASH(
           "PopupBlocker::PopupControlState and PopupBlockerState are out of "
           "sync");
   }
 }
 
 /* static */ bool ChromeUtils::IsPopupTokenUnused(GlobalObject& aGlobal) {
   return PopupBlocker::IsPopupOpeningTokenUnused();
+
+/* static */ void ChromeUtils::RegisterWindowActor(
+    const GlobalObject& aGlobal, const nsAString& aName,
+    const WindowActorOptions& aOptions, ErrorResult& aRv) {
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  RefPtr<JSWindowActorService> service = JSWindowActorService::GetSingleton();
+  service->RegisterWindowActor(aName, aOptions, aRv);
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -22,16 +22,17 @@ namespace dom {
 
 class ArrayBufferViewOrArrayBuffer;
 class BrowsingContext;
 class IdleRequestCallback;
 struct IdleRequestOptions;
 class MozQueryInterface;
 class PrecompiledScript;
 class Promise;
+struct WindowActorOptions;
 
 class ChromeUtils {
  private:
   // Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
   static void SaveHeapSnapshotShared(GlobalObject& global,
                                      const HeapSnapshotBoundaries& boundaries,
                                      nsAString& filePath, nsAString& snapshotId,
                                      ErrorResult& rv);
@@ -171,14 +172,19 @@ class ChromeUtils {
 
   static bool HasReportingHeaderForOrigin(GlobalObject& global,
                                           const nsAString& aOrigin,
                                           ErrorResult& aRv);
 
   static PopupBlockerState GetPopupControlState(GlobalObject& aGlobal);
 
   static bool IsPopupTokenUnused(GlobalObject& aGlobal);
+
+  static void RegisterWindowActor(const GlobalObject& aGlobal,
+                                  const nsAString& aName,
+                                  const WindowActorOptions& aOptions,
+                                  ErrorResult& aRv);
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_ChromeUtils__
--- a/dom/chrome-webidl/ChromeUtils.webidl
+++ b/dom/chrome-webidl/ChromeUtils.webidl
@@ -380,16 +380,19 @@ partial namespace ChromeUtils {
   [ChromeOnly, Throws]
   boolean hasReportingHeaderForOrigin(DOMString aOrigin);
 
   [ChromeOnly]
   PopupBlockerState getPopupControlState();
 
   [ChromeOnly]
   boolean isPopupTokenUnused();
+
+  [ChromeOnly, Throws]
+  void registerWindowActor(DOMString aName, WindowActorOptions aOptions);
 };
 
 /**
  * Dictionaries duplicating IPDL types in dom/ipc/DOMTypes.ipdlh
  * Used by requestPerformanceMetrics
  */
 
 dictionary MediaMemoryInfoDictionary {
@@ -516,16 +519,27 @@ dictionary HeapSnapshotBoundaries {
   boolean          runtime;
 };
 
 dictionary Base64URLEncodeOptions {
   /** Specifies whether the output should be padded with "=" characters. */
   required boolean pad;
 };
 
+dictionary WindowActorOptions {
+  /** This fields are used for configuring individual sides of the actor. */
+  required WindowActorSidedOptions parent;
+  required WindowActorSidedOptions child;
+};
+
+dictionary WindowActorSidedOptions {
+  /** The module path which should be loaded for the actor on this side. */
+  required DOMString moduleURI;
+};
+
 enum Base64URLDecodePadding {
   /**
    * Fails decoding if the input is unpadded. RFC 4648, section 3.2 requires
    * padding, unless the referring specification prohibits it.
    */
   "require",
 
   /** Tolerates padded and unpadded input. */
new file mode 100644
--- /dev/null
+++ b/dom/ipc/JSWindowActorService.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/JSWindowActorService.h"
+
+#include "mozilla/StaticPtr.h"
+
+namespace mozilla {
+namespace dom {
+struct WindowActorOptions;
+namespace {
+StaticRefPtr<JSWindowActorService> gJSWindowActorService;
+}
+
+JSWindowActorService::JSWindowActorService() {
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+JSWindowActorService::~JSWindowActorService() {
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+/* static */ already_AddRefed<JSWindowActorService>
+JSWindowActorService::GetSingleton() {
+  if (!gJSWindowActorService) {
+    gJSWindowActorService = new JSWindowActorService();
+    ClearOnShutdown(&gJSWindowActorService);
+  }
+
+  RefPtr<JSWindowActorService> service = gJSWindowActorService.get();
+  return service.forget();
+}
+
+void JSWindowActorService::RegisterWindowActor(
+    const nsAString& aName, const WindowActorOptions& aOptions,
+    ErrorResult& aRv) {
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  auto entry = mDescriptors.LookupForAdd(aName);
+  if (entry) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  entry.OrInsert([&] { return &aOptions; });
+}
+
+}  // namespace dom
+}  // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/JSWindowActorService.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_JSWindowActorService_h
+#define mozilla_dom_JSWindowActorService_h
+
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+namespace dom {
+struct WindowActorOptions;
+
+class JSWindowActorService final {
+ public:
+  NS_INLINE_DECL_REFCOUNTING(JSWindowActorService)
+
+  static already_AddRefed<JSWindowActorService> GetSingleton();
+
+  void RegisterWindowActor(const nsAString& aName,
+                           const WindowActorOptions& aOptions,
+                           ErrorResult& aRv);
+
+ private:
+  JSWindowActorService();
+  ~JSWindowActorService();
+
+  nsDataHashtable<nsStringHashKey, const WindowActorOptions*> mDescriptors;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_JSWindowActorService_h
\ No newline at end of file
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -35,16 +35,17 @@ EXPORTS.mozilla.dom += [
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'DocShellMessageUtils.h',
     'FilePickerParent.h',
+    'JSWindowActorService.h',
     'MemoryReportRequest.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
@@ -67,16 +68,17 @@ UNIFIED_SOURCES += [
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'ContentProcessManager.cpp',
     'DocShellMessageUtils.cpp',
     'FilePickerParent.cpp',
+    'JSWindowActorService.cpp',
     'MemMapSnapshot.cpp',
     'MemoryReportRequest.cpp',
     'MMPrinter.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/ipc/tests/test_registerWindowActor.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(function test_registerWindowActor() {
+  let windowActorOptions = {
+    parent: {
+      moduleURI: "resource:///actors/TestParent.jsm",
+    },
+    child: {
+      moduleURI: "resource:///actors/TestChild.jsm",
+    },
+  };
+
+  Assert.ok(ChromeUtils, "Should be able to get the ChromeUtils interface");
+  ChromeUtils.registerWindowActor("Test", windowActorOptions);
+  Assert.ok(true);
+  Assert.throws(() =>
+    ChromeUtils.registerWindowActor("Test", windowActorOptions),
+    /NotSupportedError/,
+    "Should throw if register duplicate name.");
+});
--- a/dom/ipc/tests/xpcshell.ini
+++ b/dom/ipc/tests/xpcshell.ini
@@ -1,2 +1,2 @@
-
+[test_registerWindowActor.js]
 [test_sharedMap.js]
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-a5b036eced81dcfc012f1335277af595f931fb11
+da88c56f2448e66421fe8e2cab386a61e8b956b5
--- a/gfx/wr/webrender/src/clip_scroll_tree.rs
+++ b/gfx/wr/webrender/src/clip_scroll_tree.rs
@@ -110,19 +110,19 @@ impl ClipScrollTree {
             spatial_nodes: Vec::new(),
             coord_systems: Vec::new(),
             pending_scroll_offsets: FastHashMap::default(),
             pipelines_to_discard: FastHashSet::default(),
             nodes_to_update: Vec::new(),
         }
     }
 
-    /// Calculate the relative transform from `ref_node_index`
-    /// to `target_node_index`. It's assumed that `ref_node_index`
-    /// is a parent of `target_node_index`. This method will
+    /// Calculate the relative transform from `from_node_index`
+    /// to `to_node_index`. It's assumed that `from_node_index`
+    /// is an ancestor or a descendant of `to_node_index`. This method will
     /// panic if that invariant isn't true!
     pub fn get_relative_transform(
         &self,
         from_node_index: SpatialNodeIndex,
         to_node_index: SpatialNodeIndex,
     ) -> Option<LayoutTransform> {
         let from_node = &self.spatial_nodes[from_node_index.0 as usize];
         let to_node = &self.spatial_nodes[to_node_index.0 as usize];
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -98,22 +98,22 @@ fuzzy-if(skiaContent,0-1,0-1024) == tran
 == background-size-contain-clip-padding-origin-border-padding.html background-size-contain-clip-padding-origin-border-padding-ref.html
 
 == background-layers-1a.html background-layers-1-ref.html
 fuzzy-if(OSX,0-1,0-324) == background-layers-1b.html background-layers-1-ref.html
 
 # box-decoration-break's effect on backgrounds is touchy and hard to test due to stretching
 # artifacts and the difficulty of covering exact lines, so just make sure
 # background-size results in a different rendering when present.
-pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-slice.html
-pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-clone.html background-size-clone.html
+!= background-size-cover-slice.html background-size-slice.html
+!= background-size-cover-clone.html background-size-clone.html
 
 # ...and make sure each rendering with background-size is different from the
 # other
-pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-cover-clone.html
+!= background-size-cover-slice.html background-size-cover-clone.html
 
 random-if(OSX==1010) == background-size-monster-ch.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-cm.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-em.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-ex.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-inches.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-mm.html background-size-monster-ref.html # bug 1129300
 random-if(OSX==1010) == background-size-monster-pc.html background-size-monster-ref.html # bug 1129300
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -596,17 +596,17 @@ fails-if(Android&&!asyncPan) != 367247-l
 == 367612-1c.html 367612-1-ref.html
 == 367612-1d.html 367612-1-ref.html
 == 367612-1e.html 367612-1-ref.html
 == 367612-1f.html 367612-1-ref.html
 != 367612-1g.html 367612-1-ref.html
 fuzzy-if(skiaContent,0-32,0-33) fuzzy-if(d2d,0-5,0-2) == 368020-1.html 368020-1-ref.html
 == 368020-2.html 368020-2-ref.html
 == 368020-3.html 368020-3-ref.html
-pref(layout.css.box-decoration-break.enabled,true) == 368020-5.html 368020-5-ref.html
+== 368020-5.html 368020-5-ref.html
 == 368155-1.xhtml 368155-1-ref.xhtml
 asserts(4) == 368155-negative-margins-1.html 368155-negative-margins-1-ref.html # bug 387205 / bug 457397
 # we can't test this because there's antialiasing involved, and our comparison
 # is too exact
 # == 368247-1.html 368247-1-ref.html
 == 368247-2.html 368247-2-ref.html
 == 368504-1.html 368504-1-ref.html
 == 368504-2.html 368504-2-ref.html
--- a/layout/reftests/css-blending/reftest.list
+++ b/layout/reftests/css-blending/reftest.list
@@ -1,100 +1,100 @@
-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-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
+== blend-canvas.html blend-canvas-ref.html
+== blend-constant-background-color.html blend-constant-background-color-ref.html
+fuzzy-if(webrender,1-3,1313-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
+== blend-image.html blend-image-ref.html
+== 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-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-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
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-10000) fuzzy-if(skiaContent,0-1,0-30000) == background-blending-alpha.html background-blending-alpha-ref.html
+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) == 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) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
+fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-10000) == background-blending-image-color-jpg.html background-blending-image-color-ref.html
+== background-blending-image-color-png.html background-blending-image-color-ref.html
+== background-blending-image-color-svg.html background-blending-image-color-ref.html
+fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1313-7888) == background-blending-image-gradient.html background-blending-gradient-color-ref.html
+== background-blending-image-image.html background-blending-image-color-ref.html
+== background-blending-isolation.html background-blending-isolation-ref.html
+== background-blending-list-repeat.html background-blending-list-repeat-ref.html
+== 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
+== background-blending-color-burn.html background-blending-color-burn-ref.svg
+== 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
-fuzzy-if(azureSkia||gtkWidget,0-2,0-9600) fuzzy-if(d2d,0-1,0-8000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-color.html background-blending-color-ref.svg
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-darken.html background-blending-darken-ref.svg
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-difference.html background-blending-difference-ref.svg
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||skiaContent,0-1,0-1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-exclusion.html background-blending-exclusion-ref.svg
-fuzzy-if(cocoaWidget||d2d,0-1,0-1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-hard-light.html background-blending-hard-light-ref.svg
-fuzzy-if(d2d,0-1,0-9600) fuzzy-if(azureSkia||gtkWidget,0-1,0-11200) fuzzy-if(webrender,1-1,9600-11200) pref(layout.css.background-blend-mode.enabled,true) == background-blending-hue.html background-blending-hue-ref.svg
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-lighten.html background-blending-lighten-ref.svg
-fuzzy-if(d2d,0-1,0-8000) fuzzy-if(azureSkia||gtkWidget,0-2,0-9600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-luminosity.html background-blending-luminosity-ref.svg
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-multiply.html background-blending-multiply-ref.svg
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-normal.html background-blending-normal-ref.svg
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia||gtkWidget,0-1,0-1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-overlay.html background-blending-overlay-ref.svg
-fuzzy-if(d2d,0-1,0-3200) fuzzy-if(azureSkia||gtkWidget,0-2,0-12800) pref(layout.css.background-blend-mode.enabled,true) == background-blending-saturation.html background-blending-saturation-ref.svg
-fuzzy-if(d2d||azureSkia||gtkWidget,0-1,0-1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-screen.html background-blending-screen-ref.svg
-fuzzy-if(d2d||azureSkia||gtkWidget,0-10,0-4800) pref(layout.css.background-blend-mode.enabled,true) == background-blending-soft-light.html background-blending-soft-light-ref.svg
+fuzzy-if(azureSkia||gtkWidget,0-2,0-9600) fuzzy-if(d2d,0-1,0-8000) == background-blending-color.html background-blending-color-ref.svg
+== background-blending-darken.html background-blending-darken-ref.svg
+== background-blending-difference.html background-blending-difference-ref.svg
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||skiaContent,0-1,0-1600) == background-blending-exclusion.html background-blending-exclusion-ref.svg
+fuzzy-if(cocoaWidget||d2d,0-1,0-1600) == background-blending-hard-light.html background-blending-hard-light-ref.svg
+fuzzy-if(d2d,0-1,0-9600) fuzzy-if(azureSkia||gtkWidget,0-1,0-11200) fuzzy-if(webrender,1-1,9600-11200) == background-blending-hue.html background-blending-hue-ref.svg
+== background-blending-lighten.html background-blending-lighten-ref.svg
+fuzzy-if(d2d,0-1,0-8000) fuzzy-if(azureSkia||gtkWidget,0-2,0-9600) == background-blending-luminosity.html background-blending-luminosity-ref.svg
+== background-blending-multiply.html background-blending-multiply-ref.svg
+== background-blending-normal.html background-blending-normal-ref.svg
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia||gtkWidget,0-1,0-1600) == background-blending-overlay.html background-blending-overlay-ref.svg
+fuzzy-if(d2d,0-1,0-3200) fuzzy-if(azureSkia||gtkWidget,0-2,0-12800) == background-blending-saturation.html background-blending-saturation-ref.svg
+fuzzy-if(d2d||azureSkia||gtkWidget,0-1,0-1600) == background-blending-screen.html background-blending-screen-ref.svg
+fuzzy-if(d2d||azureSkia||gtkWidget,0-10,0-4800) == background-blending-soft-light.html background-blending-soft-light-ref.svg
 
-fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-40000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-959674.html background-blending-image-color-959674-ref.html
+fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-40000) == background-blending-image-color-959674.html background-blending-image-color-959674-ref.html
 
 #fuzzy due to inconsistencies in rounded rect cliping between parent and child; may be related to antialiasing. Between platforms, the max difference is the same, and the number of different pixels is either 36 or 37. (Win, Mac and Lin)
-fuzzy(0-65,0-53) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-952051.html mix-blend-mode-952051-ref.html
+fuzzy(0-65,0-53) == mix-blend-mode-952051.html mix-blend-mode-952051-ref.html
 
-fuzzy-if(d3d11,0-49,0-200) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-and-filter.html mix-blend-mode-and-filter-ref.html
-fuzzy-if(d3d11,0-1,0-5) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-and-filter.svg mix-blend-mode-and-filter-ref.svg
+fuzzy-if(d3d11,0-49,0-200) == mix-blend-mode-and-filter.html mix-blend-mode-and-filter-ref.html
+fuzzy-if(d3d11,0-1,0-5) == mix-blend-mode-and-filter.svg mix-blend-mode-and-filter-ref.svg
 
-fuzzy(0-2,0-14400) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-child-of-blended-has-opacity.html mix-blend-mode-child-of-blended-has-opacity-ref.html
+fuzzy(0-2,0-14400) == mix-blend-mode-child-of-blended-has-opacity.html mix-blend-mode-child-of-blended-has-opacity-ref.html
 
-pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-nested-976533.html mix-blend-mode-nested-976533-ref.html
-pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-culling-1207041.html mix-blend-mode-culling-1207041-ref.html
-pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-dest-alpha-1135271.html mix-blend-mode-dest-alpha-1135271-ref.html
+== mix-blend-mode-nested-976533.html mix-blend-mode-nested-976533-ref.html
+== mix-blend-mode-culling-1207041.html mix-blend-mode-culling-1207041-ref.html
+== mix-blend-mode-dest-alpha-1135271.html mix-blend-mode-dest-alpha-1135271-ref.html
 == clipped-mixblendmode-containing-unclipped-stuff.html clipped-mixblendmode-containing-unclipped-stuff-ref.html
 fuzzy(0-1,0-6800) == clipped-opacity-containing-unclipped-mixblendmode.html clipped-opacity-containing-unclipped-mixblendmode-ref.html
 
 # Test plan 5.3.1 Blending between the background layers and the background color for an element with background-blend-mode
 # Test 9
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg-as-data-uri.html background-blending-image-color-ref.html
+== background-blending-image-color-svg-as-data-uri.html background-blending-image-color-ref.html
 # Test 10
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-gif.html background-blending-image-color-gif-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-transform3d.html background-blending-image-color-ref.html
+== background-blending-image-color-gif.html background-blending-image-color-gif-ref.html
+== background-blending-image-color-transform3d.html background-blending-image-color-ref.html
 
 # Test plan 5.3.2 Background layers do not blend with content outside the background (or behind the element) - tests 2 and 3
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation-parent-child-color.html background-blending-isolation-parent-child-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation-parent-child-image.html background-blending-isolation-parent-child-ref.html
+== background-blending-isolation-parent-child-color.html background-blending-isolation-parent-child-ref.html
+== background-blending-isolation-parent-child-image.html background-blending-isolation-parent-child-ref.html
 
 # Test plan 5.3.6 background-blend-mode for an element with background-position
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-position-percentage.html background-blending-background-position-percentage-ref.html
+== background-blending-background-position-percentage.html background-blending-background-position-percentage-ref.html
 
 # Test plan 5.3.7 background-blend-mode for an element with background-size
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-size-contain.html background-blending-background-size-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-size-cover.html background-blending-background-size-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-size-percentage.html background-blending-background-size-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-size-pixels.html background-blending-background-size-ref.html
+== background-blending-background-size-contain.html background-blending-background-size-ref.html
+== background-blending-background-size-cover.html background-blending-background-size-ref.html
+== background-blending-background-size-percentage.html background-blending-background-size-ref.html
+== background-blending-background-size-pixels.html background-blending-background-size-ref.html
 
 # Test plan 5.3.8 background-blend-mode for an element with background-repeat
 # Tests 2 and 3 are not added because space and round are not currently supported
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-repeat-no-repeat.html background-blending-background-repeat-no-repeat-ref.html
+== background-blending-background-repeat-no-repeat.html background-blending-background-repeat-no-repeat-ref.html
 
 # Test plan 5.3.9 background-blend-mode for an element with background-clip
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-clip-content-box.html background-blending-background-clip-content-box-ref.html
-pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-clip-padding-box.html background-blending-background-clip-padding-box-ref.html
+== background-blending-background-clip-content-box.html background-blending-background-clip-content-box-ref.html
+== background-blending-background-clip-padding-box.html background-blending-background-clip-padding-box-ref.html
 
 # 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
+== background-blending-background-origin-border-box.html background-blending-background-origin-ref.html
+== 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
+== background-blending-background-attachement-fixed.html background-blending-background-attachement-fixed-ref.html
+== background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-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
+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) 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
+== 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
+fuzzy(0-1,0-40000) == 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
+== blend-isolation.html blend-isolation-ref.html
 
-pref(layout.css.background-blend-mode.enabled,true) == bug1281593.html bug1281593-ref.html
+== bug1281593.html bug1281593-ref.html
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,10 +1,8 @@
-default-preferences pref(layout.css.box-decoration-break.enabled,true)
-
 == box-decoration-break-1.html box-decoration-break-1-ref.html
 fuzzy(0-1,0-20) fuzzy-if(skiaContent,0-1,0-700) fuzzy-if(webrender,21-26,8908-12681) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 skip-if(verify) fuzzy(0-45,0-460) fuzzy-if(skiaContent,0-57,0-439) fuzzy-if(Android,0-57,0-1330) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543, bug 1392106
 random-if(!gtkWidget) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,0-1,0-62) fuzzy-if(Android,0-8,0-6627) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773 # Bug 1392106
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
--- a/layout/reftests/pagination/reftest.list
+++ b/layout/reftests/pagination/reftest.list
@@ -3,20 +3,20 @@
 # Pagination tests
 # asserts(3) == abspos-breaking-000.xhtml abspos-breaking-000.ref.xhtml # bug 1067755, 1135556
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-001.xhtml abspos-breaking-000.ref.xhtml # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-002.xhtml abspos-breaking-000.ref.xhtml # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-003.html abspos-breaking-003-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-004.html abspos-breaking-004-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-005.html abspos-breaking-005-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-006.html abspos-breaking-006-ref.html # Bug 1392106
-pref(layout.css.box-decoration-break.enabled,true) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-007.html abspos-breaking-007-ref.html # Bug 1392106
-pref(layout.css.box-decoration-break.enabled,true) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-008.html abspos-breaking-008-ref.html # Bug 1392106
-pref(layout.css.box-decoration-break.enabled,true) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-009.html abspos-breaking-009-ref.html # Bug 1392106
-pref(layout.css.box-decoration-break.enabled,true) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-010.html abspos-breaking-010-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-007.html abspos-breaking-007-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-008.html abspos-breaking-008-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-009.html abspos-breaking-009-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == abspos-breaking-010.html abspos-breaking-010-ref.html # Bug 1392106
 == abspos-breaking-011.html abspos-breaking-011-ref.html # Bug 1392106
 == abspos-breaking-dynamic-001.html abspos-breaking-dynamic-001-ref.html
 == abspos-breaking-dynamic-002.html abspos-breaking-dynamic-002-ref.html
 == abspos-breaking-dynamic-003.html abspos-breaking-dynamic-003-ref.html
 == abspos-overflow-01.xhtml abspos-overflow-01.ref.xhtml
 == abspos-overflow-01-cols.xhtml abspos-overflow-01-cols.ref.xhtml
 == border-breaking-000-cols.xhtml border-breaking-000-cols.ref.xhtml
 == border-breaking-001-cols.xhtml border-breaking-001-cols.ref.xhtml
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -7,27 +7,27 @@ HTTP == fixed-opacity-2.html fixed-opaci
 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) 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
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-4.html scroll-behavior-4.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-5.html scroll-behavior-5.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-6.html scroll-behavior-6.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-7.html scroll-behavior-7.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-8.html scroll-behavior-8.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-9.html scroll-behavior-9.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-10.html scroll-behavior-10.html?ref
-pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-textarea.html scroll-behavior-textarea.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-1.html scroll-behavior-1.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-2.html scroll-behavior-2.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-3.html scroll-behavior-3.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-4.html scroll-behavior-4.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-5.html scroll-behavior-5.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-6.html scroll-behavior-6.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-7.html scroll-behavior-7.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-8.html scroll-behavior-8.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-9.html scroll-behavior-9.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-10.html scroll-behavior-10.html?ref
+pref(layout.css.scroll-behavior.enabled,true) == scroll-behavior-textarea.html scroll-behavior-textarea.html?ref
 HTTP == simple-1.html simple-1.html?ref
 HTTP == subpixel-1.html#d subpixel-1-ref.html#d
 fuzzy-if(Android,0-4,0-120) HTTP == text-1.html text-1.html?ref
 fuzzy-if(Android,0-4,0-120) HTTP == text-2.html?up text-2.html?ref
 fuzzy-if(d2d,0-1,0-4) fuzzy-if(webrender,0-1,0-42) HTTP == transformed-1.html transformed-1.html?ref
 fuzzy-if(webrender,0-1,0-43) HTTP == transformed-1.html?up transformed-1.html?ref
 fuzzy-if(Android,0-5,0-20000) == uncovering-1.html uncovering-1-ref.html
 fuzzy-if(Android,0-5,0-20000) == uncovering-2.html uncovering-2-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -26,38 +26,38 @@ include moz-only/reftest.list
 include svg-integration/reftest.list
 
 == background-svg-without-height.html background-ref.html
 == background-svg-without-height-width.html background-ref.html
 == background-svg-without-width.html background-ref.html
 
 == baseline-middle-01.svg pass.svg
 
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-color-burn.svg blend-color-burn-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-color-dodge.svg blend-color-dodge-ref.svg
-# pref(layout.css.mix-blend-mode.enabled,true) == blend-color.svg blend-color-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-darken.svg blend-darken-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-difference.svg blend-difference-ref.svg
-skip-if(Android) fuzzy-if(skiaContent,0-1,0-1600) pref(layout.css.mix-blend-mode.enabled,true) == blend-exclusion.svg blend-exclusion-ref.svg
-# pref(layout.css.mix-blend-mode.enabled,true) == blend-hard-light.svg blend-hard-light-ref.svg
-# pref(layout.css.mix-blend-mode.enabled,true) == blend-hue.svg blend-hue-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-layer-blend.svg blend-layer-blend-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-layer-filter.svg blend-layer-filter-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-layer-mask.svg blend-layer-mask-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-layer-opacity.svg blend-layer-opacity-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-lighten.svg blend-lighten-ref.svg
-# pref(layout.css.mix-blend-mode.enabled,true) == blend-luminosity.svg blend-luminosity-ref.svg
-#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-multiply-alpha.svg blend-multiply-alpha-ref.svg
-skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-multiply.svg blend-multiply-ref.svg
-pref(layout.css.mix-blend-mode.enabled,true) == blend-normal.svg blend-normal-ref.svg
-#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-overlay.svg blend-overlay-ref.svg
-#skip-if(Android)  pref(layout.css.mix-blend-mode.enabled,true) == blend-saturation.svg blend-saturation-ref.svg
-#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-screen.svg blend-screen-ref.svg
-#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-soft-light.svg blend-soft-light-ref.svg
-skip pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html # bug 1458353
+skip-if(Android) == blend-color-burn.svg blend-color-burn-ref.svg
+skip-if(Android) == blend-color-dodge.svg blend-color-dodge-ref.svg
+# == blend-color.svg blend-color-ref.svg
+skip-if(Android) == blend-darken.svg blend-darken-ref.svg
+skip-if(Android) == blend-difference.svg blend-difference-ref.svg
+skip-if(Android) fuzzy-if(skiaContent,0-1,0-1600) == blend-exclusion.svg blend-exclusion-ref.svg
+# == blend-hard-light.svg blend-hard-light-ref.svg
+# == blend-hue.svg blend-hue-ref.svg
+skip-if(Android) == blend-layer-blend.svg blend-layer-blend-ref.svg
+skip-if(Android) == blend-layer-filter.svg blend-layer-filter-ref.svg
+skip-if(Android) == blend-layer-mask.svg blend-layer-mask-ref.svg
+skip-if(Android) == blend-layer-opacity.svg blend-layer-opacity-ref.svg
+skip-if(Android) == blend-lighten.svg blend-lighten-ref.svg
+# == blend-luminosity.svg blend-luminosity-ref.svg
+#skip-if(Android) == blend-multiply-alpha.svg blend-multiply-alpha-ref.svg
+skip-if(Android) == blend-multiply.svg blend-multiply-ref.svg
+== blend-normal.svg blend-normal-ref.svg
+#skip-if(Android) == blend-overlay.svg blend-overlay-ref.svg
+#skip-if(Android)  == blend-saturation.svg blend-saturation-ref.svg
+#skip-if(Android) == blend-screen.svg blend-screen-ref.svg
+#skip-if(Android) == blend-soft-light.svg blend-soft-light-ref.svg
+skip == blend-difference-stacking.html blend-difference-stacking-ref.html # bug 1458353
 
 fuzzy(0-11,0-7155) == blur-inside-clipPath.svg blur-inside-clipPath-ref.svg
 
 == border-radius-01.html pass.svg
 
 == clip-01.svg pass.svg
 == clip-02a.svg clip-02-ref.svg
 == clip-02b.svg clip-02-ref.svg
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1633,16 +1633,24 @@ var gCSSProperties = {
   "-moz-box-pack": {
     domProp: "MozBoxPack",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "start" ],
     other_values: [ "center", "end", "justify" ],
     invalid_values: []
   },
+  "box-decoration-break": {
+    domProp: "boxDecorationBreak",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "slice" ],
+    other_values: [ "clone" ],
+    invalid_values: [ "auto",  "none",  "1px" ],
+  },
   "box-sizing": {
     domProp: "boxSizing",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "content-box" ],
     other_values: [ "border-box" ],
     invalid_values: [ "padding-box", "margin-box", "content", "padding", "border", "margin" ]
   },
@@ -2733,16 +2741,28 @@ var gCSSProperties = {
     type: CSS_TYPE_LONGHAND,
     applies_to_first_letter: true,
     applies_to_first_line: true,
     applies_to_placeholder: true,
     initial_values: [ "scroll" ],
     other_values: [ "fixed", "local", "scroll,scroll", "fixed, scroll", "scroll, fixed, local, scroll", "fixed, fixed" ],
     invalid_values: []
   },
+  "background-blend-mode": {
+    domProp: "backgroundBlendMode",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    applies_to_first_letter: true,
+    applies_to_first_line: true,
+    applies_to_placeholder: true,
+    initial_values: [ "normal" ],
+    other_values: [ "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn",
+      "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity" ],
+    invalid_values: ["none", "10px", "multiply multiply"],
+  },
   "background-clip": {
     /*
      * When we rename this to 'background-clip', we also
      * need to rename the values to match the spec.
      */
     domProp: "backgroundClip",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
@@ -4438,16 +4458,24 @@ var gCSSProperties = {
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "over" ],
     other_values: [ "under" ],
     invalid_values: [
       "left", "right", "auto", "none", "not_a_position",
       "over left", "right under", "0", "100px", "50%"
     ]
   },
+  "scroll-behavior": {
+    domProp: "scrollBehavior",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "smooth" ],
+    invalid_values: [ "none",  "1px" ],
+  },
   "table-layout": {
     domProp: "tableLayout",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
     other_values: [ "fixed" ],
     invalid_values: []
   },
@@ -5193,24 +5221,40 @@ var gCSSProperties = {
   "flood-opacity": {
     domProp: "floodOpacity",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "1", "2.8", "1.000" ],
     other_values: [ "0", "0.3", "-7.3" ],
     invalid_values: []
   },
+  "image-orientation": {
+    domProp: "imageOrientation",
+    inherited: true,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "none" ],
+    other_values: [ "from-image" ],
+    invalid_values: [ "0", "0deg" ],
+  },
   "image-rendering": {
     domProp: "imageRendering",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
     other_values: [ "optimizeSpeed", "optimizeQuality", "-moz-crisp-edges" ],
     invalid_values: []
   },
+  "isolation": {
+    domProp: "isolation",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: ["isolate"],
+    invalid_values: [],
+  },
   "lighting-color": {
     domProp: "lightingColor",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     prerequisites: { "color": "blue" },
     initial_values: [ "white", "#fff", "#ffffff", "rgb(255,255,255)", "rgba(255,255,255,1.0)", "rgba(255,255,255,42.0)" ],
     other_values: [ "green", "#fc3", "currentColor" ],
     invalid_values: [ "url('#myserver')", "url(foo.svg#myserver)", 'url("#myserver") green', "000000", "ff00ff" ]
@@ -5243,16 +5287,25 @@ var gCSSProperties = {
   "marker-start": {
     domProp: "markerStart",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "none" ],
     other_values: [ "url(#mysym)" ],
     invalid_values: []
   },
+  "mix-blend-mode": {
+    domProp: "mixBlendMode",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "normal" ],
+    other_values: ["multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn",
+        "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"],
+    invalid_values: [],
+  },
   "shape-image-threshold": {
     domProp: "shapeImageThreshold",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     applies_to_first_letter: true,
     initial_values: [ "0", "0.0000", "-3", ],
     other_values: [ "0.4", "1", "17", "397.376", "3e1", "3e+1", "3e-1", "3e0", "3e+0", "3e-0" ],
     invalid_values: [ "0px", "1px", "20%", "default", "auto" ]
@@ -7183,26 +7236,16 @@ if (IsCSSPropertyPrefEnabled("layout.css
       "strict strict",
       "auto",
       "10px",
       "0",
     ]
   };
 }
 
-if (IsCSSPropertyPrefEnabled("layout.css.image-orientation.enabled")) {
-  gCSSProperties["image-orientation"] = {
-    domProp: "imageOrientation",
-    inherited: true,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "none" ],
-    other_values: [ "from-image" ],
-    invalid_values: [ "0", "0deg" ]
-  };
-}
 
 if (IsCSSPropertyPrefEnabled("layout.css.initial-letter.enabled")) {
   gCSSProperties["initial-letter"] = {
     domProp: "initialLetter",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     applies_to_first_letter: true,
     initial_values: [ "normal" ],
@@ -7220,54 +7263,16 @@ if (IsCSSPropertyPrefEnabled("layout.css
     applies_to_first_line: true,
     applies_to_placeholder: true,
     initial_values: [ "auto" ],
     other_values: [ "grayscale" ],
     invalid_values: [ "none", "subpixel-antialiased", "antialiased" ]
   };
 }
 
-if (IsCSSPropertyPrefEnabled("layout.css.mix-blend-mode.enabled")) {
-  gCSSProperties["mix-blend-mode"] = {
-    domProp: "mixBlendMode",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "normal" ],
-    other_values: ["multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn",
-        "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"],
-    invalid_values: []
-  };
-}
-
-if (IsCSSPropertyPrefEnabled("layout.css.isolation.enabled")) {
-  gCSSProperties["isolation"] = {
-    domProp: "isolation",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "auto" ],
-    other_values: ["isolate"],
-    invalid_values: []
-  };
-}
-
-if (IsCSSPropertyPrefEnabled("layout.css.background-blend-mode.enabled")) {
-  gCSSProperties["background-blend-mode"] = {
-    domProp: "backgroundBlendMode",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    applies_to_first_letter: true,
-    applies_to_first_line: true,
-    applies_to_placeholder: true,
-    initial_values: [ "normal" ],
-    other_values: [ "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn",
-      "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity" ],
-    invalid_values: ["none", "10px", "multiply multiply"]
-  };
-}
-
 if (IsCSSPropertyPrefEnabled("layout.css.overflow-clip-box.enabled")) {
   gCSSProperties["overflow-clip-box-block"] = {
     domProp: "overflowClipBoxBlock",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     applies_to_placeholder: true,
     initial_values: [ "padding-box" ],
     other_values: [ "content-box" ],
@@ -7290,38 +7295,16 @@ if (IsCSSPropertyPrefEnabled("layout.css
     initial_values: [ "padding-box" ],
     other_values: [ "content-box", "padding-box content-box", "content-box padding-box",
                     "content-box content-box" ],
     invalid_values: [ "none", "auto", "content-box none", "border-box", "0",
                       "content-box, content-box" ]
   };
 }
 
-if (IsCSSPropertyPrefEnabled("layout.css.box-decoration-break.enabled")) {
-  gCSSProperties["box-decoration-break"] = {
-    domProp: "boxDecorationBreak",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "slice" ],
-    other_values: [ "clone" ],
-    invalid_values: [ "auto",  "none",  "1px" ]
-  };
-}
-
-if (IsCSSPropertyPrefEnabled("layout.css.scroll-behavior.property-enabled")) {
-  gCSSProperties["scroll-behavior"] = {
-    domProp: "scrollBehavior",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "auto" ],
-    other_values: [ "smooth" ],
-    invalid_values: [ "none",  "1px" ]
-  };
-}
-
 if (IsCSSPropertyPrefEnabled("layout.css.overscroll-behavior.enabled")) {
   gCSSProperties["overscroll-behavior-x"] = {
     domProp: "overscrollBehaviorX",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
     other_values: [ "contain", "none" ],
     invalid_values: [ "left", "1px" ]
--- a/layout/style/test/test_background_blend_mode.html
+++ b/layout/style/test/test_background_blend_mode.html
@@ -44,15 +44,14 @@ function test_bug_841601() {
      "set all blendmodes");
 
   p.remove();
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({ "set": [["layout.css.background-blend-mode.enabled", true]] },
-                          test_bug_841601);
+test_bug_841601();
 
 </script>
 </pre>
 </body>
 </html>
--- a/layout/style/test/test_computed_style_prefs.html
+++ b/layout/style/test/test_computed_style_prefs.html
@@ -63,19 +63,16 @@ function step() {
   gPrefsPushed = true;
   SpecialPowers.pushPrefEnv(gTests[gTestIndex].settings,
                             function() { fn(); SimpleTest.executeSoon(step); });
 }
 
 // ----
 
 var gProps = {
-  "layout.css.image-orientation.enabled": ["image-orientation"],
-  "layout.css.mix-blend-mode.enabled": ["mix-blend-mode"],
-  "layout.css.isolation.enabled": [ "isolation"],
   "layout.css.touch_action.enabled": ["touch-action"],
   "svg.transform-box.enabled": ["transform-box"]
 };
 
 var gCS = getComputedStyle(document.body, "");
 var gLengthWithAllPrefsDisabled;
 
 var gTestIndex = 0;
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
@@ -196,16 +196,17 @@ public class GeckoPreferenceFragment ext
         if (!currentLocale.equals(lastLocale)) {
             // Locales differ. Let's redisplay.
             Log.d(LOGTAG, "Locale changed: " + currentLocale);
             this.lastLocale = currentLocale;
 
             // Rebuild the list to reflect the current locale.
             getPreferenceScreen().removeAll();
             addPreferencesFromResource(getResource());
+            syncPreference = (SyncPreference) findPreference(GeckoPreferences.PREFS_SYNC);
         }
 
         // Fix the parent title regardless.
         updateParentTitle();
     }
 
     /*
      * Get the resource from Fragment arguments and return it.
--- a/mobile/android/tests/browser/chrome/head_search.js
+++ b/mobile/android/tests/browser/chrome/head_search.js
@@ -1,12 +1,12 @@
 // Bits and pieces copied from toolkit/components/search/tests/xpcshell/head_search.js
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/Task.jsm");
+ChromeUtils.import("resource://testing-common/Task.jsm");
 
 /**
  * Adds test engines and returns a promise resolved when they are installed.
  *
  * The engines are added in the given order.
  *
  * @param aItems
  *        Array of objects with the following properties:
--- a/mobile/android/tests/browser/chrome/test_session_form_data.html
+++ b/mobile/android/tests/browser/chrome/test_session_form_data.html
@@ -14,17 +14,17 @@ Migrated from Robocop: https://bugzilla.
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript">
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/Task.jsm");
+ChromeUtils.import("resource://testing-common/Task.jsm");
 
 let gChromeWin;
 let gBrowserApp;
 
 // Waiting for a tab to load or restore can be slow on the emulator.
 SimpleTest.requestLongerTimeout(2);
 
 setup_browser();
--- a/mobile/android/tests/browser/chrome/test_session_scroll_position.html
+++ b/mobile/android/tests/browser/chrome/test_session_scroll_position.html
@@ -19,17 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   /** Tests for Bug 810981, 1282902, 1301016, 1265818, 1498892 **/
 
   "use strict";
 
   ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
   ChromeUtils.import("resource://gre/modules/Services.jsm");
   ChromeUtils.import("resource://gre/modules/Messaging.jsm");
-  ChromeUtils.import("resource://gre/modules/Task.jsm");
+  ChromeUtils.import("resource://testing-common/Task.jsm");
 
   // The chrome window and friends.
   let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
   let BrowserApp = chromeWin.BrowserApp;
 
   const BASE = "http://example.org/chrome/mobile/android/tests/browser/chrome/";
   // Use something with ample space for scrolling and zooming.
   const URL = BASE + "browser_scrollPositions_sample.html";
--- a/mobile/android/tests/browser/robocop/robocop_head.js
+++ b/mobile/android/tests/browser/robocop/robocop_head.js
@@ -700,17 +700,17 @@ var _Task;
  *   }
  *
  *   do_check_eq(result, "foo");
  * });
  */
 function add_task(func) {
   if (!_Task) {
     let ns = {};
-    _Task = Components.utils.import("resource://gre/modules/Task.jsm", ns).Task;
+    _Task = Components.utils.import("resource://testing-common/Task.jsm", ns).Task;
   }
 
   _gTests.push([true, func]);
 }
 
 /**
  * Runs the next test function from the list of async tests.
  */
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3018,22 +3018,16 @@ pref("layout.css.dpi", -1);
 pref("layout.css.devPixelsPerPx", "-1.0");
 
 // Is support for CSS individual transform enabled?
 pref("layout.css.individual-transform.enabled", false);
 
 // Is support for CSS initial-letter property enabled?
 pref("layout.css.initial-letter.enabled", false);
 
-// Is support for mix-blend-mode enabled?
-pref("layout.css.mix-blend-mode.enabled", true);
-
-// Is support for isolation enabled?
-pref("layout.css.isolation.enabled", true);
-
 // Is support for scrollbar-color property enabled?
 pref("layout.css.scrollbar-color.enabled", true);
 
 // Is support for scrollbar-width property enabled?
 pref("layout.css.scrollbar-width.enabled", true);
 
 // Set the threshold distance in CSS pixels below which scrolling will snap to
 // an edge, when scroll snapping is set to "proximity".
@@ -3070,60 +3064,48 @@ pref("layout.css.getBoxQuads.enabled", t
 pref("layout.css.convertFromNode.enabled", false);
 #else
 pref("layout.css.convertFromNode.enabled", true);
 #endif
 
 // Is support for CSS text-justify property enabled?
 pref("layout.css.text-justify.enabled", true);
 
-// Is support for the CSS image-orientation property enabled?
-pref("layout.css.image-orientation.enabled", true);
-
 // Is the paint-order property supported for HTML text?
 // (It is always supported for SVG.)
 pref("layout.css.paint-order.enabled", true);
 
 // Are sets of prefixed properties supported?
 pref("layout.css.prefixes.border-image", true);
 pref("layout.css.prefixes.transforms", true);
 pref("layout.css.prefixes.transitions", true);
 pref("layout.css.prefixes.animations", true);
 pref("layout.css.prefixes.box-sizing", true);
 pref("layout.css.prefixes.font-features", true);
 
-// Is support for background-blend-mode enabled?
-pref("layout.css.background-blend-mode.enabled", true);
-
 // Is -moz-osx-font-smoothing enabled?
 // Only supported in OSX builds
 #ifdef XP_MACOSX
 pref("layout.css.osx-font-smoothing.enabled", true);
 #else
 pref("layout.css.osx-font-smoothing.enabled", false);
 #endif
 
 // Is support for CSS overflow-clip-box enabled for non-UA sheets?
 pref("layout.css.overflow-clip-box.enabled", false);
 
 // Is support for CSS contain enabled?
 pref("layout.css.contain.enabled", false);
 
-// Is support for CSS box-decoration-break enabled?
-pref("layout.css.box-decoration-break.enabled", true);
-
 // Is layout of CSS outline-style:auto enabled?
 pref("layout.css.outline-style-auto.enabled", false);
 
 // Is CSSOM-View scroll-behavior and its MSD smooth scrolling enabled?
 pref("layout.css.scroll-behavior.enabled", true);
 
-// Is the CSSOM-View scroll-behavior CSS property enabled?
-pref("layout.css.scroll-behavior.property-enabled", true);
-
 // Tuning of the smooth scroll motion used by CSSOM-View scroll-behavior.
 // Spring-constant controls the strength of the simulated MSD
 // (Mass-Spring-Damper)
 pref("layout.css.scroll-behavior.spring-constant", "250.0");
 
 // Tuning of the smooth scroll motion used by CSSOM-View scroll-behavior.
 // Damping-ratio controls the dampening force of the simulated MSD
 // (Mass-Spring-Damper).
@@ -5837,19 +5819,16 @@ pref("webextensions.storage.sync.serverU
 pref("dom.input.fallbackUploadDir", "");
 
 // Turn rewriting of youtube embeds on/off
 pref("plugins.rewrite_youtube_embeds", true);
 
 // Disable browser frames by default
 pref("dom.mozBrowserFramesEnabled", false);
 
-// Is support for 'color-adjust' CSS property enabled?
-pref("layout.css.color-adjust.enabled", true);
-
 pref("dom.audiochannel.audioCompeting", false);
 pref("dom.audiochannel.audioCompeting.allAgents", false);
 
 // Default media volume
 pref("media.default_volume", "1.0");
 
 pref("media.seekToNextFrame.enabled", true);
 
--- a/servo/components/style/properties/longhands/background.mako.rs
+++ b/servo/components/style/properties/longhands/background.mako.rs
@@ -103,13 +103,12 @@
 
 // https://drafts.fxtf.org/compositing/#background-blend-mode
 ${helpers.single_keyword(
     "background-blend-mode",
     """normal multiply screen overlay darken lighten color-dodge
     color-burn hard-light soft-light difference exclusion hue
     saturation color luminosity""",
     gecko_constant_prefix="NS_STYLE_BLEND",
-    gecko_pref="layout.css.background-blend-mode.enabled",
     vector=True, products="gecko", animation_value_type="discrete",
     spec="https://drafts.fxtf.org/compositing/#background-blend-mode",
     flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
 )}
--- a/servo/components/style/properties/longhands/border.mako.rs
+++ b/servo/components/style/properties/longhands/border.mako.rs
@@ -83,17 +83,16 @@
         animation_value_type="BorderCornerRadius",
     )}
 % endfor
 
 ${helpers.single_keyword(
     "box-decoration-break",
     "slice clone",
     gecko_enum_prefix="StyleBoxDecorationBreak",
-    gecko_pref="layout.css.box-decoration-break.enabled",
     spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
     products="gecko",
     animation_value_type="discrete",
 )}
 
 ${helpers.single_keyword(
     "-moz-float-edge",
     "content-box margin-box",
--- a/servo/components/style/properties/longhands/box.mako.rs
+++ b/servo/components/style/properties/longhands/box.mako.rs
@@ -384,17 +384,16 @@
     spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
 )}
 
 // CSSOM View Module
 // https://www.w3.org/TR/cssom-view-1/
 ${helpers.single_keyword(
     "scroll-behavior",
     "auto smooth",
-    gecko_pref="layout.css.scroll-behavior.property-enabled",
     products="gecko",
     spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior",
     animation_value_type="discrete",
 )}
 
 % for axis in ["x", "y"]:
     ${helpers.predefined_type(
         "scroll-snap-type-" + axis,
@@ -422,17 +421,16 @@
 % endfor
 
 // Compositing and Blending Level 1
 // http://www.w3.org/TR/compositing-1/
 ${helpers.single_keyword(
     "isolation",
     "auto isolate",
     products="gecko",
-    gecko_pref="layout.css.isolation.enabled",
     spec="https://drafts.fxtf.org/compositing/#isolation",
     flags="CREATES_STACKING_CONTEXT",
     animation_value_type="discrete",
 )}
 
 ${helpers.predefined_type(
     "break-after",
     "BreakBetween",
--- a/servo/components/style/properties/longhands/effects.mako.rs
+++ b/servo/components/style/properties/longhands/effects.mako.rs
@@ -57,11 +57,10 @@
 ${helpers.single_keyword(
     "mix-blend-mode",
     """normal multiply screen overlay darken lighten color-dodge
     color-burn hard-light soft-light difference exclusion hue
     saturation color luminosity""",
     gecko_constant_prefix="NS_STYLE_BLEND",
     animation_value_type="discrete",
     flags="CREATES_STACKING_CONTEXT",
-    gecko_pref="layout.css.mix-blend-mode.enabled",
     spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode",
 )}
--- a/servo/components/style/properties/longhands/inherited_box.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_box.mako.rs
@@ -50,17 +50,16 @@
 )}
 
 // CSS Color Module Level 4
 // https://drafts.csswg.org/css-color/
 ${helpers.single_keyword(
     "color-adjust",
     "economy exact", products="gecko",
     gecko_enum_prefix="StyleColorAdjust",
-    gecko_pref="layout.css.color-adjust.enabled",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-color/#propdef-color-adjust",
 )}
 
 // According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
 // And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
 ${helpers.single_keyword(
     "image-rendering",
@@ -73,11 +72,10 @@
 )}
 
 ${helpers.single_keyword(
     "image-orientation",
     "none from-image",
     products="gecko",
     gecko_enum_prefix="StyleImageOrientation",
     animation_value_type="discrete",
-    gecko_pref="layout.css.image-orientation.enabled",
     spec="https://drafts.csswg.org/css-images/#propdef-image-orientation",
 )}
--- a/testing/mochitest/BrowserTestUtils/content/content-task.js
+++ b/testing/mochitest/BrowserTestUtils/content/content-task.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* eslint-env mozilla/frame-script */
 
 "use strict";
 
-ChromeUtils.import("resource://gre/modules/Task.jsm", this);
+ChromeUtils.import("resource://testing-common/Task.jsm", this);
 ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
 const AssertCls = ChromeUtils.import("resource://testing-common/Assert.jsm", null).Assert;
 
 addMessageListener("content-task:spawn", function(msg) {
   let id = msg.data.id;
   let source = msg.data.runnable || "()=>{}";
 
   function getStack(aStack) {
--- a/testing/mozharness/mozharness/mozilla/testing/raptor.py
+++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py
@@ -598,24 +598,32 @@ class Raptor(TestingMixin, MercurialScri
                 self.run_command(["ls", "-l", item])
 
         elif '--no-upload-results' not in options:
             if not self.gecko_profile:
                 self._validate_treeherder_data(parser)
             if not self.run_local:
                 # copy results to upload dir so they are included as an artifact
                 self.info("copying raptor results to upload dir:")
+
+                src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'raptor.json')
                 dest = os.path.join(env['MOZ_UPLOAD_DIR'], 'perfherder-data.json')
                 self.info(str(dest))
-                src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'raptor.json')
                 self._artifact_perf_data(src, dest)
+
                 if self.power_test:
                     src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'raptor-power.json')
                     self._artifact_perf_data(src, dest)
 
+                src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'screenshots.html')
+                if os.path.exists(src):
+                    dest = os.path.join(env['MOZ_UPLOAD_DIR'], 'screenshots.html')
+                    self.info(str(dest))
+                    self._artifact_perf_data(src, dest)
+
 
 class RaptorOutputParser(OutputParser):
     minidump_regex = re.compile(r'''raptorError: "error executing: '(\S+) (\S+) (\S+)'"''')
     RE_PERF_DATA = re.compile(r'.*PERFHERDER_DATA:\s+(\{.*\})')
 
     def __init__(self, **kwargs):
         super(RaptorOutputParser, self).__init__(**kwargs)
         self.minidump_output = None
--- a/testing/raptor/raptor/control_server.py
+++ b/testing/raptor/raptor/control_server.py
@@ -63,27 +63,35 @@ def MakeCustomHandlerClass(results_handl
 
             if data['type'] == "webext_gecko_profile":
                 # received gecko profiling results
                 _test = str(data['data'][0])
                 _pagecycle = str(data['data'][1])
                 _raw_profile = data['data'][2]
                 LOG.info("received gecko profile for test %s pagecycle %s" % (_test, _pagecycle))
                 self.write_raw_gecko_profile(_test, _pagecycle, _raw_profile)
+            elif data['type'] == 'webext_results':
+                LOG.info("received " + data['type'] + ": " + str(data['data']))
+                self.results_handler.add(data['data'])
+            elif data['type'] == "webext_raptor-page-timeout":
+                LOG.info("received " + data['type'] + ": " + str(data['data']))
+                # pageload test has timed out; record it as a failure
+                self.results_handler.add_page_timeout(str(data['data'][0]),
+                                                      str(data['data'][1]))
+            elif data['data'] == "__raptor_shutdownBrowser":
+                LOG.info("received " + data['type'] + ": " + str(data['data']))
+                # webext is telling us it's done, and time to shutdown the browser
+                self.shutdown_browser()
+            elif data['type'] == 'webext_screenshot':
+                LOG.info("received " + data['type'])
+                self.results_handler.add_image(str(data['data'][0]),
+                                               str(data['data'][1]),
+                                               str(data['data'][2]))
             else:
                 LOG.info("received " + data['type'] + ": " + str(data['data']))
-                if data['type'] == 'webext_results':
-                    self.results_handler.add(data['data'])
-                elif data['type'] == "webext_raptor-page-timeout":
-                    # pageload test has timed out; record it as a failure
-                    self.results_handler.add_page_timeout(str(data['data'][0]),
-                                                          str(data['data'][1]))
-                elif data['data'] == "__raptor_shutdownBrowser":
-                    # webext is telling us it's done, and time to shutdown the browser
-                    self.shutdown_browser()
 
         def do_OPTIONS(self):
             self.send_response(200, "ok")
             self.send_header('Access-Control-Allow-Origin', '*')
             self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
             self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
             self.send_header("Access-Control-Allow-Headers", "Content-Type")
             self.end_headers()
--- a/testing/raptor/raptor/manifest.py
+++ b/testing/raptor/raptor/manifest.py
@@ -106,16 +106,19 @@ def write_test_settings_json(args, test_
     if val == "false":
         test_settings['raptor-options']['subtest_lower_is_better'] = False
     else:
         test_settings['raptor-options']['subtest_lower_is_better'] = True
 
     if test_details.get("alert_threshold", None) is not None:
         test_settings['raptor-options']['alert_threshold'] = float(test_details['alert_threshold'])
 
+    if test_details.get("screen_capture", None) is not None:
+        test_settings['raptor-options']['screen_capture'] = test_details.get("screen_capture")
+
     # if gecko profiling is enabled, write profiling settings for webext
     if test_details.get("gecko_profile", False):
         test_settings['raptor-options']['gecko_profile'] = True
         # when profiling, if webRender is enabled we need to set that, so
         # the runner can add the web render threads to gecko profiling
         test_settings['raptor-options']['gecko_profile_interval'] = \
             float(test_details.get("gecko_profile_interval", 0))
         test_settings['raptor-options']['gecko_profile_entries'] = \
--- a/testing/raptor/raptor/output.py
+++ b/testing/raptor/raptor/output.py
@@ -24,16 +24,17 @@ class Output(object):
     def __init__(self, results, supporting_data):
         """
         - results : list of RaptorTestResult instances
         """
         self.results = results
         self.summarized_results = {}
         self.supporting_data = supporting_data
         self.summarized_supporting_data = []
+        self.summarized_screenshots = []
 
     def summarize(self):
         suites = []
         test_results = {
             'framework': {
                 'name': 'raptor',
             },
             'suites': suites,
@@ -550,35 +551,81 @@ class Output(object):
             _subtests[name]['value'] = round(filter.median(_subtests[name]['replicates']), 2)
             subtests.append(_subtests[name])
             # only use the 'total's to compute the overall result
             if name == 'total':
                 vals.append([_subtests[name]['value'], name])
 
         return subtests, vals
 
+    def summarize_screenshots(self, screenshots):
+        if len(screenshots) == 0:
+            return
+
+        self.summarized_screenshots.append("""<!DOCTYPE html>
+        <head>
+        <style>
+            table, th, td {
+              border: 1px solid black;
+              border-collapse: collapse;
+            }
+        </style>
+        </head>
+        <html> <body>
+        <h1>Captured screenshots!</h1>
+        <table style="width:100%">
+          <tr>
+            <th>Test Name</th>
+            <th>Pagecycle</th>
+            <th>Screenshot</th>
+          </tr>""")
+
+        for screenshot in screenshots:
+            self.summarized_screenshots.append("""<tr>
+            <th>%s</th>
+            <th> %s</th>
+            <th>
+                <img src="%s" alt="%s %s" width="320" height="240">
+            </th>
+            </tr>""" % (screenshot['test_name'],
+                        screenshot['page_cycle'],
+                        screenshot['screenshot'],
+                        screenshot['test_name'],
+                        screenshot['page_cycle']))
+
+        self.summarized_screenshots.append("""</table></body> </html>""")
+
     def output(self):
         """output to file and perfherder data json """
         if self.summarized_results == {}:
             LOG.error("error: no summarized raptor results found!")
             return False
 
         if os.environ['MOZ_UPLOAD_DIR']:
             # i.e. testing/mozharness/build/raptor.json locally; in production it will
             # be at /tasks/task_*/build/ (where it will be picked up by mozharness later
             # and made into a tc artifact accessible in treeherder as perfherder-data.json)
             results_path = os.path.join(os.path.dirname(os.environ['MOZ_UPLOAD_DIR']),
                                         'raptor.json')
+            screenshot_path = os.path.join(os.path.dirname(os.environ['MOZ_UPLOAD_DIR']),
+                                           'screenshots.html')
         else:
             results_path = os.path.join(os.getcwd(), 'raptor.json')
+            screenshot_path = os.path.join(os.getcwd(), 'screenshots.html')
 
         with open(results_path, 'w') as f:
             for result in self.summarized_results:
                 f.write("%s\n" % result)
 
+        if len(self.summarized_screenshots) > 0:
+            with open(screenshot_path, 'w') as f:
+                for result in self.summarized_screenshots:
+                    f.write("%s\n" % result)
+            LOG.info("screen captures can be found locally at: %s" % screenshot_path)
+
         # when gecko_profiling, we don't want results ingested by Perfherder
         extra_opts = self.summarized_results['suites'][0].get('extraOptions', [])
         if 'gecko_profile' not in extra_opts:
             # if we have supporting data i.e. power, we ONLY want those measurements
             # dumped out. TODO: Bug 1515406 - Add option to output both supplementary
             # data (i.e. power) and the regular Raptor test result
             # Both are already available as separate PERFHERDER_DATA json blobs
             if len(self.summarized_supporting_data) == 0:
--- a/testing/raptor/raptor/results.py
+++ b/testing/raptor/raptor/results.py
@@ -14,24 +14,32 @@ LOG = get_proxy_logger(component='result
 
 
 class RaptorResultsHandler():
     """Handle Raptor test results"""
 
     def __init__(self):
         self.results = []
         self.page_timeout_list = []
+        self.images = []
         self.supporting_data = None
 
     def add(self, new_result_json):
         # add to results
         LOG.info("received results in RaptorResultsHandler.add")
         new_result = RaptorTestResult(new_result_json)
         self.results.append(new_result)
 
+    def add_image(self, screenshot, test_name, page_cycle):
+        # add to results
+        LOG.info("received screenshot")
+        self.images.append({'screenshot': screenshot,
+                            'test_name': test_name,
+                            'page_cycle': page_cycle})
+
     def add_page_timeout(self, test_name, page_url):
         self.page_timeout_list.append({'test_name': test_name, 'url': page_url})
 
     def add_supporting_data(self, supporting_data):
         ''' Supporting data is additional data gathered outside of the regular
         Raptor test run (i.e. power data). Will arrive in a dict in the format of:
 
         supporting_data = {'type': 'data-type',
@@ -58,16 +66,17 @@ class RaptorResultsHandler():
             self.supporting_data = []
         self.supporting_data.append(supporting_data)
 
     def summarize_and_output(self, test_config):
         # summarize the result data, write to file and output PERFHERDER_DATA
         LOG.info("summarizing raptor test results")
         output = Output(self.results, self.supporting_data)
         output.summarize()
+        output.summarize_screenshots(self.images)
         if self.supporting_data is not None:
             output.summarize_supporting_data()
             output.output_supporting_data()
         return output.output()
 
 
 class RaptorTestResult():
     """Single Raptor test result class"""
--- a/testing/raptor/webext/raptor/runner.js
+++ b/testing/raptor/webext/raptor/runner.js
@@ -53,16 +53,17 @@ var isTTFIPending = false;
 var isLoadTimePending = false;
 var isBenchmarkPending = false;
 var pageTimeout = 10000; // default pageload timeout
 var geckoProfiling = false;
 var geckoInterval = 1;
 var geckoEntries = 1000000;
 var webRenderEnabled = false;
 var debugMode = 0;
+var screenCapture = false;
 
 var results = {"name": "",
                "page": "",
                "type": "",
                "lower_is_better": true,
                "alert_threshold": 2.0,
                "measurements": {}};
 
@@ -116,16 +117,20 @@ function getTestSettings() {
               geckoEntries = settings.gecko_entries;
             }
             if (settings.webrender_enabled !== undefined) {
               webRenderEnabled = settings.webrender_enabled;
             }
           }
         }
 
+        if (settings.screen_capture !== undefined) {
+          screenCapture = settings.screen_capture;
+        }
+
         if (settings.newtab_per_cycle !== undefined) {
           reuseTab = settings.newtab_per_cycle;
         }
 
         if (settings.page_timeout !== undefined) {
           pageTimeout = settings.page_timeout;
         }
         console.log("using page timeout (ms): " + pageTimeout);
@@ -235,37 +240,74 @@ function waitForResult() {
             !isDCFPending &&
             !isTTFIPending &&
             !isLoadTimePending) {
           cancelTimeoutAlarm("raptor-page-timeout");
           postToControlServer("status", "results received");
           if (geckoProfiling) {
             await getGeckoProfile();
           }
+          if (screenCapture) {
+            await getScreenCapture();
+          }
+
           resolve();
         } else {
           setTimeout(checkForResult, 5);
         }
       } else if (testType == "benchmark") {
         if (!isBenchmarkPending) {
           cancelTimeoutAlarm("raptor-page-timeout");
           postToControlServer("status", "results received");
           if (geckoProfiling) {
             await getGeckoProfile();
           }
           resolve();
+          if (screenCapture) {
+            await getScreenCapture();
+          }
         } else {
           setTimeout(checkForResult, 5);
         }
       }
     }
     checkForResult();
   });
 }
 
+async function getScreenCapture() {
+  console.log("Capturing screenshot...");
+  var capturing;
+  if (["firefox", "geckoview"].includes(browserName)) {
+    capturing = ext.tabs.captureVisibleTab();
+    capturing.then(onCaptured, onError);
+    await capturing;
+  } else {
+    // create capturing promise
+    capturing =  new Promise(function(resolve, reject) {
+    ext.tabs.captureVisibleTab(resolve);
+  });
+
+    // capture and wait for promise to end
+    capturing.then(onCaptured, onError);
+    await capturing;
+  }
+}
+
+function onCaptured(screenshotUri) {
+  console.log("Screenshot capured!");
+  postToControlServer("screenshot", [screenshotUri, testName, pageCycle]);
+}
+
+function onError(error) {
+  console.log("Screenshot captured failed!");
+  console.log(`Error: ${error}`);
+}
+
+
 async function startGeckoProfiling() {
   var _threads;
   if (webRenderEnabled) {
     _threads = ["GeckoMain", "Compositor", "WR,Renderer"];
   } else {
     _threads = ["GeckoMain", "Compositor"];
   }
   postToControlServer("status", "starting gecko profiling");
@@ -471,16 +513,17 @@ function postToControlServer(msgType, ms
     }
   };
 
   client.open("POST", url, true);
 
   client.setRequestHeader("Content-Type", "application/json");
   if (client.readyState == 1) {
     console.log("posting to control server");
+    console.log(msgData);
     var data = { "type": "webext_" + msgType, "data": msgData};
     client.send(JSON.stringify(data));
   }
   if (msgType == "results") {
     // we're finished, move to cleanup
     cleanUp();
   }
 }
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -35,17 +35,17 @@ var _profileInitialized = false;
 var _XPCSHELL_PROCESS;
 
 // Register the testing-common resource protocol early, to have access to its
 // modules.
 var _Services = ChromeUtils.import("resource://gre/modules/Services.jsm", null).Services;
 _register_modules_protocol_handler();
 
 var _PromiseTestUtils = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", null).PromiseTestUtils;
-var _Task = ChromeUtils.import("resource://gre/modules/Task.jsm", null).Task;
+var _Task = ChromeUtils.import("resource://testing-common/Task.jsm", null).Task;
 
 let _NetUtil = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", null).NetUtil;
 
 let _XPCOMUtils = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", null).XPCOMUtils;
 
 // Support a common assertion library, Assert.jsm.
 var AssertCls = ChromeUtils.import("resource://testing-common/Assert.jsm", null).Assert;
 // Pass a custom report function for xpcshell-test style reporting.
--- a/toolkit/components/asyncshutdown/AsyncShutdown.jsm
+++ b/toolkit/components/asyncshutdown/AsyncShutdown.jsm
@@ -38,18 +38,16 @@
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
 ChromeUtils.import("resource://gre/modules/Services.jsm", this);
 
 ChromeUtils.defineModuleGetter(this, "PromiseUtils",
   "resource://gre/modules/PromiseUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "Task",
-  "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gDebug",
   "@mozilla.org/xpcom/debug;1", "nsIDebug2");
 Object.defineProperty(this, "gCrashReporter", {
   get() {
     delete this.gCrashReporter;
     try {
       let reporter = Cc["@mozilla.org/xre/app-info;1"].
             getService(Ci.nsICrashReporter);
@@ -308,27 +306,21 @@ function getOrigin(topFrame, filename = 
       filename = frame ? frame.filename : "?";
     }
     if (lineNumber == null) {
       lineNumber = frame ? frame.lineNumber : 0;
     }
     if (stack == null) {
       // Now build the rest of the stack as a string, using Task.jsm's rewriting
       // to ensure that we do not lose information at each call to `Task.spawn`.
-      let frames = [];
+      stack = [];
       while (frame != null) {
-        frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
+        stack.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
         frame = frame.caller;
       }
-      stack = frames.join("\n");
-      // Avoid loading Task.jsm if there's no task on the stack.
-      if (stack.includes("/Task.jsm:")) {
-        stack = Task.Debugging.generateReadableStack(stack);
-      }
-      stack = stack.split("\n");
     }
 
     return {
       filename,
       lineNumber,
       stack,
     };
   } catch (ex) {
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -43,18 +43,16 @@ var OSError = SysAll.Error;
 var Type = SysAll.Type;
 
 var Path = {};
 ChromeUtils.import("resource://gre/modules/osfile/ospath.jsm", Path);
 
 // The library of promises.
 ChromeUtils.defineModuleGetter(this, "PromiseUtils",
                                "resource://gre/modules/PromiseUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "Task",
-                               "resource://gre/modules/Task.jsm");
 
 // The implementation of communications
 ChromeUtils.import("resource://gre/modules/PromiseWorker.jsm", this);
 ChromeUtils.import("resource://gre/modules/Services.jsm", this);
 ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm", this);
 var Native = ChromeUtils.import("resource://gre/modules/osfile/osfile_native.jsm", {});
 
 
@@ -308,19 +306,16 @@ var Scheduler = this.Scheduler = {
         }
 
         // Exit critical section
 
         let message = ["Meta_shutdown", [reset]];
 
         Scheduler.latestReceived = [];
         let stack = new Error().stack;
-        // Avoid loading Task.jsm if there's no task on the stack.
-        if (stack.includes("/Task.jsm:"))
-          stack = Task.Debugging.generateReadableStack(stack);
         Scheduler.latestSent = [Date.now(), stack, ...message];
 
         // Wait for result
         let resources;
         try {
           resources = await this._worker.post(...message);
 
           Scheduler.latestReceived = [Date.now(), message];
--- a/toolkit/components/thumbnails/PageThumbs.jsm
+++ b/toolkit/components/thumbnails/PageThumbs.jsm
@@ -42,17 +42,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
 
 XPCOMUtils.defineLazyServiceGetter(this, "gUpdateTimerManager",
   "@mozilla.org/updates/timer-manager;1", "nsIUpdateTimerManager");
 
 XPCOMUtils.defineLazyServiceGetter(this, "PageThumbsStorageService",
   "@mozilla.org/thumbnails/pagethumbs-service;1", "nsIPageThumbsStorageService");
 
 /**
- * Utilities for dealing with promises and Task.jsm
+ * Utilities for dealing with promises.
  */
 const TaskUtils = {
   /**
    * Read the bytes from a blob, asynchronously.
    *
    * @return {Promise}
    * @resolve {ArrayBuffer} In case of success, the bytes contained in the blob.
    * @reject {DOMException} In case of error, the underlying DOMException.
--- a/toolkit/modules/Log.jsm
+++ b/toolkit/modules/Log.jsm
@@ -2,20 +2,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["Log"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyModuleGetters(this, {
-  Services: "resource://gre/modules/Services.jsm",
-  Task: "resource://gre/modules/Task.jsm",
-});
+ChromeUtils.defineModuleGetter(this, "Services",
+                               "resource://gre/modules/Services.jsm");
 const INTERNAL_FIELDS = new Set(["_level", "_message", "_time", "_namespace"]);
 
 
 /*
  * Dump a message everywhere we can if we have a failure.
  */
 function dumpError(text) {
   dump(text + "\n");
@@ -124,19 +122,16 @@ var Log = {
         }
         frame = frame.caller;
       }
       return `Stack trace: ${output.join("\n")}`;
     }
     // Standard JS exception
     if (e.stack) {
       let stack = e.stack;
-      // Avoid loading Task.jsm if there's no task on the stack.
-      if (stack.includes("/Task.jsm:"))
-        stack = Task.Debugging.generateReadableStack(stack);
       return "JS Stack trace: " + stack.trim()
         .replace(/@[^@]*?([^\/\.]+\.\w+:)/g, "@$1");
     }
 
     return "No traceback available";
   },
 };
 
--- a/toolkit/modules/Sqlite.jsm
+++ b/toolkit/modules/Sqlite.jsm
@@ -17,17 +17,16 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/Timer.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   Services: "resource://gre/modules/Services.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   Log: "resource://gre/modules/Log.jsm",
   FileUtils: "resource://gre/modules/FileUtils.jsm",
-  Task: "resource://gre/modules/Task.jsm",
   PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "FinalizationWitnessService",
                                    "@mozilla.org/toolkit/finalizationwitness;1",
                                    "nsIFinalizationWitnessService");
 
 // Regular expression used by isInvalidBoundLikeQuery
@@ -297,24 +296,24 @@ ConnectionData.prototype = Object.freeze
    * or even an individual operation, can still be pending when the process shuts
    * down. If any of this operations is a write, this can cause data loss, simply
    * because the write has not been completed (or even started) by shutdown.
    *
    * To avoid this risk, clients are encouraged to use `executeBeforeShutdown` for
    * any write operation, as follows:
    *
    * myConnection.executeBeforeShutdown("Bookmarks: Removing a bookmark",
-   *   Task.async(function*(db) {
+   *   async function(db) {
    *     // The connection will not be closed and shutdown will not proceed
    *     // until this task has completed.
    *
    *     // `db` exposes the same API as `myConnection` but provides additional
    *     // logging support to help debug hard-to-catch shutdown timeouts.
    *
-   *     yield db.execute(...);
+   *     await db.execute(...);
    * }));
    *
    * @param {string} name A human-readable name for the ongoing operation, used
    *  for logging and debugging purposes.
    * @param {function(db)} task A function that takes as argument a Sqlite.jsm
    *  db and returns a Promise.
    */
   executeBeforeShutdown(parent, name, task) {
@@ -594,23 +593,17 @@ ConnectionData.prototype = Object.freeze
             } else {
               this._log.warn("A transaction was already in progress, likely a nested transaction", ex);
               throw ex;
             }
           }
 
           let result;
           try {
-            // Keep Task.spawn here to preserve API compat; unfortunately
-            // func was a generator rather than a task here.
-            result = func();
-            if (Object.prototype.toString.call(result) == "[object Generator]")
-              result = await Task.spawn(func); // eslint-disable-line mozilla/no-task
-            else
-              result = await result;
+            result = await func();
           } catch (ex) {
             // It's possible that the exception has been caused by trying to
             // close the connection in the middle of a transaction.
             if (this._closeRequested) {
               this._log.warn("Connection closed while performing a transaction", ex);
             } else {
               this._log.warn("Error during transaction. Rolling back", ex);
               // If we began a transaction, we must rollback it.
@@ -1401,32 +1394,31 @@ OpenedConnection.prototype = Object.free
 
   /**
    * Perform a transaction.
    *
    * *****************************************************************************
    * YOU SHOULD _NEVER_ NEST executeTransaction CALLS FOR ANY REASON, NOR
    * DIRECTLY, NOR THROUGH OTHER PROMISES.
    * FOR EXAMPLE, NEVER DO SOMETHING LIKE:
-   *   yield executeTransaction(function* () {
+   *   await executeTransaction(async function () {
    *     ...some_code...
-   *     yield executeTransaction(function* () { // WRONG!
+   *     await executeTransaction(async function () { // WRONG!
    *       ...some_code...
    *     })
-   *     yield someCodeThatExecuteTransaction(); // WRONG!
-   *     yield neverResolvedPromise; // WRONG!
+   *     await someCodeThatExecuteTransaction(); // WRONG!
+   *     await neverResolvedPromise; // WRONG!
    *   });
    * NESTING CALLS WILL BLOCK ANY FUTURE TRANSACTION UNTIL A TIMEOUT KICKS IN.
    * *****************************************************************************
    *
-   * A transaction is specified by a user-supplied function that is a
-   * generator function which can be used by Task.jsm's Task.spawn(). The
-   * function receives this connection instance as its argument.
+   * A transaction is specified by a user-supplied function that is an
+   * async function. The function receives this connection instance as its argument.
    *
-   * The supplied function is expected to yield promises. These are often
+   * The supplied function is expected to return promises. These are often
    * promises created by calling `execute` and `executeCached`. If the
    * generator is exhausted without any errors being thrown, the
    * transaction is committed. If an error occurs, the transaction is
    * rolled back.
    *
    * The returned value from this function is a promise that will be resolved
    * once the transaction has been committed or rolled back. The promise will
    * be resolved to whatever value the supplied function resolves to. If
--- a/toolkit/modules/docs/AsyncShutdown.rst
+++ b/toolkit/modules/docs/AsyncShutdown.rst
@@ -70,31 +70,30 @@ The following snippet presents an exampl
 wishes to ensure that all clients have had a chance to complete any
 outstanding operations before FooService shuts down.
 
 .. code-block:: javascript
 
     // Module FooService
 
     Components.utils.import("resource://gre/modules/AsyncShutdown.jsm", this);
-    Components.utils.import("resource://gre/modules/Task.jsm", this);
 
     this.exports = ["FooService"];
 
     let shutdown = new AsyncShutdown.Barrier("FooService: Waiting for clients before shutting down");
 
     // Export the `client` capability, to let clients register shutdown blockers
     FooService.shutdown = shutdown.client;
 
-    // This Task should be triggered at some point during shutdown, generally
-    // as a client to another Barrier or Phase. Triggering this Task is not covered
+    // This function should be triggered at some point during shutdown, generally
+    // as a client to another Barrier or Phase. Triggering this function is not covered
     // in this snippet.
-    let onshutdown = Task.async(function*() {
+    let onshutdown = async function() {
       // Wait for all registered clients to have lifted the barrier
-      yield shutdown.wait();
+      await shutdown.wait();
 
       // Now deactivate FooService itself.
       // ...
     });
 
 Frequently, a service that owns a ``AsyncShutdown.Barrier`` is itself a client of another Barrier.
 
 .. _AsyncShutdown.Barrier.state:
@@ -116,50 +115,49 @@ The following snippet presents FooClient
       () => Blocker.state
     );
 
     let Blocker = {
       // This field contains information on the status of the blocker.
       // It can be any JSON serializable object.
       state: "Not started",
 
-      wait: Task.async(function*() {
+      async wait() {
         // This method is called once FooService starts informing its clients that
         // FooService wishes to shut down.
 
         // Update the state as we go. If the Barrier is used in conjunction with
         // a Phase, this state will be reported as part of a crash report if FooClient fails
         // to shutdown properly.
         this.state = "Starting";
 
-        let data = yield collectSomeData();
+        let data = await collectSomeData();
         this.state = "Data collection complete";
 
         try {
-          yield writeSomeDataToDisk(data);
+          await writeSomeDataToDisk(data);
           this.state = "Data successfully written to disk";
         } catch (ex) {
           this.state = "Writing data to disk failed, proceeding with shutdown: " + ex;
         }
 
-        yield FooService.oneLastCall();
+        await FooService.oneLastCall();
         this.state = "Ready";
-      }.bind(this)
+      }
     };
 
 
 Example 4: A service with both internal and external dependencies
 -----------------------------------------------------------------
 
  .. code-block:: javascript
 
     // Module FooService2
 
     Components.utils.import("resource://gre/modules/AsyncShutdown.jsm", this);
-    Components.utils.import("resource://gre/modules/Task.jsm", this);
     Components.utils.import("resource://gre/modules/Promise.jsm", this);
 
     this.exports = ["FooService2"];
 
     let shutdown = new AsyncShutdown.Barrier("FooService2: Waiting for clients before shutting down");
 
     // Export the `client` capability, to let clients register shutdown blockers
     FooService2.shutdown = shutdown.client;
@@ -194,29 +192,29 @@ Example 4: A service with both internal 
 
           // The barrier MUST be lifted, even if removeBlocker has been called.
           deferred.resolve();
         }
       };
     };
 
 
-    // This Task should be triggered at some point during shutdown, generally
-    // as a client to another Barrier. Triggering this Task is not covered
+    // This function should be triggered at some point during shutdown, generally
+    // as a client to another Barrier. Triggering this function is not covered
     // in this snippet.
-    let onshutdown = Task.async(function*() {
+    let onshutdown = async function() {
       // Wait for all registered clients to have lifted the barrier.
       // These clients may open instances of FooConnection if they need to.
-      yield shutdown.wait();
+      await shutdown.wait();
 
       // Now stop accepting any other connection request.
       isClosed = true;
 
       // Wait for all instances of FooConnection to be closed.
-      yield connections.wait();
+      await connections.wait();
 
       // Now finish shutting down FooService2
       // ...
     });
 
 .. _AsyncShutdown_phases:
 
 Phases: Expressing dependencies towards phases of shutdown
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -152,16 +152,17 @@ with Files('WindowsRegistry.jsm'):
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
 
 TESTING_JS_MODULES += [
     'HiddenFrame.jsm',
     'tests/modules/MockDocument.jsm',
     'tests/modules/PromiseTestUtils.jsm',
+    'tests/modules/Task.jsm',
     'tests/xpcshell/TestIntegration.jsm',
 ]
 
 SPHINX_TREES['toolkit_modules'] = 'docs'
 
 with Files('docs/**'):
     SCHEDULES.exclusive = ['docs']
 
@@ -238,17 +239,16 @@ EXTRA_JS_MODULES += [
     'ResetProfile.jsm',
     'ResponsivenessMonitor.jsm',
     'SelectParentHelper.jsm',
     'ServiceRequest.jsm',
     'Services.jsm',
     'sessionstore/FormData.jsm',
     'ShortcutUtils.jsm',
     'Sqlite.jsm',
-    'Task.jsm',
     'Timer.jsm',
     'Troubleshoot.jsm',
     'UpdateUtils.jsm',
     'WebChannel.jsm',
     'WebProgressChild.jsm',
     'WindowDraggingUtils.jsm',
     'ZipUtils.jsm',
 ]
rename from toolkit/modules/Task.jsm
rename to toolkit/modules/tests/modules/Task.jsm
--- a/toolkit/modules/tests/xpcshell/test_Promise.js
+++ b/toolkit/modules/tests/xpcshell/test_Promise.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/Promise.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/Task.jsm");
+ChromeUtils.import("resource://testing-common/Task.jsm");
 ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
 
 // Prevent test failures due to the unhandled rejections in this test file.
 PromiseTestUtils.disableUncaughtRejectionObserverForSelfTest();
 
 // Test runner
 
 var run_promise_tests = function run_promise_tests(tests, cb) {
--- a/toolkit/modules/tests/xpcshell/test_task.js
+++ b/toolkit/modules/tests/xpcshell/test_task.js
@@ -8,17 +8,17 @@
 ////////////////////////////////////////////////////////////////////////////////
 /// Globals
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "Services",
                                "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "Task",
-                               "resource://gre/modules/Task.jsm");
+                               "resource://testing-common/Task.jsm");
 
 /**
  * Returns a promise that will be resolved with the given value, when an event
  * posted on the event loop of the main thread is processed.
  */
 function promiseResolvedLater(aValue) {
   return new Promise(resolve => {
     Services.tm.dispatchToMainThread(() => resolve(aValue));
@@ -576,9 +576,8 @@ add_test(function test_without_maintainS
     run_next_test();
   });
 });
 
 add_test(function exit_stack_tests() {
   Task.Debugging.maintainStack = maintainStack;
   run_next_test();
 });
-
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -1521,18 +1521,17 @@ var AddonTestUtils = {
 
   /**
    * Monitors console output for the duration of a task, and returns a promise
    * which resolves to a tuple containing a list of all console messages
    * generated during the task's execution, and the result of the task itself.
    *
    * @param {function} task
    *        The task to run while monitoring console output. May be
-   *        either a generator function, per Task.jsm, or an ordinary
-   *        function which returns promose.
+   *        an async function, or an ordinary function which returns a promose.
    * @return {Promise<[Array<nsIConsoleMessage>, *]>}
    *        Resolves to an object containing a `messages` property, with
    *        the array of console messages emitted during the execution
    *        of the task, and a `result` property, containing the task's
    *        return value.
    */
   async promiseConsoleOutput(task) {
     const DONE = "=== xpcshell test console listener done ===";
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -8,26 +8,16 @@
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/UpdateTelemetry.jsm");
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser", "XMLHttpRequest"]);
 
-XPCOMUtils.defineLazyModuleGetters(this, {
-  AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
-  CertUtils: "resource://gre/modules/CertUtils.jsm",
-  ctypes: "resource://gre/modules/ctypes.jsm",
-  DeferredTask: "resource://gre/modules/DeferredTask.jsm",
-  OS: "resource://gre/modules/osfile.jsm",
-  UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
-  WindowsRegistry: "resource://gre/modules/WindowsRegistry.jsm",
-});
-
 const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}");
 
 const PREF_APP_UPDATE_ALTWINDOWTYPE        = "app.update.altwindowtype";
 const PREF_APP_UPDATE_BACKGROUNDERRORS     = "app.update.backgroundErrors";
 const PREF_APP_UPDATE_BACKGROUNDMAXERRORS  = "app.update.backgroundMaxErrors";
 const PREF_APP_UPDATE_CANCELATIONS         = "app.update.cancelations";
 const PREF_APP_UPDATE_CANCELATIONS_OSX     = "app.update.cancelations.osx";
 const PREF_APP_UPDATE_CANCELATIONS_OSX_MAX = "app.update.cancelations.osx.max";
@@ -196,16 +186,26 @@ const APPID_TO_TOPIC = {
 
 // A var is used for the delay so tests can set a smaller value.
 var gSaveUpdateXMLDelay = 2000;
 var gUpdateMutexHandle = null;
 // The permissions of the update directory should be fixed no more than once per
 // session
 var gUpdateDirPermissionFixAttempted = false;
 
+XPCOMUtils.defineLazyModuleGetters(this, {
+  AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
+  CertUtils: "resource://gre/modules/CertUtils.jsm",
+  ctypes: "resource://gre/modules/ctypes.jsm",
+  DeferredTask: "resource://gre/modules/DeferredTask.jsm",
+  OS: "resource://gre/modules/osfile.jsm",
+  UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
+  WindowsRegistry: "resource://gre/modules/WindowsRegistry.jsm",
+});
+
 XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function aus_gLogEnabled() {
   return Services.prefs.getBoolPref(PREF_APP_UPDATE_LOG, false);
 });
 
 XPCOMUtils.defineLazyGetter(this, "gUpdateBundle", function aus_gUpdateBundle() {
   return Services.strings.createBundle(URI_UPDATES_PROPERTIES);
 });
 
@@ -1181,297 +1181,286 @@ function handleCriticalWriteResult(wrote
  * Update Patch
  * @param   patch
  *          A <patch> element to initialize this object with
  * @throws if patch has a size of 0
  * @constructor
  */
 function UpdatePatch(patch) {
   this._properties = {};
-  this.errorCode = 0;
-  this.state = STATE_NONE;
-
-  for (let i = 0; i < patch.attributes.length; ++i) {
+  for (var i = 0; i < patch.attributes.length; ++i) {
     var attr = patch.attributes.item(i);
-    // If an undefined value is saved to the xml file it will be a string when
-    // it is read from the xml file.
-    if (attr.value == "undefined") {
-      continue;
-    }
     switch (attr.name) {
       case "xmlns":
         // Don't save the XML namespace.
         break;
       case "selected":
         this.selected = attr.value == "true";
         break;
       case "size":
         if (0 == parseInt(attr.value)) {
           LOG("UpdatePatch:init - 0-sized patch!");
           throw Cr.NS_ERROR_ILLEGAL_VALUE;
         }
-        this[attr.name] = attr.value;
-        break;
-      case "errorCode":
-        if (attr.value) {
-          let val = parseInt(attr.value);
-          // This will evaluate to false if the value is 0 but that's ok since
-          // this.errorCode is set to the default of 0 above.
-          if (val) {
-            this.errorCode = val;
-          }
-        }
-        break;
+        // fall through
+      case "type":
+      case "URL":
       case "finalURL":
       case "state":
-      case "type":
-      case "URL":
+      case "errorCode":
         this[attr.name] = attr.value;
         break;
       default:
-        // Set nsIPropertyBag properties that were read from the xml file.
+        this[attr.name] = attr.value;
+        // Save custom attributes when serializing to the local xml file but
+        // don't use this method for the expected attributes which are already
+        // handled in serialize.
         this.setProperty(attr.name, attr.value);
         break;
     }
   }
 }
 UpdatePatch.prototype = {
   /**
    * See nsIUpdateService.idl
    */
   serialize: function UpdatePatch_serialize(updates) {
     var patch = updates.createElementNS(URI_UPDATE_NS, "patch");
-    patch.setAttribute("size", this.size);
-    patch.setAttribute("type", this.type);
-    patch.setAttribute("URL", this.URL);
     // Don't write an errorCode if it evaluates to false since 0 is the same as
     // no error code.
     if (this.errorCode) {
       patch.setAttribute("errorCode", this.errorCode);
     }
     // finalURL is not available until after the download has started
     if (this.finalURL) {
       patch.setAttribute("finalURL", this.finalURL);
     }
-    // The selected patch is the only patch that should have this attribute.
     if (this.selected) {
       patch.setAttribute("selected", this.selected);
     }
-    if (this.state != STATE_NONE) {
-      patch.setAttribute("state", this.state);
-    }
-
-    for (let [name, value] of Object.entries(this._properties)) {
-      if (value.present) {
-        patch.setAttribute(name, value.data);
+    patch.setAttribute("size", this.size);
+    patch.setAttribute("state", this.state);
+    patch.setAttribute("type", this.type);
+    patch.setAttribute("URL", this.URL);
+
+    for (let p in this._properties) {
+      if (this._properties[p].present) {
+        patch.setAttribute(p, this._properties[p].data);
       }
     }
+
     return patch;
   },
 
   /**
+   * A hash of custom properties
+   */
+  _properties: null,
+
+  /**
    * See nsIWritablePropertyBag.idl
    */
   setProperty: function UpdatePatch_setProperty(name, value) {
     this._properties[name] = { data: value, present: true };
   },
 
   /**
    * See nsIWritablePropertyBag.idl
    */
   deleteProperty: function UpdatePatch_deleteProperty(name) {
-    if (name in this._properties) {
+    if (name in this._properties)
       this._properties[name].present = false;
-    } else {
+    else
       throw Cr.NS_ERROR_FAILURE;
-    }
   },
 
   /**
    * See nsIPropertyBag.idl
    *
    * Note: this only contains the nsIPropertyBag name / value pairs and not the
    *       nsIUpdatePatch name / value pairs.
    */
   get enumerator() {
     return this.enumerate();
   },
 
   * enumerate() {
-    // An nsISupportsInterfacePointer is used so creating an array using
-    // Array.from will retain the QueryInterface for nsIProperty.
-    let ip = Cc["@mozilla.org/supports-interface-pointer;1"].
-             createInstance(Ci.nsISupportsInterfacePointer);
-    let qi = ChromeUtils.generateQI([Ci.nsIProperty]);
-    for (let [name, value] of Object.entries(this._properties)) {
-      if (value.present) {
+    for (let propName in this._properties) {
+      if (this._properties[propName].present) {
         // The nsIPropertyBag enumerator returns a nsISimpleEnumerator whose
-        // elements are nsIProperty objects. Calling QueryInterface for
-        // nsIProperty on the object doesn't return to the caller an object that
-        // is already queried to nsIProperty but do it just in case it is fixed
-        // at some point.
-        ip.data = {name, value: value.data, QueryInterface: qi};
-        yield ip.data.QueryInterface(Ci.nsIProperty);
+        // elements are nsIProperty objects.
+        yield { name: propName,
+                value: this._properties[propName].data,
+                QueryInterface: ChromeUtils.generateQI([Ci.nsIProperty])};
       }
     }
   },
 
   /**
    * See nsIPropertyBag.idl
-   *
    * Note: returns null instead of throwing when the property doesn't exist to
    *       simplify code and to silence warnings in debug builds.
    */
   getProperty: function UpdatePatch_getProperty(name) {
-    if (name in this._properties && this._properties[name].present) {
+    if (name in this._properties &&
+        this._properties[name].present) {
       return this._properties[name].data;
     }
     return null;
   },
 
+  /**
+   * See nsIUpdateService.idl
+   */
+  get errorCode() {
+    return this._properties.errorCode || 0;
+  },
+  set errorCode(val) {
+    this._properties.errorCode = val;
+  },
+
+  /**
+   * See nsIUpdateService.idl
+   */
+  get state() {
+    return this._properties.state || STATE_NONE;
+  },
+  set state(val) {
+    this._properties.state = val;
+  },
+
   QueryInterface: ChromeUtils.generateQI([Ci.nsIUpdatePatch,
                                           Ci.nsIPropertyBag,
                                           Ci.nsIWritablePropertyBag]),
 };
 
 /**
  * Update
  * Implements nsIUpdate
  * @param   update
  *          An <update> element to initialize this object with
  * @throws if the update contains no patches
  * @constructor
  */
 function Update(update) {
+  this._properties = {};
   this._patches = [];
-  this._properties = {};
   this.isCompleteUpdate = false;
+  this.unsupported = false;
   this.channel = "default";
   this.promptWaitTime = Services.prefs.getIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 43200);
-  this.unsupported = false;
 
   // Null <update>, assume this is a message container and do no
   // further initialization
   if (!update) {
     return;
   }
 
+  let patch;
   for (let i = 0; i < update.childNodes.length; ++i) {
     let patchElement = update.childNodes.item(i);
     if (patchElement.nodeType != patchElement.ELEMENT_NODE ||
         patchElement.localName != "patch") {
       continue;
     }
 
-    let patch;
     try {
       patch = new UpdatePatch(patchElement);
     } catch (e) {
       continue;
     }
     this._patches.push(patch);
   }
 
   if (this._patches.length == 0 && !update.hasAttribute("unsupported")) {
     throw Cr.NS_ERROR_ILLEGAL_VALUE;
   }
 
   // Set the installDate value with the current time. If the update has an
   // installDate attribute this will be replaced with that value if it doesn't
   // equal 0.
   this.installDate = (new Date()).getTime();
-  this.patchCount = update.childNodes.length;
 
   for (let i = 0; i < update.attributes.length; ++i) {
-    let attr = update.attributes.item(i);
+    var attr = update.attributes.item(i);
     if (attr.name == "xmlns" || attr.value == "undefined") {
       // Don't save the XML namespace or undefined values.
-      // If an undefined value is saved to the xml file it will be a string when
-      // it is read from the xml file.
       continue;
     } else if (attr.name == "detailsURL") {
-      this.detailsURL = attr.value;
+      this._detailsURL = attr.value;
     } else if (attr.name == "installDate" && attr.value) {
       let val = parseInt(attr.value);
       if (val) {
         this.installDate = val;
       }
     } else if (attr.name == "errorCode" && attr.value) {
       let val = parseInt(attr.value);
       if (val) {
-        // Set the value of |_errorCode| instead of |errorCode| since
-        // selectedPatch won't be available at this point and normally the
-        // nsIUpdatePatch will provide the errorCode.
-        this._errorCode = val;
+        this.errorCode = val;
       }
     } else if (attr.name == "isCompleteUpdate") {
       this.isCompleteUpdate = attr.value == "true";
     } else if (attr.name == "promptWaitTime") {
       if (!isNaN(attr.value)) {
         this.promptWaitTime = parseInt(attr.value);
       }
     } else if (attr.name == "unsupported") {
       this.unsupported = attr.value == "true";
     } else {
+      this[attr.name] = attr.value;
+
       switch (attr.name) {
         case "appVersion":
         case "buildID":
         case "channel":
         case "displayVersion":
-        case "elevationFailure":
         case "name":
         case "previousAppVersion":
         case "serviceURL":
         case "statusText":
         case "type":
-          this[attr.name] = attr.value;
           break;
         default:
-          // Set nsIPropertyBag properties that were read from the xml file.
+          // Save custom attributes when serializing to the local xml file but
+          // don't use this method for the expected attributes which are already
+          // handled in serialize.
           this.setProperty(attr.name, attr.value);
           break;
       }
     }
   }
 
-  if (!this.previousAppVersion) {
-    this.previousAppVersion = Services.appinfo.version;
-  }
-
-  if (!this.elevationFailure) {
-    this.elevationFailure = false;
-  }
-
-  if (!this.detailsURL) {
-    try {
-      // Try using a default details URL supplied by the distribution
-      // if the update XML does not supply one.
-      this.detailsURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS);
-    } catch (e) {
-      this.detailsURL = "";
-    }
-  }
-
   if (!this.displayVersion) {
     this.displayVersion = this.appVersion;
   }
 
-  if (!this.name) {
-    // When the update doesn't provide a name fallback to using
-    // "<App Name> <Update App Version>"
-    let brandBundle = Services.strings.createBundle(URI_BRAND_PROPERTIES);
-    let appName = brandBundle.GetStringFromName("brandShortName");
-    this.name = gUpdateBundle.formatStringFromName("updateName",
-                                                   [appName, this.displayVersion], 2);
+  // The Update Name is either the string provided by the <update> element, or
+  // the string: "<App Name> <Update App Version>"
+  var name = "";
+  if (update.hasAttribute("name")) {
+    name = update.getAttribute("name");
+  } else {
+    var brandBundle = Services.strings.createBundle(URI_BRAND_PROPERTIES);
+    var appName = brandBundle.GetStringFromName("brandShortName");
+    name = gUpdateBundle.formatStringFromName("updateName",
+                                              [appName, this.displayVersion], 2);
   }
+  this.name = name;
 }
 Update.prototype = {
   /**
    * See nsIUpdateService.idl
    */
+  get patchCount() {
+    return this._patches.length;
+  },
+
+  /**
+   * See nsIUpdateService.idl
+   */
   getPatchAt: function Update_getPatchAt(index) {
     return this._patches[index];
   },
 
   /**
    * See nsIUpdateService.idl
    *
    * We use a copy of the state cached on this object in |_state| only when
@@ -1510,114 +1499,126 @@ Update.prototype = {
       this.selectedPatch.errorCode = errorCode;
     this._errorCode = errorCode;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   get selectedPatch() {
-    for (let i = 0; i < this.patchCount; ++i) {
-      if (this._patches[i].selected) {
+    for (var i = 0; i < this.patchCount; ++i) {
+      if (this._patches[i].selected)
         return this._patches[i];
+    }
+    return null;
+  },
+
+  /**
+   * See nsIUpdateService.idl
+   */
+  get detailsURL() {
+    if (!this._detailsURL) {
+      try {
+        // Try using a default details URL supplied by the distribution
+        // if the update XML does not supply one.
+        return Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS);
+      } catch (e) {
       }
     }
-    return null;
+    return this._detailsURL || "";
   },
 
   /**
    * See nsIUpdateService.idl
    */
   serialize: function Update_serialize(updates) {
     // If appVersion isn't defined just return null. This happens when cleaning
     // up invalid updates (e.g. incorrect channel).
     if (!this.appVersion) {
       return null;
     }
-    let update = updates.createElementNS(URI_UPDATE_NS, "update");
+    var update = updates.createElementNS(URI_UPDATE_NS, "update");
     update.setAttribute("appVersion", this.appVersion);
     update.setAttribute("buildID", this.buildID);
     update.setAttribute("channel", this.channel);
-    update.setAttribute("detailsURL", this.detailsURL);
     update.setAttribute("displayVersion", this.displayVersion);
     update.setAttribute("installDate", this.installDate);
     update.setAttribute("isCompleteUpdate", this.isCompleteUpdate);
     update.setAttribute("name", this.name);
-    update.setAttribute("previousAppVersion", this.previousAppVersion);
     update.setAttribute("promptWaitTime", this.promptWaitTime);
     update.setAttribute("serviceURL", this.serviceURL);
     update.setAttribute("type", this.type);
 
+    if (this.detailsURL) {
+      update.setAttribute("detailsURL", this.detailsURL);
+    }
+    if (this.previousAppVersion) {
+      update.setAttribute("previousAppVersion", this.previousAppVersion);
+    }
     if (this.statusText) {
       update.setAttribute("statusText", this.statusText);
     }
     if (this.unsupported) {
       update.setAttribute("unsupported", this.unsupported);
     }
-    if (this.elevationFailure) {
-      update.setAttribute("elevationFailure", this.elevationFailure);
-    }
-
-    for (let [name, value] of Object.entries(this._properties)) {
-      if (value.present) {
-        update.setAttribute(name, value.data);
+    updates.documentElement.appendChild(update);
+
+    for (let p in this._properties) {
+      if (this._properties[p].present) {
+        update.setAttribute(p, this._properties[p].data);
       }
     }
 
     for (let i = 0; i < this.patchCount; ++i) {
       update.appendChild(this.getPatchAt(i).serialize(updates));
     }
 
-    updates.documentElement.appendChild(update);
     return update;
   },
 
   /**
+   * A hash of custom properties
+   */
+  _properties: null,
+
+  /**
    * See nsIWritablePropertyBag.idl
    */
   setProperty: function Update_setProperty(name, value) {
     this._properties[name] = { data: value, present: true };
   },
 
   /**
    * See nsIWritablePropertyBag.idl
    */
   deleteProperty: function Update_deleteProperty(name) {
-    if (name in this._properties) {
+    if (name in this._properties)
       this._properties[name].present = false;
-    } else {
+    else
       throw Cr.NS_ERROR_FAILURE;
-    }
   },
 
   /**
    * See nsIPropertyBag.idl
    *
    * Note: this only contains the nsIPropertyBag name value / pairs and not the
    *       nsIUpdate name / value pairs.
    */
   get enumerator() {
     return this.enumerate();
   },
 
   * enumerate() {
-    // An nsISupportsInterfacePointer is used so creating an array using
-    // Array.from will retain the QueryInterface for nsIProperty.
-    let ip = Cc["@mozilla.org/supports-interface-pointer;1"].
-             createInstance(Ci.nsISupportsInterfacePointer);
-    let qi = ChromeUtils.generateQI([Ci.nsIProperty]);
-    for (let [name, value] of Object.entries(this._properties)) {
-      if (value.present) {
+    for (let propName in this._properties) {
+      if (this._properties[propName].present) {
         // The nsIPropertyBag enumerator returns a nsISimpleEnumerator whose
-        // elements are nsIProperty objects. Calling QueryInterface for
-        // nsIProperty on the object doesn't return to the caller an object that
-        // is already queried to nsIProperty but do it just in case it is fixed
-        // at some point.
-        ip.data = {name, value: value.data, QueryInterface: qi};
-        yield ip.data.QueryInterface(Ci.nsIProperty);
+        // elements are nsIProperty objects.
+        yield { name: propName,
+                value: this._properties[propName].data,
+                QueryInterface: ChromeUtils.generateQI([Ci.nsIProperty])};
       }
     }
   },
 
   /**
    * See nsIPropertyBag.idl
    * Note: returns null instead of throwing when the property doesn't exist to
    *       simplify code and to silence warnings in debug builds.
@@ -1632,19 +1633,18 @@ Update.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIUpdate,
                                           Ci.nsIPropertyBag,
                                           Ci.nsIWritablePropertyBag]),
 };
 
 const UpdateServiceFactory = {
   _instance: null,
   createInstance(outer, iid) {
-    if (outer != null) {
+    if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
     return this._instance == null ? this._instance = new UpdateService() :
                                     this._instance;
   },
 };
 
 /**
  * UpdateService
  * A Service for managing the discovery and installation of software updates.
@@ -2577,16 +2577,18 @@ UpdateService.prototype = {
       if (update.isCompleteUpdate == this._downloader.isCompleteUpdate &&
           background == this._downloader.background) {
         LOG("UpdateService:downloadUpdate - no support for downloading more " +
             "than one update at a time");
         return readStatusFile(getUpdatesDir());
       }
       this._downloader.cancel();
     }
+    // Set the previous application version prior to downloading the update.
+    update.previousAppVersion = Services.appinfo.version;
     this._downloader = new Downloader(background, this);
     return this._downloader.downloadUpdate(update);
   },
 
   /**
    * See nsIUpdateService.idl
    */
   pauseDownload: function AUS_pauseDownload() {
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -103,37 +103,40 @@ function run_test() {
                "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
   // Custom attributes
   Assert.equal(update.getProperty("custom1_attr"), "custom1 value",
                "the update custom1_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(update.getProperty("custom2_attr"), "custom2 value",
                "the update custom2_attr property" + MSG_SHOULD_EQUAL);
   // nsIPropertyBag enumerator
   debugDump("checking the first update enumerator");
-  Assert.ok(update.enumerator instanceof Ci.nsISimpleEnumerator,
-            "update enumerator should be an instance of nsISimpleEnumerator");
-  let results = Array.from(update.enumerator);
-  Assert.equal(results.length, 3,
-               "the length of the array created from the update enumerator" +
-               MSG_SHOULD_EQUAL);
-  Assert.ok(results.every(prop => prop instanceof Ci.nsIProperty),
-            "the objects in the array created from the update enumerator " +
-            "should all be an instance of nsIProperty");
-  Assert.equal(results[0].name, "custom1_attr",
+  let e = update.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  let prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom1_attr",
                "the first property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[0].value, "custom1 value",
+  Assert.equal(prop.value, "custom1 value",
                "the first property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].name, "custom2_attr",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom2_attr",
                "the second property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].value, "custom2 value",
+  Assert.equal(prop.value, "custom2 value",
                "the second property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[2].name, "foregroundDownload",
-               "the second property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[2].value, "true",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.equal(prop.name, "foregroundDownload",
+               "the third property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "true",
                "the third property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
   debugDump("checking the first update patch properties");
   let patch = update.selectedPatch.QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(patch.type, "partial",
                "the update patch type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.URL, "http://partial/",
                "the update patch URL attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.size, "86",
@@ -143,33 +146,35 @@ function run_test() {
   Assert.equal(patch.state, STATE_SUCCEEDED,
                "the update patch state attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.getProperty("custom1_attr"), "custom1 patch value",
                "the update patch custom1_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.getProperty("custom2_attr"), "custom2 patch value",
                "the update patch custom2_attr property" + MSG_SHOULD_EQUAL);
   // nsIPropertyBag enumerator
   debugDump("checking the first update patch enumerator");
-  Assert.ok(patch.enumerator instanceof Ci.nsISimpleEnumerator,
-            "patch enumerator should be an instance of nsISimpleEnumerator");
-  results = Array.from(patch.enumerator);
-  Assert.equal(results.length, 2,
-               "the length of the array created from the patch enumerator" +
-               MSG_SHOULD_EQUAL);
-  Assert.ok(results.every(prop => prop instanceof Ci.nsIProperty),
-            "the objects in the array created from the patch enumerator " +
-            "should all be an instance of nsIProperty");
-  Assert.equal(results[0].name, "custom1_attr",
+  e = patch.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom1_attr",
                "the first property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[0].value, "custom1 patch value",
+  Assert.equal(prop.value, "custom1 patch value",
                "the first property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].name, "custom2_attr",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom2_attr",
                "the second property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].value, "custom2 patch value",
+  Assert.equal(prop.value, "custom2 patch value",
                "the second property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
   debugDump("checking the second update properties");
   update = gUpdateManager.getUpdateAt(1).QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(update.state, STATE_FAILED,
                "the update state attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.name, "Existing",
                "the update name attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.type, "minor",
@@ -189,46 +194,49 @@ function run_test() {
   Assert.equal(update.buildID, "20080811053724",
                "the update buildID attribute" + MSG_SHOULD_EQUAL);
   Assert.ok(!!update.isCompleteUpdate,
             "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.channel, "test_channel",
                "the update channel attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.promptWaitTime, "691200",
                "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
-  Assert.equal(update.previousAppVersion, "1.0",
+  Assert.equal(update.previousAppVersion, null,
                "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
   // Custom attributes
   Assert.equal(update.getProperty("custom3_attr"), "custom3 value",
                "the update custom3_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(update.getProperty("custom4_attr"), "custom4 value",
                "the update custom4_attr property" + MSG_SHOULD_EQUAL);
   // nsIPropertyBag enumerator
   debugDump("checking the second update enumerator");
-  Assert.ok(update.enumerator instanceof Ci.nsISimpleEnumerator,
-            "update enumerator should be an instance of nsISimpleEnumerator");
-  results = Array.from(update.enumerator);
-  Assert.equal(results.length, 3,
-               "the length of the array created from the update enumerator" +
-               MSG_SHOULD_EQUAL);
-  Assert.ok(results.every(prop => prop instanceof Ci.nsIProperty),
-            "the objects in the array created from the update enumerator " +
-            "should all be an instance of nsIProperty");
-  Assert.equal(results[0].name, "custom3_attr",
+  e = update.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom3_attr",
                "the first property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[0].value, "custom3 value",
+  Assert.equal(prop.value, "custom3 value",
                "the first property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].name, "custom4_attr",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom4_attr",
                "the second property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].value, "custom4 value",
+  Assert.equal(prop.value, "custom4 value",
                "the second property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[2].name, "foregroundDownload",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.equal(prop.name, "foregroundDownload",
                "the third property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[2].value, "false",
+  Assert.equal(prop.value, "false",
                "the third property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
   debugDump("checking the second update patch properties");
   patch = update.selectedPatch.QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(patch.type, "complete",
                "the update patch type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.URL, "http://complete/",
                "the update patch URL attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.size, "75",
@@ -238,33 +246,35 @@ function run_test() {
   Assert.equal(patch.state, STATE_FAILED,
                "the update patch state attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.getProperty("custom3_attr"), "custom3 patch value",
                "the update patch custom3_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.getProperty("custom4_attr"), "custom4 patch value",
                "the update patch custom4_attr property" + MSG_SHOULD_EQUAL);
   // nsIPropertyBag enumerator
   debugDump("checking the second update patch enumerator");
-  Assert.ok(patch.enumerator instanceof Ci.nsISimpleEnumerator,
-            "patch enumerator should be an instance of nsISimpleEnumerator");
-  results = Array.from(patch.enumerator);
-  Assert.equal(results.length, 2,
-               "the length of the array created from the patch enumerator" +
-               MSG_SHOULD_EQUAL);
-  Assert.ok(results.every(prop => prop instanceof Ci.nsIProperty),
-            "the objects in the array created from the patch enumerator " +
-            "should all be an instance of nsIProperty");
-  Assert.equal(results[0].name, "custom3_attr",
+  e = patch.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom3_attr",
                "the first property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[0].value, "custom3 patch value",
+  Assert.equal(prop.value, "custom3 patch value",
                "the first property value" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].name, "custom4_attr",
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom4_attr",
                "the second property name" + MSG_SHOULD_EQUAL);
-  Assert.equal(results[1].value, "custom4 patch value",
+  Assert.equal(prop.value, "custom4 patch value",
                "the second property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
   // Cleaning up the active update along with reloading the update manager
   // in doTestFinish will prevent writing the update xml files during
   // shutdown.
   gUpdateManager.cleanupActiveUpdate();
   executeSoon(waitForUpdateXMLFiles);
 }