Merge mozilla-inbound to mozilla-central a=merge
authorRazvan Maries <rmaries@mozilla.com>
Wed, 09 Jan 2019 05:49:28 +0200
changeset 510096 3b629ad2475fde10207b2d2c5b119e4eb0ca91ef
parent 510074 a36388b88fcc72e534ba79d282ca1741744602d9 (current diff)
parent 510095 f0bf0b42b3cf98615a6a911282761b2ffa9122cb (diff)
child 510103 034b10e2add1e34a0d0af5c6b3b5a6ebbc7ce44b
child 510111 432b8b97bb6f2039ce832ac7b2a63901b38fa489
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)
reviewersmerge
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-inbound to mozilla-central a=merge
--- a/devtools/client/debugger/new/src/actions/sources/newSources.js
+++ b/devtools/client/debugger/new/src/actions/sources/newSources.js
@@ -83,17 +83,26 @@ function loadSourceMap(sourceId: SourceI
     const source = getSource(getState(), sourceId);
 
     if (!source || isOriginal(source) || !source.sourceMapURL) {
       return [];
     }
 
     let urls = null;
     try {
-      urls = await sourceMaps.getOriginalURLs(source);
+      const urlInfo = { ...source };
+      if (!urlInfo.url) {
+        // If the source was dynamically generated (via eval, dynamically
+        // created script elements, and so forth), it won't have a URL, so that
+        // it is not collapsed into other sources from the same place. The
+        // introduction URL will include the point it was constructed at,
+        // however, so use that for resolving any source maps in the source.
+        urlInfo.url = urlInfo.introductionUrl;
+      }
+      urls = await sourceMaps.getOriginalURLs(urlInfo);
     } catch (e) {
       console.error(e);
     }
 
     if (!urls) {
       // The source might have changed while we looked up the URLs, so we need
       // to load it again before dispatching. We ran into an issue here because
       // this was previously using 'source' and was at risk of resetting the
--- a/devtools/client/debugger/new/src/client/firefox/create.js
+++ b/devtools/client/debugger/new/src/client/firefox/create.js
@@ -50,16 +50,17 @@ export function createSource(
   const createdSource = {
     id: source.actor,
     thread,
     url: source.url,
     relativeUrl: source.url,
     isPrettyPrinted: false,
     isWasm: false,
     sourceMapURL: source.sourceMapURL,
+    introductionUrl: source.introductionUrl,
     isBlackBoxed: false,
     loadedState: "unloaded"
   };
   clientCommands.registerSource(createdSource);
   return Object.assign(createdSource, {
     isWasm: supportsWasm && source.introductionType === "wasm"
   });
 }
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -597,16 +597,17 @@ support-files =
   examples/sum/sum.min.js
   examples/sum/sum.min.js.map
   examples/big-sourcemap_files/bundle.js
   examples/big-sourcemap_files/bundle.js.map
   examples/reload/code_reload_1.js
   examples/reload/code_reload_2.js
   examples/reload/doc-reload.html
   examples/reload/sjs_code_reload.sjs
+  examples/doc-react-jsx.html
   examples/doc-async.html
   examples/doc-asm.html
   examples/doc-duplicate-functions.html
   examples/doc-sourcemapped.html
   examples/doc-content-script-sources.html
   examples/doc-scripts.html
   examples/doc-scripts-debugger.html
   examples/doc-script-mutate.html
@@ -724,16 +725,17 @@ skip-if = (verify && debug && (os == 'ma
 [browser_dbg-pretty-print-console.js]
 [browser_dbg-pretty-print-paused.js]
 [browser_dbg-preview.js]
 skip-if = os == "win"
 [browser_dbg-preview-module.js]
 skip-if = os == "win"
 [browser_dbg-preview-source-maps.js]
 skip-if = os == "win"
+[browser_dbg-react-jsx.js]
 [browser_dbg-returnvalues.js]
 [browser_dbg-reload.js]
 [browser_dbg-reloading.js]
 skip-if = true
 [browser_dbg-pause-points.js]
 [browser_dbg-scopes-mutations.js]
 [browser_dbg-search-file.js]
 skip-if = os == "win" # Bug 1393121
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-react-jsx.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that dynamically generated <script> elements which contain source maps
+// will be shown in the debugger.
+add_task(async function() {
+  const dbg = await initDebugger("doc-react-jsx.html");
+
+  invokeInTab("injectScript");
+  await waitForSources(dbg, "doc-react-jsx.html", "main.js");
+  await selectSource(dbg, "main.js");
+  await addBreakpoint(dbg, "main.js", 3);
+  invokeInTab("foo");
+  await waitForPaused(dbg);
+  assertPausedLocation(dbg, "main.js", 3);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/doc-react-jsx.html
@@ -0,0 +1,111 @@
+ <!-- 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/. -->
+<html>
+  <head>
+    <title>Iframe</title>
+  </head>
+
+  <body>
+    <script type="text/plain">
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports) {
+
+function foo() {
+  console.log("HELLO WORLD!");
+}
+
+window.foo = foo;
+
+
+/***/ })
+/******/ ]);
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgOTJkOTBkNjA2OTAyNmRhZDBlNmIiLCJ3ZWJwYWNrOi8vLy4vc3JjL21haW4uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7QUFFQTtBQUNBOzs7Ozs7OztBQzVEQTtBQUNBO0FBQ0E7O0FBRUEiLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7XG4gXHRcdFx0XHRjb25maWd1cmFibGU6IGZhbHNlLFxuIFx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcbiBcdFx0XHRcdGdldDogZ2V0dGVyXG4gXHRcdFx0fSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSBmdW5jdGlvbihtb2R1bGUpIHtcbiBcdFx0dmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0RGVmYXVsdCgpIHsgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddOyB9IDpcbiBcdFx0XHRmdW5jdGlvbiBnZXRNb2R1bGVFeHBvcnRzKCkgeyByZXR1cm4gbW9kdWxlOyB9O1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCAnYScsIGdldHRlcik7XG4gXHRcdHJldHVybiBnZXR0ZXI7XG4gXHR9O1xuXG4gXHQvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubyA9IGZ1bmN0aW9uKG9iamVjdCwgcHJvcGVydHkpIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KTsgfTtcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gMCk7XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gd2VicGFjay9ib290c3RyYXAgOTJkOTBkNjA2OTAyNmRhZDBlNmIiLCJcbmZ1bmN0aW9uIGZvbygpIHtcbiAgY29uc29sZS5sb2coXCJIRUxMTyBXT1JMRCFcIik7XG59XG5cbndpbmRvdy5mb28gPSBmb287XG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL3NyYy9tYWluLmpzXG4vLyBtb2R1bGUgaWQgPSAwXG4vLyBtb2R1bGUgY2h1bmtzID0gMCJdLCJzb3VyY2VSb290IjoiIn0=
+    </script>
+
+    <script>
+
+      function injectScript() {
+        const jsxScript = document.querySelector("script[type='text/plain']");
+
+        const text = "";
+        const newScript = document.createElement("script");
+
+        newScript.text = jsxScript.text;
+        document.body.appendChild(newScript);
+      }
+
+      // This inline script allows this HTML page to show up as a
+      // source. It also needs to introduce a new global variable so
+      // it's not immediately garbage collected.
+      function inline_script() { var x = 5; }
+    </script>
+  </body>
+
+</html>
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1_jsx.js
@@ -5,16 +5,17 @@
 "use strict";
 
 requestLongerTimeout(4);
 
 // Test that markup view event bubbles show the correct event info for React
 // events (React development version 15.4.1) using JSX.
 
 const TEST_LIB = URL_ROOT + "lib_react_dom_15.4.1.js";
+const TEST_LIB_BABEL = URL_ROOT + "lib_babel_6.21.0_min.js";
 const TEST_EXTERNAL_LISTENERS = URL_ROOT + "react_external_listeners.js";
 const TEST_URL = URL_ROOT + "doc_markup_events_react_development_15.4.1_jsx.html";
 
 loadHelperScript("helper_events_test_runner.js");
 
 /*eslint-disable */
 const TEST_DATA = [
   {
@@ -26,17 +27,17 @@ const TEST_DATA = [
         attributes: [
           "Bubbling",
           "DOM2"
         ],
         handler: "function emptyFunction() {}"
       },
       {
         type: "onClick",
-        filename: TEST_URL + ":10",
+        filename: TEST_LIB_BABEL + ":10",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function inlineFunction() {
   alert("inlineFunction");
 }`
@@ -90,17 +91,17 @@ const TEST_DATA = [
         ],
         handler:
 `function externalFunction() {
   alert("externalFunction");
 }`
       },
       {
         type: "onMouseUp",
-        filename: TEST_URL + ":10",
+        filename: TEST_LIB_BABEL + ":10",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function inlineFunction() {
   alert("inlineFunction");
 }`
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1_jsx.js
@@ -5,16 +5,17 @@
 "use strict";
 
 requestLongerTimeout(4);
 
 // Test that markup view event bubbles show the correct event info for React
 // events (React production version 15.3.1) using JSX.
 
 const TEST_LIB = URL_ROOT + "lib_react_with_addons_15.3.1_min.js";
+const TEST_LIB_BABEL = URL_ROOT + "lib_babel_6.21.0_min.js";
 const TEST_EXTERNAL_LISTENERS = URL_ROOT + "react_external_listeners.js";
 const TEST_URL = URL_ROOT + "doc_markup_events_react_production_15.3.1_jsx.html";
 
 loadHelperScript("helper_events_test_runner.js");
 
 /*eslint-disable */
 const TEST_DATA = [
   {
@@ -26,17 +27,17 @@ const TEST_DATA = [
         attributes: [
           "Bubbling",
           "DOM2"
         ],
         handler: "function() {}"
       },
       {
         type: "onClick",
-        filename: TEST_URL + ":10",
+        filename: TEST_LIB_BABEL + ":10",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function() {
   alert("inlineFunction");
 }`
@@ -90,17 +91,17 @@ const TEST_DATA = [
         ],
         handler:
 `function externalFunction() {
   alert("externalFunction");
 }`
       },
       {
         type: "onMouseUp",
-        filename: TEST_URL + ":10",
+        filename: TEST_LIB_BABEL + ":10",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function() {
   alert("inlineFunction");
 }`
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0_jsx.js
@@ -5,16 +5,17 @@
 "use strict";
 
 requestLongerTimeout(4);
 
 // Test that markup view event bubbles show the correct event info for React
 // events (React production version 16.2.0) using JSX.
 
 const TEST_LIB = URL_ROOT + "lib_react_dom_16.2.0_min.js";
+const TEST_LIB_BABEL = URL_ROOT + "lib_babel_6.21.0_min.js";
 const TEST_EXTERNAL_LISTENERS = URL_ROOT + "react_external_listeners.js";
 const TEST_URL = URL_ROOT + "doc_markup_events_react_production_16.2.0_jsx.html";
 
 loadHelperScript("helper_events_test_runner.js");
 
 /*eslint-disable */
 const TEST_DATA = [
   {
@@ -26,17 +27,17 @@ const TEST_DATA = [
         attributes: [
           "Bubbling",
           "DOM2"
         ],
         handler: "function() {}"
       },
       {
         type: "onClick",
-        filename: TEST_URL + ":26",
+        filename: TEST_LIB_BABEL + ":26",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function inlineFunction() {
   alert("inlineFunction");
 }`
@@ -90,17 +91,17 @@ const TEST_DATA = [
         ],
         handler:
 `function externalFunction() {
   alert("externalFunction");
 }`
       },
       {
         type: "onMouseUp",
-        filename: TEST_URL + ":26",
+        filename: TEST_LIB_BABEL + ":26",
         attributes: [
           "Bubbling",
           "React"
         ],
         handler:
 `function inlineFunction() {
   alert("inlineFunction");
 }`
--- a/devtools/client/inspector/rules/actions/index.js
+++ b/devtools/client/inspector/rules/actions/index.js
@@ -3,12 +3,12 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { createEnum } = require("devtools/client/shared/enum");
 
 createEnum([
 
-  // Update the entire rules state with the new list of rules.
+  // Updates the rules state with the new list of CSS rules for the selected element.
   "UPDATE_RULES",
 
 ], module.exports);
--- a/devtools/client/inspector/rules/actions/moz.build
+++ b/devtools/client/inspector/rules/actions/moz.build
@@ -1,7 +1,8 @@
 # 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/.
 
 DevToolsModules(
     'index.js',
+    'rules.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/actions/rules.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+  UPDATE_RULES,
+} = require("./index");
+
+module.exports = {
+
+  /**
+   * Updates the rules state with the new list of CSS rules for the selected element.
+   *
+   * @param  {Array} rules
+   *         Array of Rule objects containing the selected element's CSS rules.
+   */
+  updateRules(rules) {
+    return {
+      type: UPDATE_RULES,
+      rules,
+    };
+  },
+
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/ClassListPanel.js
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const { getStr } = require("../utils/l10n");
+
+class ClassListPanel extends PureComponent {
+  static get propTypes() {
+    return {};
+  }
+
+  render() {
+    return (
+      dom.div(
+        {
+          id: "ruleview-class-panel",
+          className: "ruleview-reveal-panel",
+        },
+        dom.input({
+          className: "devtools-textinput add-class",
+          placeholder: getStr("rule.classPanel.newClass.placeholder"),
+        }),
+        dom.div({ className: "classes" },
+          dom.p({ className: "no-classes" }, getStr("rule.classPanel.noClasses"))
+        )
+      )
+    );
+  }
+}
+
+module.exports = ClassListPanel;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Declaration.js
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Types = require("../types");
+
+class Declaration extends PureComponent {
+  static get propTypes() {
+    return {
+      declaration: PropTypes.shape(Types.declaration).isRequired,
+    };
+  }
+
+  render() {
+    const { declaration } = this.props;
+    const {
+      isEnabled,
+      isKnownProperty,
+      isOverridden,
+      name,
+      value,
+    } = declaration;
+
+    return (
+      dom.li(
+        {
+          className: "ruleview-property" +
+                     (!isEnabled || !isKnownProperty || isOverridden ?
+                      " ruleview-overridden" : ""),
+        },
+        dom.div({ className: "ruleview-propertycontainer" },
+          dom.div({
+            className: "ruleview-enableproperty theme-checkbox" +
+                        (isEnabled ? " checked" : ""),
+            tabIndex: -1,
+          }),
+          dom.span({ className: "ruleview-namecontainer" },
+            dom.span({ className: "ruleview-propertyname theme-fg-color5" }, name),
+            ": "
+          ),
+          dom.span({ className: "ruleview-propertyvaluecontainer" },
+            dom.span({ className: "ruleview-propertyvalue theme-fg-color1" }, value),
+            ";"
+          )
+        )
+      )
+    );
+  }
+}
+
+module.exports = Declaration;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Declarations.js
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Declaration = createFactory(require("./Declaration"));
+
+const Types = require("../types");
+
+class Declarations extends PureComponent {
+  static get propTypes() {
+    return {
+      declarations: PropTypes.arrayOf(PropTypes.shape(Types.declaration)).isRequired,
+    };
+  }
+
+  render() {
+    const { declarations } = this.props;
+
+    if (!declarations.length) {
+      return null;
+    }
+
+    return (
+      dom.ul({ className: "ruleview-propertylist" },
+        declarations.map(declaration => {
+          return Declaration({
+            key: declaration.id,
+            declaration,
+          });
+        })
+      )
+    );
+  }
+}
+
+module.exports = Declarations;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/PseudoClassPanel.js
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+class PseudoClassPanel extends PureComponent {
+  static get propTypes() {
+    return {};
+  }
+
+  render() {
+    return (
+      dom.div(
+        {
+          id: "pseudo-class-panel",
+          className: "ruleview-reveal-panel",
+        },
+        dom.label({},
+          dom.input({
+            id: "pseudo-hover-toggle",
+            checked: false,
+            tabIndex: -1,
+            type: "checkbox",
+            value: ":hover",
+          }),
+          ":hover"
+        ),
+        dom.label({},
+          dom.input({
+            id: "pseudo-active-toggle",
+            checked: false,
+            tabIndex: -1,
+            type: "checkbox",
+            value: ":active",
+          }),
+          ":active"
+        ),
+        dom.label({},
+          dom.input({
+            id: "pseudo-focus-toggle",
+            checked: false,
+            tabIndex: -1,
+            type: "checkbox",
+            value: ":focus",
+          }),
+          ":focus"
+        )
+      )
+    );
+  }
+}
+
+module.exports = PseudoClassPanel;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Rule.js
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Declarations = createFactory(require("./Declarations"));
+const Selector = createFactory(require("./Selector"));
+const SourceLink = createFactory(require("./SourceLink"));
+
+const Types = require("../types");
+
+class Rule extends PureComponent {
+  static get propTypes() {
+    return {
+      rule: PropTypes.shape(Types.rule).isRequired,
+    };
+  }
+
+  render() {
+    const { rule } = this.props;
+    const {
+      declarations,
+      selector,
+      sourceLink,
+    } = rule;
+
+    return (
+      dom.div(
+        { className: "ruleview-rule devtools-monospace" },
+        SourceLink({ sourceLink }),
+        dom.div({ className: "ruleview-code" },
+          dom.div({},
+            Selector({ selector }),
+            dom.span({ className: "ruleview-ruleopen" }, " {")
+          ),
+          Declarations({ declarations }),
+          dom.div({ className: "ruleview-ruleclose" }, "}")
+        )
+      )
+    );
+  }
+}
+
+module.exports = Rule;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Rules.js
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Rule = createFactory(require("./Rule"));
+
+const Types = require("../types");
+
+class Rules extends PureComponent {
+  static get propTypes() {
+    return {
+      rules: PropTypes.arrayOf(PropTypes.shape(Types.rule)).isRequired,
+    };
+  }
+
+  render() {
+    return this.props.rules.map(rule => {
+      return Rule({
+        key: rule.id,
+        rule,
+      });
+    });
+  }
+}
+
+module.exports = Rules;
--- a/devtools/client/inspector/rules/components/RulesApp.js
+++ b/devtools/client/inspector/rules/components/RulesApp.js
@@ -1,35 +1,176 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { PureComponent } = require("devtools/client/shared/vendor/react");
+const Services = require("Services");
+const {
+  createElement,
+  createFactory,
+  Fragment,
+  PureComponent,
+} = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
+const Accordion = createFactory(require("devtools/client/inspector/layout/components/Accordion"));
+const Rule = createFactory(require("./Rule"));
+const Rules = createFactory(require("./Rules"));
+const Toolbar = createFactory(require("./Toolbar"));
+
 const { getStr } = require("../utils/l10n");
+const Types = require("../types");
+
+const SHOW_PSEUDO_ELEMENTS_PREF = "devtools.inspector.show_pseudo_elements";
 
 class RulesApp extends PureComponent {
   static get propTypes() {
-    return {};
+    return {
+      rules: PropTypes.arrayOf(PropTypes.shape(Types.rule)).isRequired,
+    };
+  }
+
+  renderInheritedRules(rules) {
+    if (!rules.length) {
+      return null;
+    }
+
+    const output = [];
+    let lastInherited;
+
+    for (const rule of rules) {
+      if (rule.inheritance.inherited !== lastInherited) {
+        lastInherited = rule.inheritance.inherited;
+
+        output.push(
+          dom.div({ className: "ruleview-header" }, rule.inheritance.inheritedSource)
+        );
+      }
+
+      output.push(Rule({ rule }));
+    }
+
+    return output;
+  }
+
+  renderKeyframesRules(rules) {
+    if (!rules.length) {
+      return null;
+    }
+
+    const output = [];
+    let lastKeyframes;
+
+    for (const rule of rules) {
+      if (rule.keyframesRule.id === lastKeyframes) {
+        continue;
+      }
+
+      lastKeyframes = rule.keyframesRule.id;
+
+      const items = [
+        {
+          component: Rules,
+          componentProps: {
+            rules: rules.filter(r => r.keyframesRule.id === lastKeyframes),
+          },
+          header: rule.keyframesRule.keyframesName,
+          opened: true,
+        },
+      ];
+
+      output.push(Accordion({ items }));
+    }
+
+    return output;
+  }
+
+  renderStyleRules(rules) {
+    if (!rules.length) {
+      return null;
+    }
+
+    return Rules({ rules });
+  }
+
+  renderPseudoElementRules(rules) {
+    if (!rules.length) {
+      return null;
+    }
+
+    const items = [
+      {
+        component: Rules,
+        componentProps: { rules },
+        header: getStr("rule.pseudoElement"),
+        opened: Services.prefs.getBoolPref(SHOW_PSEUDO_ELEMENTS_PREF),
+        onToggled: () => {
+          const opened = Services.prefs.getBoolPref(SHOW_PSEUDO_ELEMENTS_PREF);
+          Services.prefs.setBoolPref(SHOW_PSEUDO_ELEMENTS_PREF, !opened);
+        },
+      },
+    ];
+
+    return createElement(Fragment, null,
+      Accordion({ items }),
+      dom.div({ className: "ruleview-header" }, getStr("rule.selectedElement"))
+    );
   }
 
   render() {
-    return dom.div(
-      {
-        id: "sidebar-panel-ruleview",
-        className: "theme-sidebar inspector-tabpanel",
-      },
+    const { rules } = this.props.rules;
+    const inheritedRules = [];
+    const keyframesRules = [];
+    const pseudoElementRules = [];
+    const styleRules = [];
+
+    for (const rule of rules) {
+      if (rule.inheritance) {
+        inheritedRules.push(rule);
+      } else if (rule.keyframesRule) {
+        keyframesRules.push(rule);
+      } else if (rule.pseudoElement) {
+        pseudoElementRules.push(rule);
+      } else {
+        styleRules.push(rule);
+      }
+    }
+
+    return (
       dom.div(
         {
-          id: "ruleview-no-results",
-          className: "devtools-sidepanel-no-result",
+          id: "sidebar-panel-ruleview",
+          className: "theme-sidebar inspector-tabpanel",
         },
-        getStr("rule.empty")
+        Toolbar({}),
+        dom.div(
+          {
+            id: "ruleview-container",
+            className: "ruleview",
+          },
+          dom.div(
+            {
+              id: "ruleview-container-focusable",
+              tabIndex: -1,
+            },
+            rules.length > 0 ?
+              createElement(Fragment, null,
+                this.renderPseudoElementRules(pseudoElementRules),
+                this.renderStyleRules(styleRules),
+                this.renderInheritedRules(inheritedRules),
+                this.renderKeyframesRules(keyframesRules)
+              )
+              :
+              dom.div({ className: "devtools-sidepanel-no-result" },
+                getStr("rule.empty")
+              )
+          )
+        )
       )
     );
   }
 }
 
 module.exports = connect(state => state)(RulesApp);
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/SearchBox.js
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const { getStr } = require("../utils/l10n");
+
+class SearchBox extends PureComponent {
+  static get propTypes() {
+    return {};
+  }
+
+  render() {
+    return (
+      dom.div({ className: "devtools-searchbox has-clear-btn" },
+        dom.input({
+          id: "ruleview-searchbox",
+          className: "devtools-filterinput devtools-rule-searchbox",
+          placeholder: getStr("rule.filterStyles.placeholder"),
+          type: "search",
+        }),
+        dom.button({
+          id: "ruleview-searchinput-clear",
+          className: "devtools-searchinput-clear",
+        })
+      )
+    );
+  }
+}
+
+module.exports = SearchBox;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Selector.js
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Types = require("../types");
+
+class Selector extends PureComponent {
+  static get propTypes() {
+    return {
+      selector: PropTypes.shape(Types.selector).isRequired,
+    };
+  }
+
+  render() {
+    const { selectorText } = this.props.selector;
+
+    return (
+      dom.span(
+        {
+          className: "ruleview-selectorcontainer",
+          tabIndex: -1,
+        },
+        selectorText
+      )
+    );
+  }
+}
+
+module.exports = Selector;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/SourceLink.js
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Types = require("../types");
+
+class SourceLink extends PureComponent {
+  static get propTypes() {
+    return {
+      sourceLink: PropTypes.shape(Types.sourceLink).isRequired,
+    };
+  }
+
+  render() {
+    const { sourceLink } = this.props;
+
+    return (
+      dom.div({ className: "ruleview-rule-source theme-link" },
+        dom.span({ className: "ruleview-rule-source-label" },
+          sourceLink.title
+        )
+      )
+    );
+  }
+}
+
+module.exports = SourceLink;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/components/Toolbar.js
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const SearchBox = createFactory(require("./SearchBox"));
+
+loader.lazyGetter(this, "ClassListPanel", function() {
+  return createFactory(require("./ClassListPanel"));
+});
+loader.lazyGetter(this, "PseudoClassPanel", function() {
+  return createFactory(require("./PseudoClassPanel"));
+});
+
+const { getStr } = require("../utils/l10n");
+
+class Toolbar extends PureComponent {
+  static get propTypes() {
+    return {};
+  }
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      // Whether or not the class panel is expanded.
+      isClassPanelExpanded: false,
+      // Whether or not the pseudo class panel is expanded.
+      isPseudoClassPanelExpanded: false,
+    };
+
+    this.onClassPanelToggle = this.onClassPanelToggle.bind(this);
+    this.onPseudoClassPanelToggle = this.onPseudoClassPanelToggle.bind(this);
+  }
+
+  onClassPanelToggle(event) {
+    event.stopPropagation();
+
+    this.setState(prevState => {
+      const isClassPanelExpanded = !prevState.isClassPanelExpanded;
+      const isPseudoClassPanelExpanded = isClassPanelExpanded ?
+        false : prevState.isPseudoClassPanelExpanded;
+
+      return {
+        isClassPanelExpanded,
+        isPseudoClassPanelExpanded,
+      };
+    });
+  }
+
+  onPseudoClassPanelToggle(event) {
+    event.stopPropagation();
+
+    this.setState(prevState => {
+      const isPseudoClassPanelExpanded = !prevState.isPseudoClassPanelExpanded;
+      const isClassPanelExpanded = isPseudoClassPanelExpanded ?
+        false : prevState.isClassPanelExpanded;
+
+      return {
+        isClassPanelExpanded,
+        isPseudoClassPanelExpanded,
+      };
+    });
+  }
+
+  render() {
+    const {
+      isClassPanelExpanded,
+      isPseudoClassPanelExpanded,
+    } = this.state;
+
+    return (
+      dom.div(
+        {
+          id: "ruleview-toolbar-container",
+          className: "devtools-toolbar",
+        },
+        dom.div({ id: "ruleview-toolbar" },
+          SearchBox({}),
+          dom.div({ id: "ruleview-command-toolbar" },
+            dom.button({
+              id: "ruleview-add-rule-button",
+              className: "devtools-button",
+              title: getStr("rule.addRule.tooltip"),
+            }),
+            dom.button({
+              id: "pseudo-class-panel-toggle",
+              className: "devtools-button" +
+                          (isPseudoClassPanelExpanded ? " checked" : ""),
+              onClick: this.onPseudoClassPanelToggle,
+              title: getStr("rule.togglePseudo.tooltip"),
+            }),
+            dom.button({
+              id: "class-panel-toggle",
+              className: "devtools-button" +
+                          (isClassPanelExpanded ? " checked" : ""),
+              onClick: this.onClassPanelToggle,
+              title: getStr("rule.classPanel.toggleClass.tooltip"),
+            })
+          )
+        ),
+        isClassPanelExpanded ?
+          ClassListPanel({})
+          :
+          null,
+        isPseudoClassPanelExpanded ?
+          PseudoClassPanel({})
+          :
+          null
+      )
+    );
+  }
+}
+
+module.exports = Toolbar;
--- a/devtools/client/inspector/rules/components/moz.build
+++ b/devtools/client/inspector/rules/components/moz.build
@@ -1,7 +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/.
 
 DevToolsModules(
+    'ClassListPanel.js',
+    'Declaration.js',
+    'Declarations.js',
+    'PseudoClassPanel.js',
+    'Rule.js',
+    'Rules.js',
     'RulesApp.js',
+    'SearchBox.js',
+    'Selector.js',
+    'SourceLink.js',
+    'Toolbar.js',
 )
--- a/devtools/client/inspector/rules/models/rule.js
+++ b/devtools/client/inspector/rules/models/rule.js
@@ -57,16 +57,48 @@ function Rule(elementStyle, options) {
   // value, and add in any disabled properties from the store.
   this.textProps = this._getTextProperties();
   this.textProps = this.textProps.concat(this._getDisabledProperties());
 }
 
 Rule.prototype = {
   mediaText: "",
 
+  get declarations() {
+    return this.textProps;
+  },
+
+  get inheritance() {
+    if (!this.inherited) {
+      return null;
+    }
+
+    return {
+      inherited: this.inherited,
+      inheritedSource: this.inheritedSource,
+    };
+  },
+
+  get selector() {
+    return {
+      matchedSelectors: this.matchedSelectors,
+      selectors: this.domRule.selectors,
+      selectorText: this.selectorText,
+    };
+  },
+
+  get sourceLink() {
+    return {
+      column: this.ruleColumn,
+      line: this.ruleLine,
+      mediaText: this.mediaText,
+      title: this.title,
+    };
+  },
+
   get title() {
     let title = CssLogic.shortSource(this.sheet);
     if (this.domRule.type !== ELEMENT_STYLE && this.ruleLine > 0) {
       title += ":" + this.ruleLine;
     }
 
     return title + (this.mediaText ? " @media " + this.mediaText : "");
   },
@@ -94,16 +126,27 @@ Rule.prototype = {
     this._keyframesName = "";
     if (this.keyframes) {
       this._keyframesName =
         STYLE_INSPECTOR_L10N.getFormatStr("rule.keyframe", this.keyframes.name);
     }
     return this._keyframesName;
   },
 
+  get keyframesRule() {
+    if (!this.keyframes) {
+      return null;
+    }
+
+    return {
+      id: this.keyframes.actorID,
+      keyframesName: this.keyframesName,
+    };
+  },
+
   get selectorText() {
     return this.domRule.selectors ? this.domRule.selectors.join(", ") :
       CssLogic.l10n("rule.sourceElement");
   },
 
   /**
    * The rule's stylesheet.
    */
--- a/devtools/client/inspector/rules/models/text-property.js
+++ b/devtools/client/inspector/rules/models/text-property.js
@@ -43,16 +43,35 @@ function TextProperty(rule, name, value,
   this.invisible = invisible;
   this.cssProperties = this.rule.elementStyle.ruleView.cssProperties;
   this.panelDoc = this.rule.elementStyle.ruleView.inspector.panelDoc;
 
   this.updateComputed();
 }
 
 TextProperty.prototype = {
+  get computedProperties() {
+    return this.computed.map(computed => {
+      return {
+        name: computed.name,
+        priority: computed.priority,
+        value: computed.value,
+      };
+    });
+  },
+
+  /**
+   * See whether this property's name is known.
+   *
+   * @return {Boolean} true if the property name is known, false otherwise.
+   */
+  get isKnownProperty() {
+    return this.cssProperties.isKnown(this.name);
+  },
+
   /**
    * Update the editor associated with this text property,
    * if any.
    */
   updateEditor: function() {
     if (this.editor) {
       this.editor.update();
     }
@@ -170,25 +189,16 @@ TextProperty.prototype = {
     if (!this.enabled) {
       declaration = "/* " + escapeCSSComment(declaration) + " */";
     }
 
     return declaration;
   },
 
   /**
-   * See whether this property's name is known.
-   *
-   * @return {Boolean} true if the property name is known, false otherwise.
-   */
-  isKnownProperty: function() {
-    return this.cssProperties.isKnown(this.name);
-  },
-
-  /**
    * Validate this property. Does it make sense for this value to be assigned
    * to this property name?
    *
    * @return {Boolean} true if the whole CSS declaration is valid, false otherwise.
    */
   isValid: function() {
     const selfIndex = this.rule.textProps.indexOf(this);
 
--- a/devtools/client/inspector/rules/moz.build
+++ b/devtools/client/inspector/rules/moz.build
@@ -11,14 +11,15 @@ DIRS += [
     'reducers',
     'utils',
     'views',
 ]
 
 DevToolsModules(
     'new-rules.js',
     'rules.js',
+    'types.js',
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 with Files('**'):
     BUG_COMPONENT = ('DevTools', 'CSS Rules Inspector')
--- a/devtools/client/inspector/rules/new-rules.js
+++ b/devtools/client/inspector/rules/new-rules.js
@@ -1,28 +1,46 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const Services = require("Services");
+const ElementStyle = require("devtools/client/inspector/rules/models/element-style");
 const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 
+const { updateRules } = require("./actions/rules");
+
 const RulesApp = createFactory(require("./components/RulesApp"));
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const INSPECTOR_L10N =
   new LocalizationHelper("devtools/client/locales/inspector.properties");
 
+const PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles";
+
 class RulesView {
   constructor(inspector, window) {
-    this.document = window.document;
+    this.cssProperties = inspector.cssProperties;
+    this.doc = window.document;
     this.inspector = inspector;
+    this.pageStyle = inspector.pageStyle;
+    this.selection = inspector.selection;
     this.store = inspector.store;
+    this.toolbox = inspector.toolbox;
+
+    this.showUserAgentStyles = Services.prefs.getBoolPref(PREF_UA_STYLES);
+
+    this.onSelection = this.onSelection.bind(this);
+
+    this.inspector.sidebar.on("select", this.onSelection);
+    this.selection.on("detached-front", this.onSelection);
+    this.selection.on("new-node-front", this.onSelection);
 
     this.init();
   }
 
   init() {
     if (!this.inspector) {
       return;
     }
@@ -31,20 +49,101 @@ class RulesView {
 
     const provider = createElement(Provider, {
       id: "ruleview",
       key: "ruleview",
       store: this.store,
       title: INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"),
     }, rulesApp);
 
-    // Expose the provider to let inspector.js use it in setupSidebar.
+    // Exposes the provider to let inspector.js use it in setupSidebar.
     this.provider = provider;
   }
 
   destroy() {
-    this.document = null;
+    this.inspector.sidebar.off("select", this.onSelection);
+    this.selection.off("detached-front", this.onSelection);
+    this.selection.off("new-node-front", this.onSelection);
+
+    if (this.elementStyle) {
+      this.elementStyle.destroy();
+    }
+
+    this._dummyElement = null;
+    this.cssProperties = null;
+    this.doc = null;
+    this.elementStyle = null;
     this.inspector = null;
+    this.pageStyle = null;
+    this.selection = null;
+    this.showUserAgentStyles = null;
     this.store = null;
+    this.toolbox = null;
+  }
+
+  /**
+   * Creates a dummy element in the document that helps get the computed style in
+   * TextProperty.
+   *
+   * @return {Element} used to get the computed style for text properties.
+   */
+  get dummyElement() {
+    // To figure out how shorthand properties are interpreted by the
+    // engine, we will set properties on a dummy element and observe
+    // how their .style attribute reflects them as computed values.
+    if (!this._dummyElement) {
+      this._dummyElement = this.doc.createElement("div");
+    }
+
+    return this._dummyElement;
+  }
+
+  /**
+   * Returns true if the rules panel is visible, and false otherwise.
+   */
+  isPanelVisible() {
+    return this.inspector && this.inspector.toolbox && this.inspector.sidebar &&
+           this.inspector.toolbox.currentToolId === "inspector" &&
+           this.inspector.sidebar.getCurrentTabID() === "newruleview";
+  }
+
+  /**
+   * Handler for selection events "detached-front" and "new-node-front" and inspector
+   * sidbar "select" event. Updates the rules view with the selected node if the panel
+   * is visible.
+   */
+  onSelection() {
+    if (!this.isPanelVisible()) {
+      return;
+    }
+
+    if (!this.selection.isConnected() ||
+        !this.selection.isElementNode()) {
+      this.update();
+      return;
+    }
+
+    this.update(this.selection.nodeFront);
+  }
+
+  /**
+   * Updates the rules view by dispatching the new rules data of the newly selected
+   * element. This is called when the rules view becomes visible or upon new node
+   * selection.
+   *
+   * @param  {NodeFront|null} element
+   *         The NodeFront of the current selected element.
+   */
+  async update(element) {
+    if (!element) {
+      this.store.dispatch(updateRules([]));
+      return;
+    }
+
+    this.elementStyle = new ElementStyle(element, this, {}, this.pageStyle,
+      this.showUserAgentStyles);
+    await this.elementStyle.populate();
+
+    this.store.dispatch(updateRules(this.elementStyle.rules));
   }
 }
 
 module.exports = RulesView;
--- a/devtools/client/inspector/rules/reducers/rules.js
+++ b/devtools/client/inspector/rules/reducers/rules.js
@@ -1,18 +1,93 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const INITIAL_RULES = {};
+const {
+  UPDATE_RULES,
+} = require("../actions/index");
+
+const INITIAL_RULES = {
+  // Array of CSS rules.
+  rules: [],
+};
+
+/**
+ * Given a rule's TextProperty, returns the properties that are needed to render a
+ * CSS declaration.
+ *
+ * @param  {TextProperty} declaration
+ *         A TextProperty of a rule.
+ * @param  {Number} index
+ *         The index of the CSS declaration within the declaration block.
+ * @return {Object} containing the properties needed to render a CSS declaration.
+ */
+function getDeclarationState(declaration, index) {
+  return {
+    // Array of the computed properties for a CSS declaration.
+    computedProperties: declaration.computedProperties,
+    // An unique CSS declaration id.
+    id: `${declaration.name}${declaration.value}${index}`,
+    // Whether or not the declaration is enabled.
+    isEnabled: declaration.enabled,
+    // Whether or not the declaration's property name is known.
+    isKnownProperty: declaration.isKnownProperty,
+    // Whether or not the the declaration is overridden.
+    isOverridden: !!declaration.overridden,
+    // The declaration's property name.
+    name: declaration.name,
+    // The declaration's priority (either "important" or an empty string).
+    priority: declaration.priority,
+    // The declaration's property value.
+    value: declaration.value,
+  };
+}
+
+/**
+ * Given a Rule, returns the properties that are needed to render a CSS rule.
+ *
+ * @param  {Rule} rule
+ *         A Rule object containing information about a CSS rule.
+ * @return {Object} containing the properties needed to render a CSS rule.
+ */
+function getRuleState(rule) {
+  return {
+    // Array of CSS declarations.
+    declarations: rule.declarations.map((declaration, i) =>
+      getDeclarationState(declaration, i)),
+    // An unique CSS rule id.
+    id: rule.domRule.actorID,
+    // An object containing information about the CSS rule's inheritance.
+    inheritance: rule.inheritance,
+    // Whether or not the rule does not match the current selected element.
+    isUnmatched: rule.isUnmatched,
+    // Whether or not the rule is an user agent style.
+    isUserAgentStyle: rule.isSystem,
+    // An object containing information about the CSS keyframes rules.
+    keyframesRule: rule.keyframesRule,
+    // An object containing information about the CSS rule's selector.
+    selector: rule.selector,
+    // An object containing information about the CSS rule's stylesheet source.
+    sourceLink: rule.sourceLink,
+    // The CSS rule type.
+    type: rule.domRule.type,
+  };
+}
 
 const reducers = {
 
+  [UPDATE_RULES](_, { rules }) {
+    return {
+      rules: rules.map(rule => getRuleState(rule)),
+    };
+  },
+
 };
 
 module.exports = function(rules = INITIAL_RULES, action) {
   const reducer = reducers[action.type];
   if (!reducer) {
     return rules;
   }
   return reducer(rules, action);
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/types.js
@@ -0,0 +1,112 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+/**
+ * A CSS declaration.
+ */
+const declaration = exports.declaration = {
+  // Array of the computed properties for a CSS declaration.
+  computedProperties: PropTypes.arrayOf(PropTypes.shape({
+    // The computed property name.
+    name: PropTypes.string,
+    // The computed priority (either "important" or an empty string).
+    priority: PropTypes.string,
+    // The computed property value.
+    value: PropTypes.string,
+  })),
+
+  // An unique CSS declaration id.
+  id: PropTypes.string,
+
+  // Whether or not the declaration is enabled.
+  isEnabled: PropTypes.bool,
+
+  // Whether or not the declaration's property name is known.
+  isKnownProperty: PropTypes.bool,
+
+  // Whether or not the the declaration is overridden.
+  isOverridden: PropTypes.bool,
+
+  // The declaration's property name.
+  name: PropTypes.string,
+
+  // The declaration's priority (either "important" or an empty string).
+  priority: PropTypes.string,
+
+  // The declaration's property value.
+  value: PropTypes.string,
+};
+
+/**
+ * A CSS selector.
+ */
+const selector = exports.selector = {
+  // Array of the selectors that match the selected element.
+  matchedSelectors: PropTypes.arrayOf(PropTypes.string),
+  // The CSS rule's selector text content.
+  selectorText: PropTypes.string,
+  // Array of the CSS rule's selectors.
+  selectors: PropTypes.arrayOf(PropTypes.string),
+};
+
+/**
+ * A CSS rule's stylesheet source.
+ */
+const sourceLink = exports.sourceLink = {
+  // The CSS rule's column number within the stylesheet.
+  column: PropTypes.number,
+  // The CSS rule's line number within the stylesheet.
+  line: PropTypes.number,
+  // The media query text within a @media rule.
+  // Note: Abstract this to support other at-rules in the future.
+  mediaText: PropTypes.string,
+  // The title used for the stylesheet source.
+  title: PropTypes.string,
+};
+
+/**
+ * A CSS Rule.
+ */
+exports.rule = {
+  // Array of CSS declarations.
+  declarations: PropTypes.arrayOf(PropTypes.shape(declaration)),
+
+  // An unique CSS rule id.
+  id: PropTypes.string,
+
+  // An object containing information about the CSS rule's inheritance.
+  inheritance: PropTypes.shape({
+    // The NodeFront of the element this rule was inherited from.
+    inherited: PropTypes.object,
+    // A header label for where the element this rule was inherited from.
+    inheritedSource: PropTypes.string,
+  }),
+
+  // Whether or not the rule does not match the current selected element.
+  isUnmatched: PropTypes.bool,
+
+  // Whether or not the rule is an user agent style.
+  isUserAgentStyle: PropTypes.bool,
+
+  // An object containing information about the CSS keyframes rules.
+  keyframesRule: PropTypes.shape({
+    // The actor ID of the keyframes rule.
+    id: PropTypes.string,
+    // The keyframes rule name.
+    keyframesName: PropTypes.string,
+  }),
+
+  // An object containing information about the CSS rule's selector.
+  selector: PropTypes.shape(selector),
+
+  // An object containing information about the CSS rule's stylesheet source.
+  sourceLink: PropTypes.shape(sourceLink),
+
+  // The CSS rule type.
+  type: PropTypes.number,
+};
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -608,17 +608,17 @@ TextPropertyEditor.prototype = {
                                  !this.prop.overridden ||
                                  this.ruleEditor.rule.isUnmatched;
 
     const showExpander = this.prop.computed.some(c => c.name !== this.prop.name);
     this.expander.style.display = showExpander ? "inline-block" : "none";
 
     if (!this.editing &&
         (this.prop.overridden || !this.prop.enabled ||
-         !this.prop.isKnownProperty())) {
+         !this.prop.isKnownProperty)) {
       this.element.classList.add("ruleview-overridden");
     } else {
       this.element.classList.remove("ruleview-overridden");
     }
   },
 
   /**
    * Update the indicator for computed styles. The computed styles themselves
--- a/devtools/client/netmonitor/test/browser_net_copy_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_headers.js
@@ -32,17 +32,17 @@ add_task(async function() {
 
   const selectedRequest = getSelectedRequest(store.getState());
   is(selectedRequest, requestItem, "Proper request is selected");
 
   const EXPECTED_REQUEST_HEADERS = [
     `${method} ${SIMPLE_URL} ${httpVersion}`,
     "Host: example.com",
     "User-Agent: " + navigator.userAgent + "",
-    "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
+    "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
     "Accept-Language: " + navigator.languages.join(",") + ";q=0.5",
     "Accept-Encoding: gzip, deflate",
     "Connection: keep-alive",
     "Upgrade-Insecure-Requests: 1",
     "Pragma: no-cache",
     "Cache-Control: no-cache",
   ].join("\n");
 
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -714,20 +714,22 @@ checkbox:-moz-focusring {
   fill: rgba(0,0,0,.3);
   stroke: transparent;
 }
 
 .theme-dark .theme-checkbox {
   fill: rgba(255,255,255,.4);
 }
 
+.theme-checkbox.checked,
 .theme-checkbox[checked] {
   stroke: rgba(0,0,0,.6);
 }
 
+.theme-dark .theme-checkbox.checked,
 .theme-dark .theme-checkbox[checked] {
   stroke: rgba(255,255,255,.8);
 }
 
 /* Throbbers */
 .devtools-throbber::before {
   content: "";
   display: inline-block;
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -139,16 +139,20 @@
 }
 
 #ruleview-container.non-interactive {
   pointer-events: none;
   visibility: collapse;
   transition: visibility 0.25s;
 }
 
+#ruleview-container .accordion ._content {
+  padding: 0;
+}
+
 .ruleview-code {
   direction: ltr;
 }
 
 .ruleview-property:not(:hover) > .ruleview-enableproperty {
   pointer-events: none;
 }
 
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -18,16 +18,24 @@ const { joinURI } = require("devtools/sh
 const { sourceSpec } = require("devtools/shared/specs/source");
 const { findClosestScriptBySource } = require("devtools/server/actors/utils/closest-scripts");
 
 loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
 loader.lazyRequireGetter(this, "arrayBufferGrip", "devtools/server/actors/array-buffer", true);
 
 function isEvalSource(source) {
   const introType = source.introductionType;
+
+  // Script elements that are dynamically created are treated as eval sources.
+  // We detect these by looking at whether there was another script on the stack
+  // when the source was created.
+  if (introType == "scriptElement" && source.introductionScript) {
+    return true;
+  }
+
   // These are all the sources that are essentially eval-ed (either
   // by calling eval or passing a string to one of these functions).
   return (introType === "eval" ||
           introType === "debugger eval" ||
           introType === "Function" ||
           introType === "eventHandler" ||
           introType === "setTimeout" ||
           introType === "setInterval");
--- a/devtools/server/actors/utils/TabSources.js
+++ b/devtools/server/actors/utils/TabSources.js
@@ -233,17 +233,24 @@ TabSources.prototype = {
     // need to be conservative and only treat valid js files as real
     // sources. Otherwise, use the `originalUrl` property to treat it
     // as an HTML source that manages multiple inline sources.
 
     // Assume the source is inline if the element that introduced it is not a
     // script element, or does not have a src attribute.
     const element = source.element ? source.element.unsafeDereference() : null;
     if (element && (element.tagName !== "SCRIPT" || !element.hasAttribute("src"))) {
-      spec.isInlineSource = true;
+      if (source.introductionScript) {
+        // As for other evaluated sources, script elements which were
+        // dynamically generated when another script ran should have
+        // a javascript content-type.
+        spec.contentType = "text/javascript";
+      } else {
+        spec.isInlineSource = true;
+      }
     } else if (source.introductionType === "wasm") {
       // Wasm sources are not JavaScript. Give them their own content-type.
       spec.contentType = "text/wasm";
     } else if (source.introductionType === "debugger eval") {
       // All debugger eval code should have a text/javascript content-type.
       // See Bug 1399064
       spec.contentType = "text/javascript";
     } else if (url) {
--- a/devtools/server/tests/mochitest/test_Debugger.Source.prototype.introductionScript.html
+++ b/devtools/server/tests/mochitest/test_Debugger.Source.prototype.introductionScript.html
@@ -63,36 +63,35 @@ window.onload = function() {
     doc.body.appendChild(script2);
   }
 
   function evalHandler(frame) {
     // The top stack frame's source should be introduced by the script that
     // called eval.
     const source = frame.script.source;
     const frame2 = frame.older;
+    const frame3 = frame2.older;
 
     ok(source.introductionType === "eval",
        "top frame's source was introduced by 'eval'");
     ok(source.introductionScript === frame2.script,
        "eval frame's introduction script is the older frame's script");
     ok(source.introductionOffset === frame2.offset,
        "eval frame's introduction offset is current offset in older frame");
     ok(source.introductionScript.source.element === script2DO,
        "eval frame's introducer belongs to script2 element");
 
-    // The frame that called eval, in turn, should have no introduction
-    // information. (In the future, we certainly could point at the call
-    // that inserted the script element into the document; if that happens,
-    // we can update this test.)
+    // The frame that called eval, in turn, was introduced at the call that
+    // inserted the script element into the document.
     ok(frame2.script.source.introductionType === "scriptElement",
        "older frame has no introduction type");
-    ok(frame2.script.source.introductionScript === undefined,
-       "older frame has no introduction script");
-    ok(frame2.script.source.introductionOffset === undefined,
-       "older frame has no introduction offset");
+    ok(frame2.script.source.introductionScript === frame3.script,
+       "older frame has introduction script");
+    ok(frame2.script.source.introductionOffset === frame3.offset,
+       "older frame has introduction offset");
 
     SimpleTest.finish();
   }
 };
 </script>
 </pre>
 </body>
 </html>
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -8697,35 +8697,35 @@ void Document::ScrollToRef() {
     if (!ref.IsEmpty()) {
       // Note that GoToAnchor will handle flushing layout as needed.
       rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
     } else {
       rv = NS_ERROR_FAILURE;
     }
 
     if (NS_FAILED(rv)) {
-      char* tmpstr = ToNewCString(mScrollToRef);
-      if (!tmpstr) {
-        return;
-      }
-      nsUnescape(tmpstr);
-      nsAutoCString unescapedRef;
-      unescapedRef.Assign(tmpstr);
-      free(tmpstr);
-
-      NS_ConvertUTF8toUTF16 utf16Str(unescapedRef);
-      if (!utf16Str.IsEmpty()) {
-        rv = shell->GoToAnchor(utf16Str, mChangeScrollPosWhenScrollingToRef);
+      nsAutoCString buff;
+      const bool unescaped =
+          NS_UnescapeURL(mScrollToRef.BeginReading(), mScrollToRef.Length(),
+                         /*aFlags =*/0, buff);
+
+      // This attempt is only necessary if characters were unescaped.
+      if (unescaped) {
+        NS_ConvertUTF8toUTF16 utf16Str(buff);
+        if (!utf16Str.IsEmpty()) {
+          rv = shell->GoToAnchor(utf16Str, mChangeScrollPosWhenScrollingToRef);
+        }
       }
 
       // If UTF-8 URI failed then try to assume the string as a
       // document's charset.
       if (NS_FAILED(rv)) {
         const Encoding* encoding = GetDocumentCharacterSet();
-        rv = encoding->DecodeWithoutBOMHandling(unescapedRef, ref);
+        rv = encoding->DecodeWithoutBOMHandling(
+            unescaped ? buff : mScrollToRef, ref);
         if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
           rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
         }
       }
     }
     if (NS_SUCCEEDED(rv)) {
       mScrolledToRefAlready = true;
     }
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -1387,44 +1387,33 @@ void FetchDriver::SetRequestHeaders(nsIH
   // Accept-Languages, ...) and we don't want to merge the Request's headers
   // with them. This array is used to know if the current header has been aleady
   // set, if yes, we ask necko to merge it with the previous one, otherwise, we
   // don't want the merge.
   nsTArray<nsCString> headersSet;
 
   AutoTArray<InternalHeaders::Entry, 5> headers;
   mRequest->Headers()->GetEntries(headers);
-  bool hasAccept = false;
   for (uint32_t i = 0; i < headers.Length(); ++i) {
     bool alreadySet = headersSet.Contains(headers[i].mName);
     if (!alreadySet) {
       headersSet.AppendElement(headers[i].mName);
     }
 
-    if (!hasAccept && headers[i].mName.EqualsIgnoreCase("accept")) {
-      hasAccept = true;
-    }
     if (headers[i].mValue.IsEmpty()) {
       DebugOnly<nsresult> rv =
           aChannel->SetEmptyRequestHeader(headers[i].mName);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     } else {
       DebugOnly<nsresult> rv = aChannel->SetRequestHeader(
           headers[i].mName, headers[i].mValue, alreadySet /* merge */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
-  if (!hasAccept) {
-    DebugOnly<nsresult> rv = aChannel->SetRequestHeader(
-        NS_LITERAL_CSTRING("accept"), NS_LITERAL_CSTRING("*/*"),
-        false /* merge */);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
-  }
-
   nsAutoCString method;
   mRequest->GetMethod(method);
   if (!method.EqualsLiteral("GET") && !method.EqualsLiteral("HEAD")) {
     nsAutoString origin;
     if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {
       DebugOnly<nsresult> rv = aChannel->SetRequestHeader(
           nsDependentCString(net::nsHttp::Origin),
           NS_ConvertUTF16toUTF8(origin), false /* merge */);
--- a/dom/power/PowerManagerService.cpp
+++ b/dom/power/PowerManagerService.cpp
@@ -3,16 +3,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/. */
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/Hal.h"
 #include "mozilla/HalWakeLock.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ModuleUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDOMWindow.h"
 #include "nsIObserverService.h"
 #include "PowerManagerService.h"
 #include "WakeLock.h"
 
 // For _exit().
@@ -143,8 +144,40 @@ already_AddRefed<WakeLock> PowerManagerS
   nsresult rv = wakelock->Init(aTopic, aContentParent);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return wakelock.forget();
 }
 
 }  // namespace power
 }  // namespace dom
 }  // namespace mozilla
+
+NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
+                                         mozilla::dom::power::PowerManagerService::GetInstance)
+
+static const mozilla::Module::CIDEntry kPowerManagerCIDs[] = {
+    // clang-format off
+  { &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor, mozilla::Module::ALLOW_IN_GPU_PROCESS },
+  { nullptr }
+    // clang-format on
+};
+
+static const mozilla::Module::ContractIDEntry kPowerManagerContracts[] = {
+    // clang-format off
+  { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID, mozilla::Module::ALLOW_IN_GPU_PROCESS },
+  { nullptr }
+    // clang-format on
+};
+
+// We mark the power module as being available in the GPU process because the
+// appshell depends on the power manager service.
+static const mozilla::Module kPowerManagerModule = {mozilla::Module::kVersion,
+                                                    kPowerManagerCIDs,
+                                                    kPowerManagerContracts,
+                                                    nullptr,
+                                                    nullptr,
+                                                    nullptr,
+                                                    nullptr,
+                                                    mozilla::Module::ALLOW_IN_GPU_PROCESS};
+
+NSMODULE_DEFN(nsPowerManagerModule) = &kPowerManagerModule;
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -2296,18 +2296,19 @@ nsresult ScriptLoader::FillCompileOption
   }
 
   if (mDocument) {
     mDocument->NoteScriptTrackingStatus(aRequest->mURL, aRequest->IsTracking());
   }
 
   bool isScriptElement =
       !aRequest->IsModuleRequest() || aRequest->AsModuleRequest()->IsTopLevel();
-  aOptions->setIntroductionType(isScriptElement ? "scriptElement"
-                                                : "importedModule");
+  aOptions->setIntroductionInfoToCaller(jsapi.cx(),
+                                        isScriptElement ? "scriptElement"
+                                                        : "importedModule");
   aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
   aOptions->setIsRunOnce(true);
   aOptions->setNoScriptRval(true);
   if (aRequest->mHasSourceMapURL) {
     aOptions->setSourceMapURL(aRequest->mSourceMapURL.get());
   }
   if (aRequest->mOriginPrincipal) {
     nsIPrincipal* scriptPrin = nsContentUtils::ObjectPrincipal(aScopeChain);
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -408,24 +408,20 @@ nsresult txCompileObserver::startLoad(ns
       loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   channel->SetContentType(NS_LITERAL_CSTRING("text/xml"));
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
-    DebugOnly<nsresult> rv;
-    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
-                                       NS_LITERAL_CSTRING("*/*"), false);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
-
     nsCOMPtr<nsIURI> referrerURI;
     aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
     if (referrerURI) {
+      DebugOnly<nsresult> rv;
       rv = httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -174,8 +174,9 @@ load 1490704-1.html
 load 1501518.html
 load 1503986-1.html
 load 1505426-1.html
 load 1508811.html
 load 1508822.html
 load 1509099.html
 load 1496194.html
 load 1509123.html
+load texture-allocator-zero-region.html
new file mode 100644
--- /dev/null
+++ b/gfx/tests/crashtests/texture-allocator-zero-region.html
@@ -0,0 +1,9 @@
+<style>
+* {
+  column-width: 1px;
+  -webkit-filter: hue-rotate(1deg);
+  outline: 3px solid;
+}
+</style>
+<form style="overflow:hidden">
+<h3>
--- a/js/public/CompileOptions.h
+++ b/js/public/CompileOptions.h
@@ -503,16 +503,20 @@ class MOZ_STACK_CLASS JS_PUBLIC_API Comp
     introductionType = intro;
     introductionLineno = line;
     introductionScriptRoot = script;
     introductionOffset = offset;
     hasIntroductionInfo = true;
     return *this;
   }
 
+  // Set introduction information according to any currently executing script.
+  CompileOptions& setIntroductionInfoToCaller(JSContext* cx,
+                                              const char* introductionType);
+
   CompileOptions& maybeMakeStrictMode(bool strict) {
     strictOption = strictOption || strict;
     return *this;
   }
 
  private:
   void operator=(const CompileOptions& rhs) = delete;
 };
--- a/js/src/jit-test/tests/wasm/spec/address.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/address.wast.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: getBuildConfiguration()['arm']
+// skip due to bug 1517351
 
 // address.wast:3
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8a\x80\x80\x80\x00\x02\x60\x01\x7f\x01\x7f\x60\x01\x7f\x00\x03\x9f\x80\x80\x80\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x05\x83\x80\x80\x80\x00\x01\x00\x01\x07\xcd\x82\x80\x80\x00\x1e\x08\x38\x75\x5f\x67\x6f\x6f\x64\x31\x00\x00\x08\x38\x75\x5f\x67\x6f\x6f\x64\x32\x00\x01\x08\x38\x75\x5f\x67\x6f\x6f\x64\x33\x00\x02\x08\x38\x75\x5f\x67\x6f\x6f\x64\x34\x00\x03\x08\x38\x75\x5f\x67\x6f\x6f\x64\x35\x00\x04\x08\x38\x73\x5f\x67\x6f\x6f\x64\x31\x00\x05\x08\x38\x73\x5f\x67\x6f\x6f\x64\x32\x00\x06\x08\x38\x73\x5f\x67\x6f\x6f\x64\x33\x00\x07\x08\x38\x73\x5f\x67\x6f\x6f\x64\x34\x00\x08\x08\x38\x73\x5f\x67\x6f\x6f\x64\x35\x00\x09\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x31\x00\x0a\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x32\x00\x0b\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x33\x00\x0c\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x34\x00\x0d\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x35\x00\x0e\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x31\x00\x0f\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x32\x00\x10\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x33\x00\x11\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x34\x00\x12\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x35\x00\x13\x08\x33\x32\x5f\x67\x6f\x6f\x64\x31\x00\x14\x08\x33\x32\x5f\x67\x6f\x6f\x64\x32\x00\x15\x08\x33\x32\x5f\x67\x6f\x6f\x64\x33\x00\x16\x08\x33\x32\x5f\x67\x6f\x6f\x64\x34\x00\x17\x08\x33\x32\x5f\x67\x6f\x6f\x64\x35\x00\x18\x06\x38\x75\x5f\x62\x61\x64\x00\x19\x06\x38\x73\x5f\x62\x61\x64\x00\x1a\x07\x31\x36\x75\x5f\x62\x61\x64\x00\x1b\x07\x31\x36\x73\x5f\x62\x61\x64\x00\x1c\x06\x33\x32\x5f\x62\x61\x64\x00\x1d\x0a\x82\x83\x80\x80\x00\x1e\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x02\x19\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2d\x00\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2c\x00\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2f\x01\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2e\x01\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x28\x02\xff\xff\xff\xff\x0f\x1a\x0b\x0b\xa0\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x1a\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a");
 
 // address.wast:104
 assert_return(() => call($1, "8u_good1", [0]), 97);
 
 // address.wast:105
--- a/js/src/jit-test/tests/wasm/spec/call_indirect.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/call_indirect.wast.js
@@ -1,8 +1,10 @@
+// |jit-test| skip-if: getBuildConfiguration()['arm']
+// skip due to bug 1517351
 
 // call_indirect.wast:3
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\xfb\x80\x80\x80\x00\x18\x60\x00\x00\x60\x00\x01\x7f\x60\x00\x01\x7e\x60\x00\x01\x7d\x60\x00\x01\x7c\x60\x01\x7f\x01\x7f\x60\x01\x7e\x01\x7e\x60\x01\x7d\x01\x7d\x60\x01\x7c\x01\x7c\x60\x02\x7d\x7f\x01\x7f\x60\x02\x7f\x7e\x01\x7e\x60\x02\x7c\x7d\x01\x7d\x60\x02\x7e\x7c\x01\x7c\x60\x01\x7f\x01\x7f\x60\x01\x7e\x01\x7e\x60\x01\x7d\x01\x7d\x60\x01\x7c\x01\x7c\x60\x04\x7e\x7c\x7f\x7e\x01\x7f\x60\x01\x7e\x01\x7f\x60\x04\x7e\x7c\x7f\x7e\x00\x60\x01\x7e\x00\x60\x01\x7f\x01\x7e\x60\x01\x7f\x01\x7d\x60\x01\x7f\x01\x7c\x03\xca\x80\x80\x80\x00\x49\x01\x02\x03\x04\x05\x06\x07\x08\x0a\x0c\x09\x0b\x0d\x0e\x0f\x10\x00\x01\x02\x03\x04\x02\x01\x02\x03\x04\x01\x02\x03\x04\x0a\x15\x05\x16\x17\x06\x06\x05\x07\x08\x05\x07\x08\x05\x05\x00\x00\x00\x01\x01\x01\x01\x02\x01\x03\x01\x00\x00\x01\x01\x00\x03\x04\x04\x04\x01\x03\x01\x01\x01\x01\x01\x02\x04\x85\x80\x80\x80\x00\x01\x70\x01\x1d\x1d\x05\x83\x80\x80\x80\x00\x01\x00\x01\x06\x8d\x80\x80\x80\x00\x01\x7c\x01\x44\x00\x00\x00\x00\x00\x00\x24\x40\x0b\x07\xfc\x86\x80\x80\x00\x37\x08\x74\x79\x70\x65\x2d\x69\x33\x32\x00\x11\x08\x74\x79\x70\x65\x2d\x69\x36\x34\x00\x12\x08\x74\x79\x70\x65\x2d\x66\x33\x32\x00\x13\x08\x74\x79\x70\x65\x2d\x66\x36\x34\x00\x14\x0a\x74\x79\x70\x65\x2d\x69\x6e\x64\x65\x78\x00\x15\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x69\x33\x32\x00\x16\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x69\x36\x34\x00\x17\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x66\x33\x32\x00\x18\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x66\x36\x34\x00\x19\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x69\x33\x32\x00\x1a\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x69\x36\x34\x00\x1b\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x66\x33\x32\x00\x1c\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x66\x36\x34\x00\x1d\x08\x64\x69\x73\x70\x61\x74\x63\x68\x00\x1e\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x69\x36\x34\x00\x1f\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x69\x33\x32\x00\x20\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x66\x33\x32\x00\x21\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x66\x36\x34\x00\x22\x07\x66\x61\x63\x2d\x69\x36\x34\x00\x23\x07\x66\x69\x62\x2d\x69\x36\x34\x00\x24\x07\x66\x61\x63\x2d\x69\x33\x32\x00\x25\x07\x66\x61\x63\x2d\x66\x33\x32\x00\x26\x07\x66\x61\x63\x2d\x66\x36\x34\x00\x27\x07\x66\x69\x62\x2d\x69\x33\x32\x00\x28\x07\x66\x69\x62\x2d\x66\x33\x32\x00\x29\x07\x66\x69\x62\x2d\x66\x36\x34\x00\x2a\x04\x65\x76\x65\x6e\x00\x2b\x03\x6f\x64\x64\x00\x2c\x07\x72\x75\x6e\x61\x77\x61\x79\x00\x2d\x0e\x6d\x75\x74\x75\x61\x6c\x2d\x72\x75\x6e\x61\x77\x61\x79\x00\x2e\x0f\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x66\x69\x72\x73\x74\x00\x30\x0d\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x6d\x69\x64\x00\x31\x0e\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x6c\x61\x73\x74\x00\x32\x0f\x61\x73\x2d\x69\x66\x2d\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e\x00\x33\x0e\x61\x73\x2d\x62\x72\x5f\x69\x66\x2d\x66\x69\x72\x73\x74\x00\x34\x0d\x61\x73\x2d\x62\x72\x5f\x69\x66\x2d\x6c\x61\x73\x74\x00\x35\x11\x61\x73\x2d\x62\x72\x5f\x74\x61\x62\x6c\x65\x2d\x66\x69\x72\x73\x74\x00\x36\x10\x61\x73\x2d\x62\x72\x5f\x74\x61\x62\x6c\x65\x2d\x6c\x61\x73\x74\x00\x37\x0e\x61\x73\x2d\x73\x74\x6f\x72\x65\x2d\x66\x69\x72\x73\x74\x00\x38\x0d\x61\x73\x2d\x73\x74\x6f\x72\x65\x2d\x6c\x61\x73\x74\x00\x39\x14\x61\x73\x2d\x6d\x65\x6d\x6f\x72\x79\x2e\x67\x72\x6f\x77\x2d\x76\x61\x6c\x75\x65\x00\x3a\x0f\x61\x73\x2d\x72\x65\x74\x75\x72\x6e\x2d\x76\x61\x6c\x75\x65\x00\x3b\x0f\x61\x73\x2d\x64\x72\x6f\x70\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x3c\x0b\x61\x73\x2d\x62\x72\x2d\x76\x61\x6c\x75\x65\x00\x3d\x12\x61\x73\x2d\x6c\x6f\x63\x61\x6c\x2e\x73\x65\x74\x2d\x76\x61\x6c\x75\x65\x00\x3e\x12\x61\x73\x2d\x6c\x6f\x63\x61\x6c\x2e\x74\x65\x65\x2d\x76\x61\x6c\x75\x65\x00\x3f\x13\x61\x73\x2d\x67\x6c\x6f\x62\x61\x6c\x2e\x73\x65\x74\x2d\x76\x61\x6c\x75\x65\x00\x40\x0f\x61\x73\x2d\x6c\x6f\x61\x64\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x41\x10\x61\x73\x2d\x75\x6e\x61\x72\x79\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x42\x0e\x61\x73\x2d\x62\x69\x6e\x61\x72\x79\x2d\x6c\x65\x66\x74\x00\x43\x0f\x61\x73\x2d\x62\x69\x6e\x61\x72\x79\x2d\x72\x69\x67\x68\x74\x00\x44\x0f\x61\x73\x2d\x74\x65\x73\x74\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x45\x0f\x61\x73\x2d\x63\x6f\x6d\x70\x61\x72\x65\x2d\x6c\x65\x66\x74\x00\x46\x10\x61\x73\x2d\x63\x6f\x6d\x70\x61\x72\x65\x2d\x72\x69\x67\x68\x74\x00\x47\x12\x61\x73\x2d\x63\x6f\x6e\x76\x65\x72\x74\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x48\x09\xa3\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x1d\x00\x01\x02\x03\x04\x05\x06\x07\x0a\x08\x0b\x09\x23\x24\x2b\x2c\x2d\x2e\x2f\x0c\x0d\x0e\x0f\x25\x26\x27\x28\x29\x2a\x0a\xba\x8b\x80\x80\x00\x49\x85\x80\x80\x80\x00\x00\x41\xb2\x02\x0b\x85\x80\x80\x80\x00\x00\x42\xe4\x02\x0b\x87\x80\x80\x80\x00\x00\x43\x00\x20\x73\x45\x0b\x8b\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\xc8\xae\x40\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\xdd\x80\x80\x80\x00\x00\x41\x00\x11\x00\x00\x42\x00\x41\x00\x11\x14\x00\x42\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x41\x00\x42\x00\x41\x00\x11\x13\x00\x41\x00\x11\x00\x00\x41\x00\x11\x01\x00\x45\x1a\x41\x00\x11\x01\x00\x45\x1a\x42\x00\x41\x00\x11\x12\x00\x45\x1a\x42\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x41\x00\x42\x00\x41\x00\x11\x11\x00\x45\x1a\x42\x00\x41\x00\x11\x06\x00\x50\x1a\x0b\x87\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x01\x11\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x02\x11\x03\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x03\x11\x04\x00\x0b\x8a\x80\x80\x80\x00\x00\x42\xe4\x00\x41\x05\x11\x06\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x20\x41\x04\x11\x05\x00\x0b\x8a\x80\x80\x80\x00\x00\x42\xc0\x00\x41\x05\x11\x06\x00\x0b\x8c\x80\x80\x80\x00\x00\x43\xc3\xf5\xa8\x3f\x41\x06\x11\x07\x00\x0b\x90\x80\x80\x80\x00\x00\x44\x3d\x0a\xd7\xa3\x70\x3d\xfa\x3f\x41\x07\x11\x08\x00\x0b\x8e\x80\x80\x80\x00\x00\x43\x66\x66\x00\x42\x41\x20\x41\x08\x11\x09\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x20\x42\xc0\x00\x41\x09\x11\x0a\x00\x0b\x95\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\x50\x40\x43\x00\x00\x00\x42\x41\x0a\x11\x0b\x00\x0b\x93\x80\x80\x80\x00\x00\x42\xc0\x00\x44\x66\x66\x66\x66\x66\x06\x50\x40\x41\x0b\x11\x0c\x00\x0b\x89\x80\x80\x80\x00\x00\x20\x01\x20\x00\x11\x06\x00\x0b\x89\x80\x80\x80\x00\x00\x42\x09\x20\x00\x11\x0e\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x09\x20\x00\x11\x0d\x00\x0b\x8c\x80\x80\x80\x00\x00\x43\x00\x00\x10\x41\x20\x00\x11\x0f\x00\x0b\x90\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\x22\x40\x20\x00\x11\x10\x00\x0b\x98\x80\x80\x80\x00\x00\x20\x00\x50\x04\x7e\x42\x01\x05\x20\x00\x20\x00\x42\x01\x7d\x41\x0c\x11\x06\x00\x7e\x0b\x0b\xa2\x80\x80\x80\x00\x00\x20\x00\x42\x01\x58\x04\x7e\x42\x01\x05\x20\x00\x42\x02\x7d\x41\x0d\x11\x06\x00\x20\x00\x42\x01\x7d\x41\x0d\x11\x06\x00\x7c\x0b\x0b\x98\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\x01\x05\x20\x00\x20\x00\x41\x01\x6b\x41\x17\x11\x05\x00\x6c\x0b\x0b\xa3\x80\x80\x80\x00\x00\x20\x00\x43\x00\x00\x00\x00\x5b\x04\x7d\x43\x00\x00\x80\x3f\x05\x20\x00\x20\x00\x43\x00\x00\x80\x3f\x93\x41\x18\x11\x07\x00\x94\x0b\x0b\xaf\x80\x80\x80\x00\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x61\x04\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x05\x20\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\xa1\x41\x19\x11\x08\x00\xa2\x0b\x0b\xa2\x80\x80\x80\x00\x00\x20\x00\x41\x01\x4d\x04\x7f\x41\x01\x05\x20\x00\x41\x02\x6b\x41\x1a\x11\x05\x00\x20\x00\x41\x01\x6b\x41\x1a\x11\x05\x00\x6a\x0b\x0b\xae\x80\x80\x80\x00\x00\x20\x00\x43\x00\x00\x80\x3f\x5f\x04\x7d\x43\x00\x00\x80\x3f\x05\x20\x00\x43\x00\x00\x00\x40\x93\x41\x1b\x11\x07\x00\x20\x00\x43\x00\x00\x80\x3f\x93\x41\x1b\x11\x07\x00\x92\x0b\x0b\xbe\x80\x80\x80\x00\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x65\x04\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x05\x20\x00\x44\x00\x00\x00\x00\x00\x00\x00\x40\xa1\x41\x1c\x11\x08\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\xa1\x41\x1c\x11\x08\x00\xa0\x0b\x0b\x95\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\x2c\x05\x20\x00\x41\x01\x6b\x41\x0f\x11\x05\x00\x0b\x0b\x96\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\xe3\x00\x05\x20\x00\x41\x01\x6b\x41\x0e\x11\x05\x00\x0b\x0b\x87\x80\x80\x80\x00\x00\x41\x10\x11\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x12\x11\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x11\x11\x00\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x41\x02\x41\x03\x1b\x0b\x8c\x80\x80\x80\x00\x00\x41\x02\x41\x00\x11\x01\x00\x41\x03\x1b\x0b\x8c\x80\x80\x80\x00\x00\x41\x02\x41\x03\x41\x00\x11\x01\x00\x1b\x0b\x8f\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x04\x7f\x41\x01\x05\x41\x02\x0b\x0b\x8e\x80\x80\x80\x00\x00\x02\x7e\x41\x01\x11\x02\x00\x41\x02\x0d\x00\x0b\x0b\x8e\x80\x80\x80\x00\x00\x02\x7f\x41\x02\x41\x00\x11\x01\x00\x0d\x00\x0b\x0b\x90\x80\x80\x80\x00\x00\x02\x7d\x41\x02\x11\x03\x00\x41\x02\x0e\x01\x00\x00\x0b\x0b\x90\x80\x80\x80\x00\x00\x02\x7f\x41\x02\x41\x00\x11\x01\x00\x0e\x01\x00\x00\x0b\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x41\x01\x36\x02\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x0a\x41\x03\x11\x04\x00\x39\x03\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x40\x00\x0b\x8a\x80\x80\x80\x00\x00\x41\x01\x41\x04\x11\x05\x00\x0f\x0b\x8a\x80\x80\x80\x00\x00\x42\x01\x41\x05\x11\x06\x00\x1a\x0b\x91\x80\x80\x80\x00\x00\x02\x7d\x43\x00\x00\x80\x3f\x41\x06\x11\x07\x00\x0c\x00\x0b\x0b\x96\x80\x80\x80\x00\x01\x01\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x21\x00\x20\x00\x0b\x94\x80\x80\x80\x00\x01\x01\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x22\x00\x0b\x94\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x24\x00\x23\x00\x0b\x8a\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x28\x02\x00\x0b\x90\x80\x80\x80\x00\x00\x02\x7d\x43\x00\x00\x00\x00\x41\x06\x11\x07\x00\x91\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x41\x0a\x6a\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x0a\x41\x01\x41\x04\x11\x05\x00\x6b\x0b\x0b\x8d\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x45\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x41\x0a\x4d\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x0a\x41\x01\x41\x04\x11\x05\x00\x47\x0b\x0b\x8d\x80\x80\x80\x00\x00\x02\x7e\x41\x01\x41\x04\x11\x05\x00\xac\x0b\x0b");
 
 // call_indirect.wast:447
 assert_return(() => call($1, "type-i32", []), 306);
 
 // call_indirect.wast:448
--- a/js/src/jit/arm64/CodeGenerator-arm64.cpp
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -971,17 +971,17 @@ void CodeGenerator::visitRound(LRound* l
     // If the output potentially saturated, take a bailout.
     bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
 
     // If the result of the rounding was non-zero, return the output.
     // In the case of zero, the input may have been NaN or -0, which must bail.
     masm.branch32(Assembler::NotEqual, output, Imm32(0), &done);
     {
       // If input is NaN, comparisons set the C and V bits of the NZCV flags.
-      masm.Fcmp(ARMFPRegister(input), 0.0);
+      masm.Fcmp(input64, 0.0);
       bailoutIf(Assembler::Overflow, lir->snapshot());
 
       // Move all 64 bits of the input into a scratch register to check for -0.
       vixl::UseScratchRegisterScope temps(&masm.asVIXL());
       const ARMRegister scratchGPR64 = temps.AcquireX();
       masm.Fmov(scratchGPR64, input64);
       masm.Cmp(scratchGPR64, vixl::Operand(uint64_t(0x8000000000000000)));
       bailoutIf(Assembler::Equal, lir->snapshot());
@@ -1016,17 +1016,92 @@ void CodeGenerator::visitRound(LRound* l
 
     // If output is zero, then the actual result is -0. Bail.
     bailoutTest32(Assembler::Zero, output, output, lir->snapshot());
   }
 
   masm.bind(&done);
 }
 
-void CodeGenerator::visitRoundF(LRoundF* lir) { MOZ_CRASH("visitRoundF"); }
+void CodeGenerator::visitRoundF(LRoundF* lir) {
+  const FloatRegister input = ToFloatRegister(lir->input());
+  const ARMFPRegister input32(input, 32);
+  const FloatRegister temp = ToFloatRegister(lir->temp());
+  const FloatRegister scratch = ScratchFloat32Reg;
+  const Register output = ToRegister(lir->output());
+
+  Label negative, done;
+
+  // Branch to a slow path if input < 0.0 due to complicated rounding rules.
+  // Note that Fcmp with NaN unsets the negative flag.
+  masm.Fcmp(input32, 0.0);
+  masm.B(&negative, Assembler::Condition::lo);
+
+  // Handle the simple case of a positive input, and also -0 and NaN.
+  // Rounding proceeds with consideration of the fractional part of the input:
+  // 1. If > 0.5, round to integer with higher absolute value (so, up).
+  // 2. If < 0.5, round to integer with lower absolute value (so, down).
+  // 3. If = 0.5, round to +Infinity (so, up).
+  {
+    // Convert to signed 32-bit integer, rounding halfway cases away from zero.
+    // In the case of overflow, the output is saturated.
+    // In the case of NaN and -0, the output is zero.
+    masm.Fcvtas(ARMRegister(output, 32), input32);
+    // If the output potentially saturated, take a bailout.
+    bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
+
+    // If the result of the rounding was non-zero, return the output.
+    // In the case of zero, the input may have been NaN or -0, which must bail.
+    masm.branch32(Assembler::NotEqual, output, Imm32(0), &done);
+    {
+      // If input is NaN, comparisons set the C and V bits of the NZCV flags.
+      masm.Fcmp(input32, 0.0f);
+      bailoutIf(Assembler::Overflow, lir->snapshot());
+
+      // Move all 64 bits of the input into a scratch register to check for -0.
+      vixl::UseScratchRegisterScope temps(&masm.asVIXL());
+      const ARMRegister scratchGPR32 = temps.AcquireW();
+      masm.Fmov(scratchGPR32, input32);
+      masm.Cmp(scratchGPR32, vixl::Operand(uint32_t(0x80000000)));
+      bailoutIf(Assembler::Equal, lir->snapshot());
+    }
+
+    masm.jump(&done);
+  }
+
+  // Handle the complicated case of a negative input.
+  // Rounding proceeds with consideration of the fractional part of the input:
+  // 1. If > 0.5, round to integer with higher absolute value (so, down).
+  // 2. If < 0.5, round to integer with lower absolute value (so, up).
+  // 3. If = 0.5, round to +Infinity (so, up).
+  masm.bind(&negative);
+  {
+    // Inputs in [-0.5, 0) need 0.5 added; other negative inputs need
+    // the biggest double less than 0.5.
+    Label join;
+    masm.loadConstantFloat32(GetBiggestNumberLessThan(0.5f), temp);
+    masm.loadConstantFloat32(-0.5f, scratch);
+    masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &join);
+    masm.loadConstantFloat32(0.5f, temp);
+    masm.bind(&join);
+
+    masm.addFloat32(input, temp);
+    // Round all values toward -Infinity.
+    // In the case of overflow, the output is saturated.
+    // NaN and -0 are already handled by the "positive number" path above.
+    masm.Fcvtms(ARMRegister(output, 32), temp);
+    // If the output potentially saturated, take a bailout.
+    bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
+
+    // If output is zero, then the actual result is -0. Bail.
+    bailoutTest32(Assembler::Zero, output, output, lir->snapshot());
+  }
+
+  masm.bind(&done);
+}
 
 void CodeGenerator::visitTrunc(LTrunc* lir) { MOZ_CRASH("visitTrunc"); }
 
 void CodeGenerator::visitTruncF(LTruncF* lir) { MOZ_CRASH("visitTruncF"); }
 
 void CodeGenerator::visitClzI(LClzI* lir) {
   ARMRegister input = toWRegister(lir->input());
   ARMRegister output = toWRegister(lir->output());
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3542,16 +3542,33 @@ JS::CompileOptions::CompileOptions(JSCon
     asmJSOption = AsmJSOption::DisabledByDebugger;
   } else {
     asmJSOption = AsmJSOption::Enabled;
   }
   throwOnAsmJSValidationFailureOption =
       cx->options().throwOnAsmJSValidationFailure();
 }
 
+CompileOptions& CompileOptions::setIntroductionInfoToCaller(
+    JSContext* cx, const char* introductionType) {
+  RootedScript maybeScript(cx);
+  const char* filename;
+  unsigned lineno;
+  uint32_t pcOffset;
+  bool mutedErrors;
+  DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno,
+                                       &pcOffset, &mutedErrors);
+  if (filename) {
+    return setIntroductionInfo(filename, introductionType, lineno,
+                               maybeScript, pcOffset);
+  } else {
+    return setIntroductionType(introductionType);
+  }
+}
+
 #if defined(JS_BUILD_BINAST)
 
 JSScript* JS::DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
                            const uint8_t* buf, size_t length) {
   MOZ_ASSERT(!cx->zone()->isAtomsZone());
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
--- a/layout/base/MobileViewportManager.cpp
+++ b/layout/base/MobileViewportManager.cpp
@@ -92,16 +92,20 @@ void MobileViewportManager::SetRestoreRe
   mRestoreDisplaySize = Some(restoreDisplaySize);
 }
 
 void MobileViewportManager::SetRestoreResolution(float aResolution) {
   mRestoreResolution = Some(aResolution);
 }
 
 float MobileViewportManager::ComputeIntrinsicResolution() const {
+  if (!mDocument || !mPresShell) {
+    return 1.f;
+  }
+
   ScreenIntSize displaySize = ViewAs<ScreenPixel>(
       mDisplaySize, PixelCastJustification::LayoutDeviceIsScreenForBounds);
   CSSToScreenScale intrinsicScale =
       ComputeIntrinsicScale(mDocument->GetViewportInfo(displaySize),
                             displaySize, mMobileViewportSize);
   CSSToLayoutDeviceScale cssToDev =
       mPresShell->GetPresContext()->CSSToDevPixelScale();
   return (intrinsicScale / cssToDev).scale;
@@ -119,16 +123,21 @@ mozilla::CSSToScreenScale MobileViewport
 
 void MobileViewportManager::RequestReflow() {
   MVM_LOG("%p: got a reflow request\n", this);
   RefreshViewportSize(false);
 }
 
 void MobileViewportManager::ResolutionUpdated() {
   MVM_LOG("%p: resolution updated\n", this);
+
+  if (!mPresShell) {
+    return;
+  }
+
   if (!mPainted) {
     // Save the value, so our default zoom calculation
     // can take it into account later on.
     SetRestoreResolution(mPresShell->GetResolution());
   }
   RefreshVisualViewportSize();
 }
 
@@ -154,16 +163,20 @@ MobileViewportManager::HandleEvent(dom::
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileViewportManager::Observe(nsISupports* aSubject, const char* aTopic,
                                const char16_t* aData) {
+  if (!mDocument) {
+    return NS_OK;
+  }
+
   if (SameCOMIdentity(aSubject, ToSupports(mDocument)) &&
       BEFORE_FIRST_PAINT.EqualsASCII(aTopic)) {
     MVM_LOG("%p: got a before-first-paint event\n", this);
     if (!mPainted) {
       // before-first-paint message arrived before load event
       SetInitialViewport();
     }
   }
@@ -217,16 +230,20 @@ static LayoutDeviceToLayerScale ZoomToRe
              aZoom, PixelCastJustification::ScreenIsParentLayerForRoot) /
          aCssToDev * ParentLayerToLayerScale(1);
 }
 
 void MobileViewportManager::UpdateResolution(
     const nsViewportInfo& aViewportInfo, const ScreenIntSize& aDisplaySize,
     const CSSSize& aViewportOrContentSize,
     const Maybe<float>& aDisplayWidthChangeRatio, UpdateType aType) {
+  if (!mPresShell || !mDocument) {
+    return;
+  }
+
   CSSToLayoutDeviceScale cssToDev =
       mPresShell->GetPresContext()->CSSToDevPixelScale();
   LayoutDeviceToLayerScale res(mPresShell->GetResolution());
   CSSToScreenScale zoom = ResolutionToZoom(res, cssToDev);
   Maybe<CSSToScreenScale> newZoom;
 
   ScreenIntSize compositionSize = GetCompositionSize(aDisplaySize);
   CSSToScreenScale intrinsicScale = ComputeIntrinsicScale(
@@ -339,16 +356,20 @@ void MobileViewportManager::UpdateResolu
   // and needs to be updated if either might have changed.
   if (newZoom || aType == UpdateType::ViewportSize) {
     UpdateVisualViewportSize(aDisplaySize, newZoom ? *newZoom : zoom);
   }
 }
 
 ScreenIntSize MobileViewportManager::GetCompositionSize(
     const ScreenIntSize& aDisplaySize) const {
+  if (!mPresShell) {
+    return ScreenIntSize();
+  }
+
   ScreenIntSize compositionSize(aDisplaySize);
   ScreenMargin scrollbars =
       LayoutDeviceMargin::FromAppUnits(
           nsLayoutUtils::ScrollbarAreaToExcludeFromCompositionBoundsFor(
               mPresShell->GetRootScrollFrame()),
           mPresShell->GetPresContext()->AppUnitsPerDevPixel())
       // Scrollbars are not subject to resolution scaling, so LD pixels =
       // Screen pixels for them.
@@ -357,24 +378,32 @@ ScreenIntSize MobileViewportManager::Get
   compositionSize.width -= scrollbars.LeftRight();
   compositionSize.height -= scrollbars.TopBottom();
 
   return compositionSize;
 }
 
 void MobileViewportManager::UpdateVisualViewportSize(
     const ScreenIntSize& aDisplaySize, const CSSToScreenScale& aZoom) {
+  if (!mPresShell) {
+    return;
+  }
+
   ScreenSize compositionSize = ScreenSize(GetCompositionSize(aDisplaySize));
 
   CSSSize compSize = compositionSize / aZoom;
   MVM_LOG("%p: Setting VVPS %s\n", this, Stringify(compSize).c_str());
   nsLayoutUtils::SetVisualViewportSize(mPresShell, compSize);
 }
 
 void MobileViewportManager::UpdateDisplayPortMargins() {
+  if (!mPresShell) {
+    return;
+  }
+
   if (nsIFrame* root = mPresShell->GetRootScrollFrame()) {
     bool hasDisplayPort = nsLayoutUtils::HasDisplayPort(root->GetContent());
     bool hasResolution = mPresShell->GetResolution() != 1.0f;
     if (!hasDisplayPort && !hasResolution) {
       // We only want to update the displayport if there is one already, or
       // add one if there's a resolution on the document (see bug 1225508
       // comment 1).
       return;
@@ -392,16 +421,20 @@ void MobileViewportManager::UpdateDispla
         scrollable, nsLayoutUtils::RepaintMode::DoNotRepaint);
   }
 }
 
 void MobileViewportManager::RefreshVisualViewportSize() {
   // This function is a subset of RefreshViewportSize, and only updates the
   // visual viewport size.
 
+  if (!mPresShell) {
+    return;
+  }
+
   if (!gfxPrefs::APZAllowZooming()) {
     return;
   }
 
   ScreenIntSize displaySize = ViewAs<ScreenPixel>(
       mDisplaySize, PixelCastJustification::LayoutDeviceIsScreenForBounds);
 
   CSSToLayoutDeviceScale cssToDev =
@@ -424,16 +457,20 @@ void MobileViewportManager::RefreshViewp
   // separately for each trigger that changes. For instance it should never get
   // called such that both the full zoom and the meta-viewport tag have changed;
   // instead it would get called twice - once after each trigger changes. This
   // assumption is what allows the aForceAdjustResolution parameter to work as
   // intended; if this assumption is violated then we will need to add extra
   // complicated logic in UpdateResolution to ensure we only do the resolution
   // update in the right scenarios.
 
+  if (!mPresShell || !mDocument) {
+    return;
+  }
+
   Maybe<float> displayWidthChangeRatio;
   LayoutDeviceIntSize newDisplaySize;
   if (nsLayoutUtils::GetContentViewerSize(mPresShell->GetPresContext(),
                                           newDisplaySize)) {
     // See the comment in UpdateResolution for why we're doing this.
     if (mDisplaySize.width > 0) {
       if (aForceAdjustResolution ||
           mDisplaySize.width != newDisplaySize.width) {
@@ -481,32 +518,38 @@ void MobileViewportManager::RefreshViewp
     UpdateDisplayPortMargins();
   }
 
   CSSSize oldSize = mMobileViewportSize;
 
   // Update internal state.
   mMobileViewportSize = viewport;
 
+  RefPtr<MobileViewportManager> strongThis(this);
+
   // Kick off a reflow.
   mPresShell->ResizeReflowIgnoreOverride(
       nsPresContext::CSSPixelsToAppUnits(viewport.width),
       nsPresContext::CSSPixelsToAppUnits(viewport.height),
       nsPresContext::CSSPixelsToAppUnits(oldSize.width),
       nsPresContext::CSSPixelsToAppUnits(oldSize.height));
 
   // We are going to fit the content to the display width if the initial-scale
   // is not specied and if the content is still wider than the display width.
   ShrinkToDisplaySizeIfNeeded(viewportInfo, displaySize);
 
   mIsFirstPaint = false;
 }
 
 void MobileViewportManager::ShrinkToDisplaySizeIfNeeded(
     nsViewportInfo& aViewportInfo, const ScreenIntSize& aDisplaySize) {
+  if (!mPresShell) {
+    return;
+  }
+
   if (!gfxPrefs::APZAllowZooming()) {
     // If the APZ is disabled, we don't scale down wider contents to fit them
     // into device screen because users won't be able to zoom out the tiny
     // contents.
     return;
   }
 
   nsIScrollableFrame* rootScrollableFrame =
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -121,24 +121,21 @@ class nsIDocumentLoaderFactory;
 
 static void Shutdown();
 
 #include "nsGeolocation.h"
 #include "nsDeviceSensors.h"
 #include "mozilla/dom/nsContentSecurityManager.h"
 #include "mozilla/dom/nsCSPService.h"
 #include "mozilla/dom/nsCSPContext.h"
-#include "nsIPowerManagerService.h"
 #include "nsIMediaManager.h"
 #include "mozilla/dom/nsMixedContentBlocker.h"
 
 #include "mozilla/net/WebSocketEventService.h"
 
-#include "mozilla/dom/power/PowerManagerService.h"
-
 #include "nsIPresentationService.h"
 
 #include "MediaManager.h"
 
 #include "GMPService.h"
 
 #include "mozilla/dom/PresentationDeviceManager.h"
 #include "mozilla/dom/PresentationTCPSessionTransport.h"
@@ -148,17 +145,16 @@ static void Shutdown();
 #include "nsControllerCommandTable.h"
 
 #include "mozilla/TextInputProcessor.h"
 #include "mozilla/ScriptableContentIterator.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::net;
-using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManagerService;
 using mozilla::gmp::GeckoMediaPluginService;
 
 #define NS_HAPTICFEEDBACK_CID                        \
   {                                                  \
     0x1f15dbc8, 0xbfaa, 0x45de, {                    \
       0x8a, 0x46, 0x08, 0xe2, 0xe2, 0x63, 0x26, 0xb0 \
     }                                                \
@@ -204,18 +200,16 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors)
 
 #if defined(ANDROID)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
-                                         PowerManagerService::GetInstance)
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMediaManagerService,
                                          MediaManager::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationDeviceManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TextInputProcessor)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPresentationService,
                                          NS_CreatePresentationService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationTCPSessionTransport)
@@ -235,30 +229,16 @@ void nsLayoutModuleInitialize() {
   }
 
   static_assert(sizeof(uintptr_t) == sizeof(void*),
                 "Eeek! You'll need to adjust the size of uintptr_t to the "
                 "size of a pointer on your platform.");
 
   gInitialized = true;
 
-  if (XRE_GetProcessType() == GeckoProcessType_VR) {
-    // VR process doesn't need the layout module.
-    return;
-  }
-
-  if (XRE_GetProcessType() == GeckoProcessType_GPU ||
-      XRE_GetProcessType() == GeckoProcessType_RDD) {
-    // We mark the layout module as being available in the GPU and RDD
-    // process so that XPCOM's component manager initializes the power
-    // manager service, which is needed for nsAppShell. However, we
-    // don't actually need anything in the layout module itself.
-    return;
-  }
-
   if (NS_FAILED(xpcModuleCtor())) {
     MOZ_CRASH("xpcModuleCtor failed");
   }
 
   if (NS_FAILED(nsLayoutStatics::Initialize())) {
     Shutdown();
     MOZ_CRASH("nsLayoutStatics::Initialize failed");
   }
@@ -492,17 +472,16 @@ NS_DEFINE_NAMED_CID(NS_EXPANDEDPRINCIPAL
 NS_DEFINE_NAMED_CID(NS_SYSTEMPRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_NULLPRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(THIRDPARTYUTIL_CID);
 NS_DEFINE_NAMED_CID(NS_STRUCTUREDCLONECONTAINER_CID);
 NS_DEFINE_NAMED_CID(NS_DEVICE_SENSORS_CID);
 #if defined(ANDROID)
 NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID);
 #endif
-NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MEDIAMANAGERSERVICE_CID);
 #ifdef MOZ_WEBSPEECH_TEST_BACKEND
 NS_DEFINE_NAMED_CID(NS_FAKE_SPEECH_RECOGNITION_SERVICE_CID);
 #endif
 #ifdef MOZ_WEBSPEECH
 NS_DEFINE_NAMED_CID(NS_SYNTHVOICEREGISTRY_CID);
 #endif
@@ -591,17 +570,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, SystemPrincipalConstructor },
   { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor },
   { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor },
 #if defined(ANDROID)
   { &kNS_HAPTICFEEDBACK_CID, false, nullptr, nsHapticFeedbackConstructor },
 #endif
   { &kTHIRDPARTYUTIL_CID, false, nullptr, ThirdPartyUtilConstructor },
   { &kNS_STRUCTUREDCLONECONTAINER_CID, false, nullptr, nsStructuredCloneContainerConstructor },
-  { &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor, Module::ALLOW_IN_GPU_PROCESS },
   { &kOSFILECONSTANTSSERVICE_CID, true, nullptr, OSFileConstantsServiceConstructor },
   { &kGECKO_MEDIA_PLUGIN_SERVICE_CID, true, nullptr, GeckoMediaPluginServiceConstructor },
   { &kNS_MEDIAMANAGERSERVICE_CID, false, nullptr, nsIMediaManagerServiceConstructor },
 #ifdef ACCESSIBILITY
   { &kNS_ACCESSIBILITY_SERVICE_CID, false, nullptr, CreateA11yService },
 #endif
   { &kPRESENTATION_SERVICE_CID, false, nullptr, nsIPresentationServiceConstructor },
   { &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
@@ -664,17 +642,16 @@ static const mozilla::Module::ContractID
   { NS_SYSTEMPRINCIPAL_CONTRACTID, &kNS_SYSTEMPRINCIPAL_CID },
   { NS_NULLPRINCIPAL_CONTRACTID, &kNS_NULLPRINCIPAL_CID },
   { NS_DEVICE_SENSORS_CONTRACTID, &kNS_DEVICE_SENSORS_CID },
 #if defined(ANDROID)
   { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID },
 #endif
   { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
   { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
-  { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID, Module::ALLOW_IN_GPU_PROCESS },
   { OSFILECONSTANTSSERVICE_CONTRACTID, &kOSFILECONSTANTSSERVICE_CID },
   { MEDIAMANAGERSERVICE_CONTRACTID, &kNS_MEDIAMANAGERSERVICE_CID },
 #ifdef ACCESSIBILITY
   { "@mozilla.org/accessibilityService;1", &kNS_ACCESSIBILITY_SERVICE_CID },
 #endif
   { "@mozilla.org/gecko-media-plugin-service;1",  &kGECKO_MEDIA_PLUGIN_SERVICE_CID },
   { PRESENTATION_SERVICE_CONTRACTID, &kPRESENTATION_SERVICE_CID },
   { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
@@ -706,22 +683,16 @@ static const mozilla::Module::CategoryEn
 
 static nsresult Initialize() {
   // nsLayoutModuleInitialize should be called first.
   MOZ_RELEASE_ASSERT(gInitialized);
   return NS_OK;
 }
 
 static void LayoutModuleDtor() {
-  if (XRE_GetProcessType() == GeckoProcessType_GPU ||
-      XRE_GetProcessType() == GeckoProcessType_VR ||
-      XRE_GetProcessType() == GeckoProcessType_RDD) {
-    return;
-  }
-
   Shutdown();
   nsContentUtils::XPCOMShutdown();
 
   // Layout depends heavily on gfx and imagelib, so we want to make sure that
   // these modules are shut down after all the layout cleanup runs.
   mozilla::image::ShutdownModule();
   gfxPlatform::Shutdown();
   gfx::gfxVars::Shutdown();
@@ -731,12 +702,11 @@ static void LayoutModuleDtor() {
 }
 
 static const mozilla::Module kLayoutModule = {mozilla::Module::kVersion,
                                               kLayoutCIDs,
                                               kLayoutContracts,
                                               kLayoutCategories,
                                               nullptr,
                                               Initialize,
-                                              LayoutModuleDtor,
-                                              Module::ALLOW_IN_GPU_PROCESS};
+                                              LayoutModuleDtor};
 
 NSMODULE_DEFN(nsLayoutModule) = &kLayoutModule;
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1439,22 +1439,16 @@ nsresult Loader::LoadSheet(SheetLoadData
     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
     if (cos) {
       cos->AddClassFlags(nsIClassOfService::Leader);
     }
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
-    // Send a minimal Accept header for text/css
-    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
-                                       NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
-                                       false);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
     if (referrerURI) {
       rv = httpChannel->SetReferrerWithPolicy(
           referrerURI, aLoadData->mSheet->GetReferrerPolicy());
       Unused << NS_WARN_IF(NS_FAILED(rv));
     }
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel =
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1734,19 +1734,16 @@ pref("network.http.max-persistent-connec
 // new connection, once the limit on the number of persistent connections per
 // host has been reached.  however, a new connection will not be created if
 // max-connections or max-connections-per-server has also been reached.
 pref("network.http.request.max-start-delay", 10);
 
 // If a connection is reset, we will retry it max-attempts times.
 pref("network.http.request.max-attempts", 10);
 
-// Headers
-pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
-
 // Prefs allowing granular control of referers
 // 0=don't send any, 1=send only on clicks, 2=send on image requests as well
 pref("network.http.sendRefererHeader",      2);
 // Set the default Referrer Policy; to be used unless overriden by the site
 // 0=no-referrer, 1=same-origin, 2=strict-origin-when-cross-origin,
 // 3=no-referrer-when-downgrade
 pref("network.http.referer.defaultPolicy", 3);
 // Set the Private Browsing Default Referrer Policy;
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -677,18 +677,24 @@ class WellKnownChecker {
   ~WellKnownChecker() { LOG(("WellKnownChecker dtor %p\n", this)); }
 
  private:
   nsresult MakeChannel(nsHttpChannel *chan, TransactionObserver *obs,
                        nsHttpConnectionInfo *ci, nsIURI *uri, uint32_t caps,
                        nsILoadInfo *loadInfo) {
     uint64_t channelId;
     nsLoadFlags flags;
+
+    nsContentPolicyType contentPolicyType =
+        loadInfo ? loadInfo->GetExternalContentPolicyType()
+                 : nsIContentPolicy::TYPE_OTHER;
+
     if (NS_FAILED(gHttpHandler->NewChannelId(channelId)) ||
-        NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId)) ||
+        NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId,
+                             contentPolicyType)) ||
         NS_FAILED(chan->SetAllowAltSvc(false)) ||
         NS_FAILED(chan->SetRedirectMode(
             nsIHttpChannelInternal::REDIRECT_MODE_ERROR)) ||
         NS_FAILED(chan->SetLoadInfo(loadInfo)) ||
         NS_FAILED(chan->GetLoadFlags(&flags))) {
       return NS_ERROR_FAILURE;
     }
     flags |= HttpBaseChannel::LOAD_BYPASS_CACHE;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -324,17 +324,18 @@ void HttpBaseChannel::SetFlashPluginStat
     nsIHttpChannel::FlashPluginState aState) {
   LOG(("HttpBaseChannel::SetFlashPluginState %p", this));
   mFlashPluginState = aState;
 }
 
 nsresult HttpBaseChannel::Init(nsIURI* aURI, uint32_t aCaps,
                                nsProxyInfo* aProxyInfo,
                                uint32_t aProxyResolveFlags, nsIURI* aProxyURI,
-                               uint64_t aChannelId) {
+                               uint64_t aChannelId,
+                               nsContentPolicyType aContentPolicyType) {
   LOG1(("HttpBaseChannel::Init [this=%p]\n", this));
 
   MOZ_ASSERT(aURI, "null uri");
 
   mURI = aURI;
   mOriginalURI = aURI;
   mDocumentURI = nullptr;
   mCaps = aCaps;
@@ -371,17 +372,18 @@ nsresult HttpBaseChannel::Init(nsIURI* a
   // Set request headers
   nsAutoCString hostLine;
   rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
   if (NS_FAILED(rv)) return rv;
 
   rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
   if (NS_FAILED(rv)) return rv;
 
-  rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS);
+  rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS,
+                                               aContentPolicyType);
   if (NS_FAILED(rv)) return rv;
 
   nsAutoCString type;
   if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) &&
       !type.EqualsLiteral("unknown"))
     mProxyInfo = aProxyInfo;
 
   return rv;
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -123,17 +123,18 @@ class HttpBaseChannel : public nsHashPro
 
   NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_BASE_CHANNEL_IID)
 
   HttpBaseChannel();
 
   virtual MOZ_MUST_USE nsresult Init(nsIURI *aURI, uint32_t aCaps,
                                      nsProxyInfo *aProxyInfo,
                                      uint32_t aProxyResolveFlags,
-                                     nsIURI *aProxyURI, uint64_t aChannelId);
+                                     nsIURI *aProxyURI, uint64_t aChannelId,
+                                     nsContentPolicyType aContentPolicyType);
 
   // nsIRequest
   NS_IMETHOD GetName(nsACString &aName) override;
   NS_IMETHOD IsPending(bool *aIsPending) override;
   NS_IMETHOD GetStatus(nsresult *aStatus) override;
   NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup) override;
   NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup) override;
   NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags) override;
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -231,28 +231,33 @@ nsresult InterceptedHttpChannel::Redirec
   // channel.  We need to hold a reference to the callbacks on the stack
   // as well, though, so we can call them if a failure occurs.
   nsCOMPtr<nsIInterceptedBodyCallback> bodyCallback = mBodyCallback.forget();
 
   RefPtr<InterceptedHttpChannel> newChannel = CreateForSynthesis(
       mResponseHead, mBodyReader, bodyCallback, mChannelCreationTime,
       mChannelCreationTimestamp, mAsyncOpenTime);
 
-  rv = newChannel->Init(aResponseURI, mCaps,
-                        static_cast<nsProxyInfo*>(mProxyInfo.get()),
-                        mProxyResolveFlags, mProxyURI, mChannelId);
-
   // If the response has been redirected, propagate all the URLs to content.
   // Thus, the exact value of the redirect flag does not matter as long as it's
   // not REDIRECT_INTERNAL.
   uint32_t flags = aResponseRedirected ? nsIChannelEventSink::REDIRECT_TEMPORARY
                                        : nsIChannelEventSink::REDIRECT_INTERNAL;
 
   nsCOMPtr<nsILoadInfo> redirectLoadInfo =
       CloneLoadInfoForRedirect(aResponseURI, flags);
+
+  nsContentPolicyType contentPolicyType =
+      redirectLoadInfo ? redirectLoadInfo->GetExternalContentPolicyType()
+                       : nsIContentPolicy::TYPE_OTHER;
+
+  rv = newChannel->Init(
+      aResponseURI, mCaps, static_cast<nsProxyInfo*>(mProxyInfo.get()),
+      mProxyResolveFlags, mProxyURI, mChannelId, contentPolicyType);
+
   newChannel->SetLoadInfo(redirectLoadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Normally we don't propagate the LoadInfo's service worker tainting
   // synthesis flag on redirect.  A real redirect normally will want to allow
   // normal tainting to proceed from its starting taint.  For this particular
   // redirect, though, we are performing a redirect to communicate the URL of
   // the service worker synthetic response itself.  This redirect still
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -371,19 +371,20 @@ void nsHttpChannel::ReleaseMainThreadOnl
   arrayToRelease.AppendElement(mRedirectChannel.forget());
   arrayToRelease.AppendElement(mPreflightChannel.forget());
 
   NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease)));
 }
 
 nsresult nsHttpChannel::Init(nsIURI *uri, uint32_t caps, nsProxyInfo *proxyInfo,
                              uint32_t proxyResolveFlags, nsIURI *proxyURI,
-                             uint64_t channelId) {
+                             uint64_t channelId,
+                             nsContentPolicyType aContentPolicyType) {
   nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo, proxyResolveFlags,
-                                      proxyURI, channelId);
+                                      proxyURI, channelId, aContentPolicyType);
   if (NS_FAILED(rv)) return rv;
 
   LOG1(("nsHttpChannel::Init [this=%p]\n", this));
 
   return rv;
 }
 
 nsresult nsHttpChannel::AddSecurityMessage(const nsAString &aMessageTag,
@@ -9557,19 +9558,23 @@ NS_IMPL_ISUPPORTS(CopyNonDefaultHeaderVi
 nsresult nsHttpChannel::RedirectToInterceptedChannel() {
   nsCOMPtr<nsINetworkInterceptController> controller;
   GetCallback(controller);
 
   RefPtr<InterceptedHttpChannel> intercepted =
       InterceptedHttpChannel::CreateForInterception(
           mChannelCreationTime, mChannelCreationTimestamp, mAsyncOpenTime);
 
-  nsresult rv = intercepted->Init(mURI, mCaps,
-                                  static_cast<nsProxyInfo *>(mProxyInfo.get()),
-                                  mProxyResolveFlags, mProxyURI, mChannelId);
+  nsContentPolicyType type = mLoadInfo
+                                 ? mLoadInfo->GetExternalContentPolicyType()
+                                 : nsIContentPolicy::TYPE_OTHER;
+
+  nsresult rv = intercepted->Init(
+      mURI, mCaps, static_cast<nsProxyInfo *>(mProxyInfo.get()),
+      mProxyResolveFlags, mProxyURI, mChannelId, type);
 
   nsCOMPtr<nsILoadInfo> redirectLoadInfo =
       CloneLoadInfoForRedirect(mURI, nsIChannelEventSink::REDIRECT_INTERNAL);
   intercepted->SetLoadInfo(redirectLoadInfo);
 
   rv = SetupReplacementChannel(mURI, intercepted, true,
                                nsIChannelEventSink::REDIRECT_INTERNAL);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -133,21 +133,20 @@ class nsHttpChannel final : public HttpB
   NS_IMETHOD GetURI(nsIURI **aURI) override;
   NS_IMETHOD GetNotificationCallbacks(
       nsIInterfaceRequestor **aCallbacks) override;
   NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup) override;
   NS_IMETHOD GetRequestMethod(nsACString &aMethod) override;
 
   nsHttpChannel();
 
-  virtual MOZ_MUST_USE nsresult Init(nsIURI *aURI, uint32_t aCaps,
-                                     nsProxyInfo *aProxyInfo,
-                                     uint32_t aProxyResolveFlags,
-                                     nsIURI *aProxyURI,
-                                     uint64_t aChannelId) override;
+  virtual MOZ_MUST_USE nsresult
+  Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
+       uint32_t aProxyResolveFlags, nsIURI *aProxyURI, uint64_t aChannelId,
+       nsContentPolicyType aContentPolicyType) override;
 
   MOZ_MUST_USE nsresult OnPush(const nsACString &uri,
                                Http2PushedStream *pushedStream);
 
   static bool IsRedirectStatus(uint32_t status);
   static bool WillRedirect(nsHttpResponseHead *response);
 
   // Methods HttpBaseChannel didn't implement for us or that we override.
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -110,16 +110,22 @@
 #define TCP_FAST_OPEN_FAILURE_LIMIT \
   "network.tcp.tcp_fastopen_consecutive_failure_limit"
 #define TCP_FAST_OPEN_STALLS_LIMIT "network.tcp.tcp_fastopen_http_stalls_limit"
 #define TCP_FAST_OPEN_STALLS_IDLE \
   "network.tcp.tcp_fastopen_http_check_for_stalls_only_if_idle_for"
 #define TCP_FAST_OPEN_STALLS_TIMEOUT \
   "network.tcp.tcp_fastopen_http_stalls_timeout"
 
+#define ACCEPT_HEADER_NAVIGATION \
+  "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+#define ACCEPT_HEADER_IMAGE "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
+#define ACCEPT_HEADER_STYLE "text/css,*/*;q=0.1"
+#define ACCEPT_HEADER_ALL "*/*"
+
 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
 
 #define NS_HTTP_PROTOCOL_FLAGS \
   (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
 
 //-----------------------------------------------------------------------------
@@ -612,30 +618,44 @@ nsresult nsHttpHandler::InitConnectionMg
       mMaxUrgentExcessiveConns, mMaxConnections,
       mMaxPersistentConnectionsPerServer, mMaxPersistentConnectionsPerProxy,
       mMaxRequestDelay, mThrottleEnabled, mThrottleVersion, mThrottleSuspendFor,
       mThrottleResumeFor, mThrottleReadLimit, mThrottleReadInterval,
       mThrottleHoldTime, mThrottleMaxTime);
   return rv;
 }
 
-nsresult nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request,
-                                                  bool isSecure) {
+nsresult nsHttpHandler::AddStandardRequestHeaders(
+    nsHttpRequestHead *request, bool isSecure,
+    nsContentPolicyType aContentPolicyType) {
   nsresult rv;
 
   // Add the "User-Agent" header
   rv = request->SetHeader(nsHttp::User_Agent, UserAgent(), false,
                           nsHttpHeaderArray::eVarietyRequestDefault);
   if (NS_FAILED(rv)) return rv;
 
   // MIME based content negotiation lives!
   // Add the "Accept" header.  Note, this is set as an override because the
   // service worker expects to see it.  The other "default" headers are
   // hidden from service worker interception.
-  rv = request->SetHeader(nsHttp::Accept, mAccept, false,
+  nsAutoCString accept;
+  if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+      aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+    accept.Assign(ACCEPT_HEADER_NAVIGATION);
+  } else if (aContentPolicyType == nsIContentPolicy::TYPE_IMAGE ||
+             aContentPolicyType == nsIContentPolicy::TYPE_IMAGESET) {
+    accept.Assign(ACCEPT_HEADER_IMAGE);
+  } else if (aContentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) {
+    accept.Assign(ACCEPT_HEADER_STYLE);
+  } else {
+    accept.Assign(ACCEPT_HEADER_ALL);
+  }
+
+  rv = request->SetHeader(nsHttp::Accept, accept, false,
                           nsHttpHeaderArray::eVarietyRequestOverride);
   if (NS_FAILED(rv)) return rv;
 
   // Add the "Accept-Language" header.  This header is also exposed to the
   // service worker.
   if (mAcceptLanguagesIsDirty) {
     rv = SetAcceptLanguages();
     MOZ_ASSERT(NS_SUCCEEDED(rv));
@@ -1353,25 +1373,16 @@ void nsHttpHandler::PrefsChanged(const c
     }
   }
 
   if (PREF_CHANGED(HTTP_PREF("qos"))) {
     rv = Preferences::GetInt(HTTP_PREF("qos"), &val);
     if (NS_SUCCEEDED(rv)) mQoSBits = (uint8_t)clamped(val, 0, 0xff);
   }
 
-  if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
-    nsAutoCString accept;
-    rv = Preferences::GetCString(HTTP_PREF("accept.default"), accept);
-    if (NS_SUCCEEDED(rv)) {
-      rv = SetAccept(accept.get());
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-    }
-  }
-
   if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
     nsAutoCString acceptEncodings;
     rv = Preferences::GetCString(HTTP_PREF("accept-encoding"), acceptEncodings);
     if (NS_SUCCEEDED(rv)) {
       rv = SetAcceptEncodings(acceptEncodings.get(), false);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
@@ -1957,21 +1968,16 @@ nsresult nsHttpHandler::SetAcceptLanguag
   nsAutoCString buf;
   nsresult rv = PrepareAcceptLanguages(acceptLanguages.get(), buf);
   if (NS_SUCCEEDED(rv)) {
     mAcceptLanguages.Assign(buf);
   }
   return rv;
 }
 
-nsresult nsHttpHandler::SetAccept(const char *aAccept) {
-  mAccept = aAccept;
-  return NS_OK;
-}
-
 nsresult nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings,
                                            bool isSecure) {
   if (isSecure) {
     mHttpsAcceptEncodings = aAcceptEncodings;
   } else {
     // use legacy list if a secure override is not specified
     mHttpAcceptEncodings = aAcceptEncodings;
     if (mHttpsAcceptEncodings.IsEmpty()) {
@@ -2103,18 +2109,22 @@ nsHttpHandler::NewProxiedChannel2(nsIURI
     // Load UserAgentOverrides.jsm before any HTTP request is issued.
     EnsureUAOverridesInit();
   }
 
   uint64_t channelId;
   rv = NewChannelId(channelId);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsContentPolicyType contentPolicyType =
+      aLoadInfo ? aLoadInfo->GetExternalContentPolicyType()
+                : nsIContentPolicy::TYPE_OTHER;
+
   rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI,
-                         channelId);
+                         channelId, contentPolicyType);
   if (NS_FAILED(rv)) return rv;
 
   // set the loadInfo on the new channel
   rv = httpChannel->SetLoadInfo(aLoadInfo);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -59,18 +59,19 @@ class nsHttpHandler final : public nsIHt
   NS_DECL_NSIPROTOCOLHANDLER
   NS_DECL_NSIPROXIEDPROTOCOLHANDLER
   NS_DECL_NSIHTTPPROTOCOLHANDLER
   NS_DECL_NSIOBSERVER
   NS_DECL_NSISPECULATIVECONNECT
 
   static already_AddRefed<nsHttpHandler> GetInstance();
 
-  MOZ_MUST_USE nsresult AddStandardRequestHeaders(nsHttpRequestHead *,
-                                                  bool isSecure);
+  MOZ_MUST_USE nsresult
+  AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure,
+                            nsContentPolicyType aContentPolicyType);
   MOZ_MUST_USE nsresult AddConnectionHeader(nsHttpRequestHead *,
                                             uint32_t capabilities);
   bool IsAcceptableEncoding(const char *encoding, bool isSecure);
 
   const nsCString &UserAgent();
 
   enum HttpVersion HttpVersion() { return mHttpVersion; }
   enum HttpVersion ProxyHttpVersion() { return mProxyHttpVersion; }
@@ -406,17 +407,16 @@ class nsHttpHandler final : public nsIHt
 
   //
   // Useragent/prefs helper methods
   //
   void BuildUserAgent();
   void InitUserAgentComponents();
   void PrefsChanged(const char *pref);
 
-  MOZ_MUST_USE nsresult SetAccept(const char *);
   MOZ_MUST_USE nsresult SetAcceptLanguages();
   MOZ_MUST_USE nsresult SetAcceptEncodings(const char *, bool mIsSecure);
 
   MOZ_MUST_USE nsresult InitConnectionMgr();
 
   void NotifyObservers(nsIHttpChannel *chan, const char *event);
 
   void SetFastOpenOSSupport();
@@ -493,17 +493,16 @@ class nsHttpHandler final : public nsIHt
   // intended to protect the user against spoofing attempts that use
   // the userpass field of the URL to obscure the actual origin server.
   uint8_t mPhishyUserPassLength;
 
   uint8_t mQoSBits;
 
   bool mEnforceAssocReq;
 
-  nsCString mAccept;
   nsCString mAcceptLanguages;
   nsCString mHttpAcceptEncodings;
   nsCString mHttpsAcceptEncodings;
 
   nsCString mDefaultSocketType;
 
   // cache support
   uint32_t mLastUniqueID;
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -40,8 +40,10 @@ skip-if = (verify && debug && os == 'mac
 skip-if = verify
 [test_1396395.html]
 [test_1421324.html]
 [test_1425031.html]
 [test_1503201.html]
 [test_origin_header.html]
 [test_1502055.html]
 support-files = sw_1502055.js file_1502055.sjs iframe_1502055.html
+[test_accept_header.html]
+support-files = test_accept_header.sjs
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Accept header</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+
+// All the requests are sent to test_accept_header.sjs which will return
+// different content based on the queryString. When the queryString is 'get',
+// test_accept_header.sjs returns a JSON object with the latest request and its
+// accept header value.
+
+function test_last_request_and_continue(query, expected) {
+  fetch("test_accept_header.sjs?get").then(r => r.json()).then(json => {
+    is(json.type, query, "Expected: " + query);
+    is(json.accept, expected, "Accept header: " + expected);
+    next();
+  });
+}
+
+function test_iframe() {
+  let observer = new PerformanceObserver(function(list, obj) {
+    obj.disconnect();
+
+    list.getEntries().forEach(entry => {
+      if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
+        obj.disconnect();
+        test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+      }
+    });
+  });
+
+  observer.observe({entryTypes: ["resource"]});
+
+  let ifr = document.createElement("iframe");
+  ifr.src = "test_accept_header.sjs?iframe";
+  document.body.appendChild(ifr);
+}
+
+function test_image() {
+  let i = new Image();
+  i.src = "test_accept_header.sjs?image";
+  i.onload = function() {
+    // Fetch spec says we should have: "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
+    test_last_request_and_continue("image", "image/webp,*/*");
+  }
+}
+
+function test_style() {
+  let observer = new PerformanceObserver(function(list, obj) {
+    obj.disconnect();
+
+    list.getEntries().forEach(entry => {
+      if (entry.name.endsWith("test_accept_header.sjs?style")) {
+        obj.disconnect();
+        test_last_request_and_continue("style", "text/css,*/*;q=0.1");
+      }
+    });
+  });
+
+  observer.observe({entryTypes: ["resource"]});
+
+  let head = document.getElementsByTagName("head")[0];
+  let link = document.createElement("link");
+  link.rel = "stylesheet";
+  link.type = "text/css";
+  link.href = "test_accept_header.sjs?style";
+  head.appendChild(link);
+}
+
+function test_worker() {
+  let w = new Worker("test_accept_header.sjs?worker");
+  w.onmessage = function() {
+    test_last_request_and_continue("worker", "*/*");
+  }
+}
+
+let tests = [
+  test_iframe,
+  test_image,
+  test_style,
+  test_worker,
+];
+
+function next() {
+  if (tests.length == 0) {
+    SimpleTest.finish();
+    return;
+  }
+
+  let test = tests.shift();
+  test();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({ "set": [
+  [ "dom.enable_performance_observer", true ]
+]}, next);
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.sjs
@@ -0,0 +1,48 @@
+function handleRequest(request, response) {
+  response.setStatusLine(request.httpVersion, "200", "OK");
+
+  if (request.queryString == "worker") {
+    response.setHeader("Content-Type", "application/json", false);
+    response.write("postMessage(42)");
+
+    setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
+    return;
+  }
+
+  if (request.queryString == "image") {
+    // A 1x1 PNG image.
+    // Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
+    const IMAGE = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
+                       "ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
+
+    response.setHeader("Content-Type", "image/png", false);
+    response.write(IMAGE);
+
+    setState("data", JSON.stringify({type: "image", accept: request.getHeader("Accept") }));
+    return;
+  }
+
+  if (request.queryString == "style") {
+    response.setHeader("Content-Type", "text/css", false);
+    response.write("");
+
+    setState("data", JSON.stringify({type: "style", accept: request.getHeader("Accept") }));
+    return;
+  }
+
+  if (request.queryString == "iframe") {
+    response.setHeader("Content-Type", "text/html", false);
+    response.write("<h1>Hello world!</h1>");
+
+    setState("data", JSON.stringify({type: "iframe", accept: request.getHeader("Accept") }));
+    return;
+  }
+
+  if (request.queryString == "get") {
+    response.setHeader("Content-Type", "text/javascript", false);
+    response.write(getState("data"));
+
+    setState("data", "");
+    return;
+  }
+}
--- a/toolkit/mozapps/update/UpdateTelemetry.jsm
+++ b/toolkit/mozapps/update/UpdateTelemetry.jsm
@@ -171,16 +171,18 @@ var AUSTLMY = {
   DWNLD_ERR_PATCH_SIZE_LARGER: 8,
   DWNLD_ERR_PATCH_SIZE_NOT_EQUAL: 9,
   DWNLD_ERR_BINDING_ABORTED: 10,
   DWNLD_ERR_ABORT: 11,
   DWNLD_ERR_DOCUMENT_NOT_CACHED: 12,
   DWNLD_ERR_VERIFY_NO_REQUEST: 13,
   DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL: 14,
   DWNLD_ERR_WRITE_FAILURE: 15,
+  // Temporary failure code to see if there are failures without an update phase
+  DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE: 40,
 
   /**
    * Submit a telemetry ping for the update download result code.
    *
    * @param  aIsComplete
    *         If true the histogram is for a patch type complete, if false the
    *         histogram is for a patch type partial, and when undefined the
    *         histogram is for an unknown patch type. This is used to determine
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -189,18 +189,23 @@ const APPID_TO_TOPIC = {
   // Firefox
   "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}": "sessionstore-windows-restored",
   // SeaMonkey
   "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}": "sessionstore-windows-restored",
   // Thunderbird
   "{3550f703-e582-4d05-9a08-453d09bdfdc6}": "mail-startup-done",
 };
 
-// A var is used for the delay so tests can set a smaller value.
-var gSaveUpdateXMLDelay = 2000;
+// The interval for the update xml write deferred task.
+const XML_SAVER_INTERVAL_MS = 200;
+
+// Object to keep track of the current phase of the update and whether there
+// has been a write failure for the phase so only one telemetry ping is made
+// for the phase.
+var gUpdateFileWriteInfo = {phase: null, failure: false};
 var gUpdateMutexHandle = null;
 // The permissions of the update directory should be fixed no more than once per
 // session
 var gUpdateDirPermissionFixAttempted = false;
 
 XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function aus_gLogEnabled() {
   return Services.prefs.getBoolPref(PREF_APP_UPDATE_LOG, false);
 });
@@ -1093,52 +1098,52 @@ function pingStateAndStatusCodes(aUpdate
  * Returns false if the permission-fixing process cannot be started. Since this
  * is asynchronous, a true return value does not mean that the permissions were
  * actually fixed.
  *
  * @param path A string representing the path that could not be written. This
  *             value will only be used for logging purposes.
  */
 function handleCriticalWriteFailure(path) {
-  LOG("Unable to write to critical update file: " + path);
-
-  let updateManager = Cc["@mozilla.org/updates/update-manager;1"].
-                      getService(Ci.nsIUpdateManager);
-
-  let update = updateManager.activeUpdate;
-  if (update) {
-    let patch = update.selectedPatch;
+  LOG("handleCriticalWriteFailure - Unable to write to critical update file: " +
+      path);
+  if (!gUpdateFileWriteInfo.failure) {
+    gUpdateFileWriteInfo.failure = true;
     let patchType = AUSTLMY.PATCH_UNKNOWN;
-    if (patch.type == "complete") {
-      patchType = AUSTLMY.PATCH_COMPLETE;
-    } else if (patch.type == "partial") {
-      patchType = AUSTLMY.PATCH_PARTIAL;
+    let update = Cc["@mozilla.org/updates/update-manager;1"].
+                 getService(Ci.nsIUpdateManager).activeUpdate;
+    if (update) {
+      let patch = update.selectedPatch;
+      if (patch.type == "complete") {
+        patchType = AUSTLMY.PATCH_COMPLETE;
+      } else if (patch.type == "partial") {
+        patchType = AUSTLMY.PATCH_PARTIAL;
+      }
     }
-    if (update.state == STATE_DOWNLOADING) {
-      if (!patch.downloadWriteFailureTelemetrySent) {
-        AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_ERR_WRITE_FAILURE);
-        patch.downloadWriteFailureTelemetrySent = true;
+
+    if (gUpdateFileWriteInfo.phase == "check") {
+      let updateServiceInstance = UpdateServiceFactory.createInstance();
+      let pingSuffix = updateServiceInstance._pingSuffix;
+      if (!pingSuffix) {
+        // If pingSuffix isn't defined then this this is a manual check which
+        // isn't recorded at this time.
+        AUSTLMY.pingCheckCode(pingSuffix, AUSTLMY.CHK_ERR_WRITE_FAILURE);
       }
-    } else if (!patch.applyWriteFailureTelemetrySent) {
-      // It's not ideal to hardcode AUSTLMY.STARTUP below (it could be
-      // AUSTLMY.STAGE). But staging is not used anymore and neither value
-      // really makes sense for this code. For the other codes it indicates when
-      // that code was read from the update status file, but this code was never
-      // read from the update status file.
+    } else if (gUpdateFileWriteInfo.phase == "download") {
+      AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_ERR_WRITE_FAILURE);
+    } else if (gUpdateFileWriteInfo.phase == "stage") {
+      let suffix = patchType + "_" + AUSTLMY.STAGE;
+      AUSTLMY.pingStateCode(suffix, AUSTLMY.STATE_WRITE_FAILURE);
+    } else if (gUpdateFileWriteInfo.phase == "startup") {
       let suffix = patchType + "_" + AUSTLMY.STARTUP;
       AUSTLMY.pingStateCode(suffix, AUSTLMY.STATE_WRITE_FAILURE);
-      patch.applyWriteFailureTelemetrySent = true;
-    }
-  } else {
-    let updateServiceInstance = UpdateServiceFactory.createInstance();
-    let request = updateServiceInstance.backgroundChecker._request;
-    if (!request.checkWriteFailureTelemetrySent) {
-      let pingSuffix = updateServiceInstance._pingSuffix;
-      AUSTLMY.pingCheckCode(pingSuffix, AUSTLMY.CHK_ERR_WRITE_FAILURE);
-      request.checkWriteFailureTelemetrySent = true;
+    } else {
+      // Temporary failure code to see if there are failures without an update
+      // phase.
+      AUSTLMY.pingDownloadCode(patchType, AUSTLMY.DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE);
     }
   }
 
   if (!gUpdateDirPermissionFixAttempted) {
     // Currently, we only have a mechanism for fixing update directory permissions
     // on Windows.
     if (AppConstants.platform != "win") {
       LOG("There is currently no implementation for fixing update directory " +
@@ -1182,16 +1187,17 @@ function handleCriticalWriteResult(wrote
  * @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.finalURL = null;
   this.state = STATE_NONE;
 
   for (let 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;
@@ -1750,16 +1756,19 @@ UpdateService.prototype = {
         }
         if (this._retryTimer) {
           this._retryTimer.cancel();
         }
 
         this.pauseDownload();
         // Prevent leaking the downloader (bug 454964)
         this._downloader = null;
+        // In case an update check is in progress.
+        Cc["@mozilla.org/updates/update-checker;1"].
+          createInstance(Ci.nsIUpdateChecker).stopCurrentCheck();
         break;
     }
   },
 
   /**
    * The following needs to happen during the post-update-processing
    * notification from nsUpdateServiceStub.js:
    * 1. post update processing
@@ -1770,16 +1779,17 @@ UpdateService.prototype = {
 
   /**
    * Perform post-processing on updates lingering in the updates directory
    * from a previous application session - either report install failures (and
    * optionally attempt to fetch a different version if appropriate) or
    * notify the user of install success.
    */
   _postUpdateProcessing: function AUS__postUpdateProcessing() {
+    gUpdateFileWriteInfo = {phase: "startup", failure: false};
     if (!this.canCheckForUpdates) {
       LOG("UpdateService:_postUpdateProcessing - unable to check for " +
           "updates... returning early");
       return;
     }
 
     if (!this.canApplyUpdates) {
       LOG("UpdateService:_postUpdateProcessing - unable to apply " +
@@ -2622,22 +2632,16 @@ UpdateService.prototype = {
                                           Ci.nsIObserver]),
 };
 
 /**
  * A service to manage active and past updates.
  * @constructor
  */
 function UpdateManager() {
-  if (Services.appinfo.ID == "xpcshell@tests.mozilla.org") {
-    // Use a smaller value for xpcshell tests so they don't have to wait as
-    // long for the files to be saved.
-    gSaveUpdateXMLDelay = 0;
-  }
-
   // Load the active-update.xml file to see if there is an active update.
   let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
   if (activeUpdates.length > 0) {
     // Set the active update directly on the var used to cache the value.
     this._activeUpdate = activeUpdates[0];
     // This check is performed here since UpdateService:_postUpdateProcessing
     // won't be called when there isn't an update.status file.
     if (readStatusFile(getUpdatesDir()) == STATE_NONE) {
@@ -2671,33 +2675,34 @@ UpdateManager.prototype = {
   _updatesDirty: false,
 
   /**
    * See nsIObserver.idl
    */
   observe: function UM_observe(subject, topic, data) {
     // Hack to be able to run and cleanup tests by reloading the update data.
     if (topic == "um-reload-update-data") {
+      if (!Cu.isInAutomation) {
+        return;
+      }
       if (this._updatesXMLSaver) {
         this._updatesXMLSaver.disarm();
-        AsyncShutdown.profileBeforeChange.removeBlocker(this._updatesXMLSaverCallback);
-        this._updatesXMLSaver = null;
-        this._updatesXMLSaverCallback = null;
       }
-      // Set the write delay to 0 for mochitest-chrome and mochitest-browser
-      // tests.
-      gSaveUpdateXMLDelay = 0;
+
+      let updates = [];
+      this._updatesDirty = true;
       this._activeUpdate = null;
-      let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
-      if (activeUpdates.length > 0) {
-        this._activeUpdate = activeUpdates[0];
+      if (data != "skip-files") {
+        let activeUpdates = this._loadXMLFileIntoArray(FILE_ACTIVE_UPDATE_XML);
+        if (activeUpdates.length > 0) {
+          this._activeUpdate = activeUpdates[0];
+        }
+        updates = this._loadXMLFileIntoArray(FILE_UPDATES_XML);
       }
-      this._updatesDirty = true;
       delete this._updates;
-      let updates = this._loadXMLFileIntoArray(FILE_UPDATES_XML);
       Object.defineProperty(this, "_updates", {
         value: updates,
         writable: true,
         configurable: true,
         enumerable: true,
       });
     }
   },
@@ -2763,18 +2768,18 @@ UpdateManager.prototype = {
             " file. Exception: " + e);
       }
     }
     return updates;
   },
 
   /**
    * Loads the update history from the updates.xml file and then replaces
-   * _updates with an array of all previously downloaded and installed updates
-   * so the file is only read once.
+   * |_updates| with an array of all previous updates so the file is only read
+   * once.
    */
   get _updates() {
     delete this._updates;
     let updates = this._loadXMLFileIntoArray(FILE_UPDATES_XML);
     Object.defineProperty(this, "_updates", {
       value: updates,
       writable: true,
       configurable: true,
@@ -2841,28 +2846,32 @@ UpdateManager.prototype = {
       } catch (e) {
         LOG("UpdateManager:_writeUpdatesToXMLFile - Delete file exception: " +
             e);
         return false;
       }
       return true;
     }
 
-    const EMPTY_UPDATES_DOCUMENT_OPEN = "<?xml version=\"1.0\"?><updates xmlns=\"http://www.mozilla.org/2005/app-update\">";
+    const EMPTY_UPDATES_DOCUMENT_OPEN =
+      "<?xml version=\"1.0\"?><updates xmlns=\"" + URI_UPDATE_NS + "\">";
     const EMPTY_UPDATES_DOCUMENT_CLOSE = "</updates>";
     try {
       var parser = new DOMParser();
       var doc = parser.parseFromString(EMPTY_UPDATES_DOCUMENT_OPEN + EMPTY_UPDATES_DOCUMENT_CLOSE, "text/xml");
 
       for (var i = 0; i < updates.length; ++i) {
         doc.documentElement.appendChild(updates[i].serialize(doc));
       }
 
       var xml = EMPTY_UPDATES_DOCUMENT_OPEN + doc.documentElement.innerHTML +
                 EMPTY_UPDATES_DOCUMENT_CLOSE;
+      // If the destination file existed and is removed while the following is
+      // being performed the copy of the tmp file to the destination file will
+      // fail.
       await OS.File.writeAtomic(file.path, xml, {encoding: "utf-8",
                                                  tmpPath: file.path + ".tmp"});
       await OS.File.setPermissions(file.path, {unixMode: FileUtils.PERMS_FILE});
     } catch (e) {
       LOG("UpdateManager:_writeUpdatesToXMLFile - Exception: " + e);
       return false;
     }
     return true;
@@ -2873,53 +2882,53 @@ UpdateManager.prototype = {
   /**
    * See nsIUpdateService.idl
    */
   saveUpdates: function UM_saveUpdates() {
     if (!this._updatesXMLSaver) {
       this._updatesXMLSaverCallback = () => this._updatesXMLSaver.finalize();
 
       this._updatesXMLSaver = new DeferredTask(() => this._saveUpdatesXML(),
-                                               gSaveUpdateXMLDelay);
+                                               XML_SAVER_INTERVAL_MS);
       AsyncShutdown.profileBeforeChange.addBlocker(
         "UpdateManager: writing update xml data", this._updatesXMLSaverCallback);
     } else {
       this._updatesXMLSaver.disarm();
     }
 
     this._updatesXMLSaver.arm();
   },
 
   /**
    * Saves the active-updates.xml and updates.xml when the updates history has
    * been modified files.
    */
   _saveUpdatesXML: function UM__saveUpdatesXML() {
-    AsyncShutdown.profileBeforeChange.removeBlocker(this._updatesXMLSaverCallback);
-    this._updatesXMLSaver = null;
-    this._updatesXMLSaverCallback = null;
-
     // The active update stored in the active-update.xml file will change during
     // the lifetime of an active update and the file should always be updated
     // when saveUpdates is called.
-    this._writeUpdatesToXMLFile(this._activeUpdate ? [this._activeUpdate] : [],
-                                FILE_ACTIVE_UPDATE_XML).then(
+    let updates = this._activeUpdate ? [this._activeUpdate] : [];
+    let promises = [];
+    promises[0] = this._writeUpdatesToXMLFile(updates,
+                                              FILE_ACTIVE_UPDATE_XML).then(
       wroteSuccessfully => handleCriticalWriteResult(wroteSuccessfully,
                                                      FILE_ACTIVE_UPDATE_XML)
     );
     // The update history stored in the updates.xml file should only need to be
     // updated when an active update has been added to it in which case
     // |_updatesDirty| will be true.
     if (this._updatesDirty) {
       this._updatesDirty = false;
-      this._writeUpdatesToXMLFile(this._updates, FILE_UPDATES_XML).then(
+      promises[1] = this._writeUpdatesToXMLFile(this._updates,
+                                                FILE_UPDATES_XML).then(
         wroteSuccessfully => handleCriticalWriteResult(wroteSuccessfully,
                                                        FILE_UPDATES_XML)
       );
     }
+    return Promise.all(promises);
   },
 
   /**
    * See nsIUpdateService.idl
    */
   refreshUpdateStatus: function UM_refreshUpdateStatus() {
     var update = this._activeUpdate;
     if (!update) {
@@ -3120,16 +3129,17 @@ Checker.prototype = {
     return url;
   },
 
   /**
    * See nsIUpdateService.idl
    */
   checkForUpdates: function UC_checkForUpdates(listener, force) {
     LOG("Checker: checkForUpdates, force: " + force);
+    gUpdateFileWriteInfo = {phase: "check", failure: false};
     if (!listener) {
       throw Cr.NS_ERROR_NULL_POINTER;
     }
 
     let UpdateServiceInstance = UpdateServiceFactory.createInstance();
     // |force| can override |canCheckForUpdates| since |force| indicates a
     // manual update check. But nothing should override enterprise policies.
     if (UpdateServiceInstance.disabledByPolicy) {
@@ -3538,16 +3548,17 @@ Downloader.prototype = {
 
   /**
    * Download and stage the given update.
    * @param   update
    *          A nsIUpdate object to download a patch for. Cannot be null.
    */
   downloadUpdate: function Downloader_downloadUpdate(update) {
     LOG("UpdateService:_downloadUpdate");
+    gUpdateFileWriteInfo = {phase: "download", failure: false};
     if (!update) {
       AUSTLMY.pingDownloadCode(undefined, AUSTLMY.DWNLD_ERR_NO_UPDATE);
       throw Cr.NS_ERROR_NULL_POINTER;
     }
 
     var updateDir = getUpdatesDir();
 
     this._update = update;
@@ -3573,21 +3584,21 @@ Downloader.prototype = {
     var uri = Services.io.newURI(this._patch.URL);
 
     this._request = Cc["@mozilla.org/network/incremental-download;1"].
                     createInstance(Ci.nsIIncrementalDownload);
     this._request.init(uri, patchFile, DOWNLOAD_CHUNK_SIZE, interval);
     this._request.start(this, null);
 
     writeStatusFile(updateDir, STATE_DOWNLOADING);
-    this._patch.QueryInterface(Ci.nsIWritablePropertyBag);
-    this._patch.state = STATE_DOWNLOADING;
-    var um = Cc["@mozilla.org/updates/update-manager;1"].
-             getService(Ci.nsIUpdateManager);
-    um.saveUpdates();
+    if (this._patch.state != STATE_DOWNLOADING) {
+      this._patch.state = STATE_DOWNLOADING;
+      Cc["@mozilla.org/updates/update-manager;1"].
+        getService(Ci.nsIUpdateManager).saveUpdates();
+    }
     return STATE_DOWNLOADING;
   },
 
   /**
    * An array of download listeners to notify when we receive
    * nsIRequestObserver or nsIProgressEventSink method calls.
    */
   _listeners: [],
@@ -3607,17 +3618,17 @@ Downloader.prototype = {
   },
 
   /**
    * Removes a download listener
    * @param   listener
    *          The listener to remove.
    */
   removeDownloadListener: function Downloader_removeDownloadListener(listener) {
-    for (var i = 0; i < this._listeners.length; ++i) {
+    for (let i = 0; i < this._listeners.length; ++i) {
       if (this._listeners[i] == listener) {
         this._listeners.splice(i, 1);
         return;
       }
     }
   },
 
   /**
@@ -3626,26 +3637,28 @@ Downloader.prototype = {
    *          The nsIRequest object for the transfer
    * @param   context
    *          Additional data
    */
   onStartRequest: function Downloader_onStartRequest(request, context) {
     if (request instanceof Ci.nsIIncrementalDownload)
       LOG("Downloader:onStartRequest - original URI spec: " + request.URI.spec +
           ", final URI spec: " + request.finalURI.spec);
-    // Always set finalURL in onStartRequest since it can change.
-    this._patch.finalURL = request.finalURI.spec;
-    var um = Cc["@mozilla.org/updates/update-manager;1"].
-             getService(Ci.nsIUpdateManager);
-    um.saveUpdates();
-
-    var listeners = this._listeners.concat();
-    var listenerCount = listeners.length;
-    for (var i = 0; i < listenerCount; ++i)
+    // Set finalURL in onStartRequest if it is different.
+    if (this._patch.finalURL != request.finalURI.spec) {
+      this._patch.finalURL = request.finalURI.spec;
+      Cc["@mozilla.org/updates/update-manager;1"].
+        getService(Ci.nsIUpdateManager).saveUpdates();
+    }
+
+    let listeners = this._listeners.concat();
+    let listenerCount = listeners.length;
+    for (let i = 0; i < listenerCount; ++i) {
       listeners[i].onStartRequest(request, context);
+    }
   },
 
   /**
    * When new data has been downloaded
    * @param   request
    *          The nsIRequest object for the transfer
    * @param   context
    *          Additional data
@@ -3843,29 +3856,37 @@ Downloader.prototype = {
       this._update.statusText = getStatusTextFromCode(status,
                                                       Cr.NS_BINDING_FAILED);
 
       // Destroy the updates directory, since we're done with it.
       cleanUpUpdatesDir();
 
       deleteActiveUpdate = true;
     }
+    let saveUpdate = false;
     LOG("Downloader:onStopRequest - setting state to: " + state);
-    this._patch.state = state;
+    if (this._patch.state != state) {
+      saveUpdate = true;
+      this._patch.state = state;
+    }
     var um = Cc["@mozilla.org/updates/update-manager;1"].
              getService(Ci.nsIUpdateManager);
     if (deleteActiveUpdate) {
+      saveUpdate = true;
       this._update.installDate = (new Date()).getTime();
       // Setting |activeUpdate| to null will move the active update to the
       // update history.
       um.activeUpdate = null;
-    } else if (um.activeUpdate) {
+    } else if (um.activeUpdate && um.activeUpdate.state != state) {
+      saveUpdate = true;
       um.activeUpdate.state = state;
     }
-    um.saveUpdates();
+    if (saveUpdate) {
+      um.saveUpdates();
+    }
 
     // Only notify listeners about the stopped state if we
     // aren't handling an internal retry.
     if (!shouldRetrySoon && !shouldRegisterOnlineObserver) {
       var listeners = this._listeners.concat();
       var listenerCount = listeners.length;
       for (var i = 0; i < listenerCount; ++i) {
         listeners[i].onStopRequest(request, context, status);
@@ -3931,18 +3952,18 @@ Downloader.prototype = {
       return;
     }
 
     if (state == STATE_PENDING || state == STATE_PENDING_SERVICE ||
         state == STATE_PENDING_ELEVATE) {
       if (getCanStageUpdates()) {
         LOG("Downloader:onStopRequest - attempting to stage update: " +
             this._update.name);
-
-        // Initiate the update in the background
+        gUpdateFileWriteInfo = {phase: "stage", failure: false};
+        // Stage the update
         try {
           Cc["@mozilla.org/updates/update-processor;1"].
             createInstance(Ci.nsIUpdateProcessor).
             processUpdate(this._update);
         } catch (e) {
           // Fail gracefully in case the application does not support the update
           // processor service.
           LOG("Downloader:onStopRequest - failed to stage update. Exception: " +
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -70,19 +70,17 @@ function getVersionParams(aAppVersion) {
   let appInfo = Services.appinfo;
   return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version);
 }
 
 /**
  * Clean up updates list and the updates directory.
  */
 function cleanUpUpdates() {
-  gUpdateManager.activeUpdate = null;
-  gUpdateManager.saveUpdates();
-
+  reloadUpdateManagerData(true);
   removeUpdateDirsAndFiles();
 }
 
 /**
  * Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService
  * to check for updates by setting the app update last update time to the
  * current time minus one minute in seconds and the interval time to 12 hours
  * in seconds.
@@ -141,16 +139,17 @@ function runUpdateTest(updateParams, che
     registerCleanupFunction(() => {
       gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
       UpdateListener.reset();
       cleanUpUpdates();
     });
 
     gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     setUpdateTimerPrefs();
+    removeUpdateDirsAndFiles();
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_IDLETIME, 0],
         [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
       ]});
 
@@ -194,18 +193,19 @@ function runUpdateTest(updateParams, che
 function runUpdateProcessingTest(updates, steps) {
   return (async function() {
     registerCleanupFunction(() => {
       gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
       UpdateListener.reset();
       cleanUpUpdates();
     });
 
+    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     setUpdateTimerPrefs();
-    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
+    removeUpdateDirsAndFiles();
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_IDLETIME, 0],
         [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
       ]});
 
--- a/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul
@@ -27,17 +27,18 @@ const TESTS = [ {
 function runTest() {
   debugDump("entering");
 
   let patchProps = {type: "partial",
                     size: "1234",
                     state: STATE_DOWNLOADING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {size: "1234",
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_DOWNLOADING);
--- a/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul
@@ -26,17 +26,18 @@ const TESTS = [ {
 
 function runTest() {
   debugDump("entering");
 
   let patchProps = {type: "partial",
                     size: "1234",
                     state: STATE_DOWNLOADING};
   let patches = getLocalPatchString(patchProps);
-  patchProps = {selected: "false"};
+  patchProps = {selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_DOWNLOADING);
--- a/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul
@@ -38,17 +38,18 @@ function runTest() {
 
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_FAILED_CRC_ERROR);
--- a/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul
@@ -39,17 +39,18 @@ function runTest() {
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
                 size: "1234",
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   writeStatusFile(STATE_FAILED_CRC_ERROR);
--- a/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul
@@ -61,17 +61,18 @@ function runTest() {
 
   // Specify the url to update.sjs with a slowDownloadMar param so the ui can
   // load before the download completes.
   let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {url: slowDownloadURL,
-                selected: "false"};
+                selected: "false",
+                state: null};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
   writeStatusFile(STATE_FAILED_READ_ERROR);
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
 
--- a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul
+++ b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul
@@ -43,18 +43,35 @@ function runTest() {
   closeUpdateWindow();
 
   // Always disable updates and update staging when cleaning up.
   Services.prefs.setBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, true);
   Services.prefs.setBoolPref(PREF_DISABLE_SECURITY, true);  // Needed to disable updates
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
 
   resetFiles();
+  reloadUpdateManagerData(true);
   removeUpdateDirsAndFiles();
-  reloadUpdateManagerData();
+
+  // The updates directory is located outside of the application directory and
+  // needs to be removed on Windows and Mac OS X.
+  if (IS_WIN || IS_MACOSX) {
+    let updatesDir = getUpdatesRootDir();
+    // Try to remove the directory used to apply updates. Since the test has
+    // already finished this is non-fatal for the test.
+    if (updatesDir.exists()) {
+      debugDump("attempting to remove directory. Path: " + updatesDir.path);
+      try {
+        removeDirRecursive(updatesDir);
+      } catch (e) {
+        logTestInfo("non-fatal error removing directory. Path: " +
+                    updatesDir.path + ", Exception: " + e);
+      }
+    }
+  }
 
   let file = getUpdatesXMLFile(true);
   ok(!file.exists(), file.path + " should not exist");
 
   file = getUpdatesXMLFile(false);
   ok(!file.exists(), file.path + " should not exist");
 
   let dir = getUpdatesDir();
--- a/toolkit/mozapps/update/tests/chrome/utils.js
+++ b/toolkit/mozapps/update/tests/chrome/utils.js
@@ -282,17 +282,17 @@ function finishTestDefault() {
   }
 
   verifyTestsRan();
 
   resetPrefs();
   gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
   resetFiles();
   removeUpdateDirsAndFiles();
-  reloadUpdateManagerData();
+  reloadUpdateManagerData(true);
 
   Services.ww.unregisterNotification(gWindowObserver);
   if (gDocElem) {
     gDocElem.removeEventListener("pageshow", onPageShowDefault);
   }
 
   finishTestRestoreUpdaterBackup();
 }
--- a/toolkit/mozapps/update/tests/data/shared.js
+++ b/toolkit/mozapps/update/tests/data/shared.js
@@ -133,19 +133,20 @@ function testPostUpdateProcessing() {
 
 /* Initializes the update service stub */
 function initUpdateServiceStub() {
   Cc["@mozilla.org/updates/update-service-stub;1"].
   createInstance(Ci.nsISupports);
 }
 
 /* Reloads the update metadata from disk */
-function reloadUpdateManagerData() {
+function reloadUpdateManagerData(skipFiles = false) {
+  let observeData = skipFiles ? "skip-files" : "";
   gUpdateManager.QueryInterface(Ci.nsIObserver).
-  observe(null, "um-reload-update-data", "");
+  observe(null, "um-reload-update-data", observeData);
 }
 
 const observer = {
   observe(aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) {
       let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
       if (channel != gChannel) {
         debugDump("Changing channel from " + channel + " to " + gChannel);
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -725,16 +725,20 @@ var gTestDirsCommon = [
     subDirs: ["970/", "971/"],
     subDirFiles: ["97xtext0", "97xtext1"],
   }, {
     relPathDir: DIR_RESOURCES + "9/98/",
     dirRemoved: true,
   }, {
     relPathDir: DIR_RESOURCES + "9/99/",
     dirRemoved: true,
+  }, {
+    description: "Silences 'WARNING: Failed to resolve XUL App Dir.' in debug builds",
+    relPathDir: DIR_RESOURCES + "browser",
+    dirRemoved: false,
   }];
 
 // Directories for a complete successful update. This array can be used for a
 // complete failed update by calling setTestFilesAndDirsForFailure.
 var gTestDirsCompleteSuccess = [
   {
     description: "Removed by precomplete (rmdir)",
     relPathDir: DIR_RESOURCES + "2/20/",
@@ -889,23 +893,16 @@ function setupTestCommon(aAppUpdateAutoE
  */
 function cleanupTestCommon() {
   debugDump("start - general test cleanup");
 
   if (gChannel) {
     gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
   }
 
-  // Call app update's observe method passing quit-application to test that the
-  // shutdown of app update runs without throwing or leaking. The observer
-  // method is used directly instead of calling notifyObservers so components
-  // outside of the scope of this test don't assert and thereby cause app update
-  // tests to fail.
-  gAUS.observe(null, "quit-application", "");
-
   gTestserver = null;
 
   if (IS_UNIX) {
     // This will delete the launch script if it exists.
     getLaunchScript();
   }
 
   if (IS_WIN && MOZ_APP_BASENAME) {
@@ -1019,103 +1016,27 @@ function dumpOverride(aText) {
 function doTestFinish() {
   if (DEBUG_AUS_TEST) {
     // This prevents do_print errors from being printed by the xpcshell test
     // harness due to nsUpdateService.js logging to the console when the
     // app.update.log preference is true.
     Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false);
     gAUS.observe(null, "nsPref:changed", PREF_APP_UPDATE_LOG);
   }
-  executeSoon(testFinishWaitForUpdateXMLFiles);
-}
-
-/**
- * Waits until the update files don't exist and then calls do_test_finished to
- * end the test. This is necessary due to the update xml files being written
- * asynchronously by nsIUpdateManager. Uses do_timeout instead of
- * do_execute_soon to lessen log spew.
- */
-function testFinishWaitForUpdateXMLFiles() {
-  /**
-   * Waits until the update tmp files don't exist and then calls
-   * testFinishReloadUpdateXMLFiles.
-   */
-  function testFinishWaitForUpdateTmpXMLFiles() {
-    let tmpActiveUpdateXML = getUpdatesRootDir();
-    tmpActiveUpdateXML.append(FILE_ACTIVE_UPDATE_XML + ".tmp");
-    if (tmpActiveUpdateXML.exists()) {
-      // The xml files are written asynchronously so wait until it has been
-      // removed.
-      do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
-      return;
-    }
-
-    let tmpUpdatesXML = getUpdatesRootDir();
-    tmpUpdatesXML.append(FILE_UPDATES_XML + ".tmp");
-    if (tmpUpdatesXML.exists()) {
-      // The xml files are written asynchronously so wait until it has been
-      // removed.
-      do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
-      return;
-    }
-
-    do_timeout(10, testFinishReloadUpdateXMLFiles);
-  }
-
-  /**
-   * Creates empty update xml files, reloads / saves the update data, and then
-   * calls testFinishWaitForUpdateXMLFiles.
-   */
-  function testFinishReloadUpdateXMLFiles() {
-    try {
-      // Wrapped in a try catch since the file can be in the middle of a write.
-      writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true);
-    } catch (e) {
-      do_timeout(10, testFinishReloadUpdateXMLFiles);
-      return;
-    }
-    try {
-      // Wrapped in a try catch since the file can be in the middle of a write.
-      writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
-    } catch (e) {
-      do_timeout(10, testFinishReloadUpdateXMLFiles);
-      return;
-    }
-
-    reloadUpdateManagerData();
-    gUpdateManager.saveUpdates();
-    do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-  }
-
-  /**
-   * Waits until the active-update.xml and updates.xml files don't exist and
-   * then calls do_test_finished to end the test. This is necessary due to the
-   * update xml files being written asynchronously by nsIUpdateManager.
-   */
-  function testFinishWaitForUpdateXMLFilesDelete() {
-    let activeUpdateXML = getUpdatesXMLFile(true);
-    if (activeUpdateXML.exists()) {
-      // Since the file is removed asynchronously wait until it has been
-      // removed. Uses do_timeout instead of do_execute_soon to lessen log spew.
-      do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-      return;
-    }
-
-    let updatesXML = getUpdatesXMLFile(false);
-    if (updatesXML.exists()) {
-      // Since the file is removed asynchronously wait until it has been
-      // removed. Uses do_timeout instead of do_execute_soon to lessen log spew.
-      do_timeout(10, testFinishWaitForUpdateXMLFilesDelete);
-      return;
-    }
-
-    do_timeout(10, do_test_finished);
-  }
-
-  do_timeout(10, testFinishWaitForUpdateTmpXMLFiles);
+
+  reloadUpdateManagerData(true);
+
+  // Call app update's observe method passing quit-application to test that the
+  // shutdown of app update runs without throwing or leaking. The observer
+  // method is used directly instead of calling notifyObservers so components
+  // outside of the scope of this test don't assert and thereby cause app update
+  // tests to fail.
+  gAUS.observe(null, "quit-application", "");
+
+  executeSoon(do_test_finished);
 }
 
 /**
  * Sets the most commonly used preferences used by tests
  */
 function setDefaultPrefs() {
   Services.prefs.setBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false);
   if (DEBUG_AUS_TEST) {
@@ -2877,19 +2798,22 @@ function waitForHelperExit() {
  * @param   aMarFile
  *          The mar file for the update test.
  * @param   aPostUpdateAsync
  *          When null the updater.ini is not created otherwise this parameter
  *          is passed to createUpdaterINI.
  * @param   aPostUpdateExeRelPathPrefix
  *          When aPostUpdateAsync null this value is ignored otherwise it is
  *          passed to createUpdaterINI.
+ * @param   aSetupActiveUpdate
+ *          Whether to setup the active update.
  */
 function setupUpdaterTest(aMarFile, aPostUpdateAsync,
-                          aPostUpdateExeRelPathPrefix = "") {
+                          aPostUpdateExeRelPathPrefix = "",
+                          aSetupActiveUpdate = true) {
   debugDump("start - updater test setup");
   let updatesPatchDir = getUpdatesPatchDir();
   if (!updatesPatchDir.exists()) {
     updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
   }
   // Copy the mar that will be applied
   let mar = getTestDirFile(aMarFile);
   mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_MAR);
@@ -2966,17 +2890,19 @@ function setupUpdaterTest(aMarFile, aPos
             }
           });
         }
       });
     }
     debugDump("finish - setup test directory: " + aTestDir.relPathDir);
   });
 
-  setupActiveUpdate();
+  if (aSetupActiveUpdate) {
+    setupActiveUpdate();
+  }
 
   if (aPostUpdateAsync !== null) {
     createUpdaterINI(aPostUpdateAsync, aPostUpdateExeRelPathPrefix);
   }
 
   debugDump("finish - updater test setup");
   setupAppFilesAsync();
 }
@@ -3990,17 +3916,19 @@ function getLaunchScript() {
 
 /**
  * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so
  * xpcshell tests can run in parallel and to keep the environment clean.
  */
 function adjustGeneralPaths() {
   let dirProvider = {
     getFile: function AGP_DP_getFile(aProp, aPersistent) {
-      aPersistent.value = true;
+      // Set the value of persistent to false so when this directory provider is
+      // unregistered it will revert back to the original provider.
+      aPersistent.value = false;
       switch (aProp) {
         case NS_GRE_DIR:
           return getApplyDirFile(DIR_RESOURCES, true);
         case NS_GRE_BIN_DIR:
           return getApplyDirFile(DIR_MACOS, true);
         case XRE_EXECUTABLE_FILE:
           return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true);
         case XRE_UPDATE_ROOT_DIR:
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
@@ -12,21 +12,17 @@ const WindowWatcher = {
         Assert.equal(aTitle, title,
                      "the ui string for title" + MSG_SHOULD_EQUAL);
         let text = gUpdateBundle.formatStringFromName("updaterIOErrorMsg",
                                                       [Services.appinfo.name,
                                                        Services.appinfo.name], 2);
         Assert.equal(aText, text,
                      "the ui string for message" + 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);
+        executeSoon(doTestFinish);
       },
     };
   },
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowWatcher]),
 };
 
 function run_test() {
@@ -59,15 +55,8 @@ function run_test() {
   reloadUpdateManagerData();
 
   let update = gUpdateManager.activeUpdate;
   update.errorCode = WRITE_ERROR;
   let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
                  createInstance(Ci.nsIUpdatePrompt);
   prompter.showUpdateError(update);
 }
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  executeSoon(doTestFinish);
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedNoRecovery.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedNoRecovery.js
@@ -39,18 +39,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_NET_RESET,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedOffline.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedOffline.js
@@ -37,19 +37,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_OK,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
@@ -47,19 +47,10 @@ function updateCheckCompleted() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_OK,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInvalidSizeMar.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInvalidSizeMar.js
@@ -44,22 +44,18 @@ function check_test_helper_pt1_1() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_UNEXPECTED,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
-
-  // Cleaning up the active update along with reloading the update manager
-  // in doTestFinish will prevent writing the update xml files during shutdown.
-  gUpdateManager.cleanupActiveUpdate();
+  // There is a pending write to the xml files.
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadMissingMar.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadMissingMar.js
@@ -47,18 +47,18 @@ function check_test_helper_pt1_1() {
 
 /**
  * Called after the download listener onStopRequest is called.
  */
 function downloadListenerStop() {
   Assert.equal(gStatusResult, Cr.NS_ERROR_UNEXPECTED,
                "the download status result" + MSG_SHOULD_EQUAL);
   gAUS.removeDownloadListener(downloadListener);
+  // There is a pending write to the xml files.
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {
-  // The HttpServer must be stopped before calling do_test_finished
   stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
@@ -19,21 +19,13 @@ function run_test() {
   standardInit();
 
   Assert.equal(gUpdateManager.updateCount, 0,
                "the update manager updateCount attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(gUpdateManager.activeUpdate.state, STATE_DOWNLOADING,
                "the update manager activeUpdate state attribute" +
                MSG_SHOULD_EQUAL);
 
-  // Pausing the download along with reloading the update manager in
-  // doTestFinish will prevent writing the update xml files during shutdown.
+  // Pause the download early to prevent it writing the update xml files during
+  // shutdown.
   gAUS.pauseDownload();
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
   executeSoon(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
@@ -274,10 +274,10 @@ function run_test_pt11() {
 function check_test_pt11() {
   let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
   Assert.ok(!!bestUpdate,
             "there should be one update available");
   Assert.equal(bestUpdate.appVersion, "1.0",
                "the update appVersion attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(bestUpdate.displayVersion, "1.0",
                "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
-  doTestFinish();
+  stop_httpserver(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
@@ -49,18 +49,10 @@ function run_test() {
   logTestInfo("testing showUpdateError should not call getNewPrompter");
   update.errorCode = WRITE_ERROR;
   gUP.showUpdateError(update);
   // Report a successful check after the call to showUpdateError since it
   // didn't throw and otherwise it would report no tests run.
   Assert.ok(true,
             "calling showUpdateError should not attempt to open a window");
 
-  gUpdateManager.cleanupActiveUpdate();
-  executeSoon(waitForUpdateXMLFiles);
+  executeSoon(doTestFinish);
 }
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
-  doTestFinish();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateAutoPrefMigrate.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateAutoPrefMigrate.js
@@ -32,17 +32,17 @@ async function run_test() {
   await verifyPref(configFile, false);
 
   // Test that migration doesn't happen twice
   Services.prefs.setBoolPref("app.update.auto", true);
   await verifyPref(configFile, false);
 
   // If the file is deleted after migration, the default value should be
   // returned, regardless of the pref value.
-  debugDump(`about to remove config file`);
+  debugDump("about to remove config file");
   configFile.remove(false);
   Assert.ok(!configFile.exists(), "Pref file should have been removed");
   let configValue = await UpdateUtils.getAppUpdateAutoEnabled();
   Assert.equal(configValue, true, "getAppUpdateAutoEnabled should have " +
                                   "returned the default value (true)");
 
   // Setting a new value should cause the value to get written out again
   await UpdateUtils.setAppUpdateAutoEnabled(false);
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -256,21 +256,10 @@ function run_test() {
                "the first property name" + MSG_SHOULD_EQUAL);
   Assert.equal(results[0].value, "custom3 patch value",
                "the first property value" + MSG_SHOULD_EQUAL);
   Assert.equal(results[1].name, "custom4_attr",
                "the second property name" + MSG_SHOULD_EQUAL);
   Assert.equal(results[1].value, "custom4 patch value",
                "the second property value" + 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);
-}
-
-/**
- * Called after the call to waitForUpdateXMLFiles finishes.
- */
-function waitForUpdateXMLFilesFinished() {
   executeSoon(doTestFinish);
 }
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
@@ -13,58 +13,45 @@ const STATE_AFTER_STAGE = STATE_APPLIED;
 
 function run_test() {
   if (!setupTestCommon()) {
     return;
   }
 
   gTestFiles = gTestFilesCompleteSuccess;
   gTestDirs = gTestDirsCompleteSuccess;
-  setupUpdaterTest(FILE_COMPLETE_MAR);
+  setupUpdaterTest(FILE_COMPLETE_MAR, null, "", false);
 }
 
 /**
  * Called after the call to setupUpdaterTest finishes.
  */
 function setupUpdaterTestFinished() {
-  stageUpdate(false);
-}
-
-/**
- * Called after the call to stageUpdate finishes.
- */
-function stageUpdateFinished() {
-  checkPostUpdateRunningFile(false);
-  checkFilesAfterUpdateSuccess(getStageDirFile, true);
-  checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true);
-  // Change the version file to an older version to simulate installing a new
+  let patchProps = {state: STATE_AFTER_STAGE};
+  let patches = getLocalPatchString(patchProps);
+  let updateProps = {appVersion: "0.9"};
+  let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+  getUpdateLog(FILE_UPDATE_LOG).create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
+  writeStatusFile(STATE_AFTER_STAGE);
+  // Create the version file with an older version to simulate installing a new
   // version of the application while there is an update that has been staged.
   writeVersionFile("0.9");
-  // Try to switch the application to the staged application that was updated.
+  // Try to switch the application to the fake staged application.
   runUpdateUsingApp(STATE_AFTER_STAGE);
 }
 
 /**
  * Called after the call to runUpdateUsingApp finishes.
  */
 function runUpdateFinished() {
-  // Change the active update to an older version to simulate installing a new
-  // version of the application while there is an update that has been staged.
-  let patchProps = {state: STATE_AFTER_STAGE};
-  let patches = getLocalPatchString(patchProps);
-  let updateProps = {appVersion: "0.9"};
-  let updates = getLocalUpdateString(updateProps, patches);
-  getUpdatesXMLFile(true).remove(false);
-  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-  reloadUpdateManagerData();
-
   standardInit();
   checkPostUpdateRunningFile(false);
   setTestFilesAndDirsForFailure();
-  checkFilesAfterUpdateFailure(getApplyDirFile, !IS_MACOSX, false);
+  checkFilesAfterUpdateFailure(getApplyDirFile);
 
   executeSoon(waitForUpdateXMLFiles);
 }
 
 /**
  * Called after the call to waitForUpdateXMLFiles finishes.
  */
 function waitForUpdateXMLFilesFinished() {
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -152,17 +152,17 @@ nsLookAndFeel::ProcessSelectionBackgroun
   uint8_t alpha;
   nscolor resultColor = aColor;
   NS_RGB2HSV(resultColor, hue, sat, value, alpha);
   int factor = 2;
   alpha = alpha / factor;
   if (sat > 0) {
     // The color is not a shade of grey, restore the saturation taken away by
     // the transparency.
-    sat = sat * factor;
+    sat = mozilla::clamped(sat * factor, 0, 255);
   } else {
     // The color is a shade of grey, find the value that looks equivalent
     // on a white background with the given opacity.
     value = mozilla::clamped(255 - (255 - value) * factor, 0, 255);
   }
   NS_HSV2RGB(resultColor, hue, sat, value, alpha);
   return resultColor;
 }
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -329,24 +329,42 @@ nsresult nsComponentManagerImpl::Init() 
       RegisterModule(module);
     }
   }
 
   for (uint32_t i = 0; i < sExtraStaticModules->Length(); ++i) {
     RegisterModule((*sExtraStaticModules)[i]);
   }
 
-  // This needs to be called very early, before anything in nsLayoutModule is
-  // used, and before any calls are made into the JS engine.
-  nsLayoutModuleInitialize();
+  bool loadChromeManifests;
+  switch (XRE_GetProcessType()) {
+    // We are going to assume that only a select few (see below) process types
+    // want to load chrome manifests, and that any new process types will not
+    // want to load them, because they're not going to be executing JS.
+    default:
+      loadChromeManifests = false;
+      break;
 
-  bool loadChromeManifests = (XRE_GetProcessType() != GeckoProcessType_GPU &&
-                              XRE_GetProcessType() != GeckoProcessType_VR &&
-                              XRE_GetProcessType() != GeckoProcessType_RDD);
+    // XXX The check this code replaced implicitly let through all of these
+    // process types, but presumably only the default (parent) and content
+    // processes really need chrome manifests...?
+    case GeckoProcessType_Default:
+    case GeckoProcessType_Plugin:
+    case GeckoProcessType_Content:
+    case GeckoProcessType_IPDLUnitTest:
+    case GeckoProcessType_GMPlugin:
+      loadChromeManifests = true;
+      break;
+  }
+
   if (loadChromeManifests) {
+    // This needs to be called very early, before anything in nsLayoutModule is
+    // used, and before any calls are made into the JS engine.
+    nsLayoutModuleInitialize();
+
     // The overall order in which chrome.manifests are expected to be treated
     // is the following:
     // - greDir
     // - greDir's omni.ja
     // - appDir
     // - appDir's omni.ja
 
     InitializeModuleLocations();