Merge mozilla-central to beta. a=merge CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Mon, 07 May 2018 17:11:35 +0300
changeset 473211 038a427f1a3ef1d3f5160f94684341c5af4a3200
parent 473181 4632e7d90224f898dcfb675c47cacfa9784be5f5 (current diff)
parent 473210 93443d36d4bd53dba004f7b73430879f96daa681 (diff)
child 473212 d6129fd8865f6bee5e56263237375bdf6bba2ddf
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0
Merge mozilla-central to beta. a=merge CLOSED TREE
browser/base/content/test/general/benignPage.html
browser/base/content/test/general/browser_trackingUI_1.js
browser/base/content/test/general/browser_trackingUI_2.js
browser/base/content/test/general/browser_trackingUI_3.js
browser/base/content/test/general/browser_trackingUI_4.js
browser/base/content/test/general/browser_trackingUI_5.js
browser/base/content/test/general/browser_trackingUI_6.js
browser/base/content/test/general/browser_trackingUI_telemetry.js
browser/base/content/test/general/file_trackingUI_6.html
browser/base/content/test/general/file_trackingUI_6.js
browser/base/content/test/general/file_trackingUI_6.js^headers^
browser/base/content/test/general/trackingPage.html
js/src/jit-test/tests/TypedObject/atopneuteredbuffer.js
js/src/jit-test/tests/TypedObject/bug-1415313.js
js/src/jit-test/tests/TypedObject/bug1082649.js
js/src/jit-test/tests/TypedObject/inlinetransparent.js
js/src/jit-test/tests/TypedObject/opaqueatopbuffer.js
js/src/jit-test/tests/ion/inlining/TypedObject-storage-opaque.js
js/src/jit-test/tests/ion/inlining/TypedObject-storage-transparent.js
js/src/jit-test/tests/ion/inlining/TypedObject-storage-unknown.js
js/src/jit-test/tests/ion/inlining/TypedObject-storage-wrong.js
js/src/tests/non262/TypedObject/atopbuffer.js
js/src/tests/non262/TypedObject/atopbufferwithoffset.js
js/src/tests/non262/TypedObject/map-neutered-midway.js
layout/style/nsCSSPropsGenerated.inc.in
mobile/android/base/java/org/mozilla/gecko/CrashReporterActivity.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ParcelableUtils.java
taskcluster/ci/beetmover-release-source-checksums/kind.yml
--- a/browser/components/migration/tests/marionette/manifest.ini
+++ b/browser/components/migration/tests/marionette/manifest.ini
@@ -1,5 +1,5 @@
 [DEFAULT]
 run-if = buildapp == 'browser'
 
 [test_refresh_firefox.py]
-skip-if = (os == 'win' && !debug) #bug 1425323
+
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -665,17 +665,17 @@ function prompt(aBrowser, aRequest) {
           let constraints = { video: { mediaSource: type, deviceId: {exact: deviceId } } };
           chromeWin.navigator.mediaDevices.getUserMedia(constraints).then(stream => {
             if (video.deviceId != deviceId) {
               // The user has selected a different device or closed the panel
               // before getUserMedia finished.
               stream.getTracks().forEach(t => t.stop());
               return;
             }
-            video.srcObject = stream;
+            video.src = chromeWin.URL.createObjectURL(stream);
             video.stream = stream;
             doc.getElementById("webRTC-preview").hidden = false;
             video.onloadedmetadata = function(e) {
               video.play();
             };
           });
         };
         menupopup.addEventListener("command", menupopup._commandEventListener);
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-shorthand-fontfamily.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-shorthand-fontfamily.js
@@ -36,18 +36,25 @@ async function testRuleView(ruleView, no
 
   // Get the computed font family property inside the font rule view
   let propertyList = ruleView.element
     .querySelectorAll(".ruleview-propertylist");
   let fontExpander = propertyList[1].querySelectorAll(".ruleview-expander")[0];
   fontExpander.click();
 
   let rule = getRuleViewRule(ruleView, "#testElement");
-  let valueSpan = rule
-    .querySelector(".ruleview-computed .ruleview-propertyvalue");
+  let computedlist = rule.querySelectorAll(".ruleview-computed");
+  let valueSpan;
+  for (let computed of computedlist) {
+    let propertyName = computed.querySelector(".ruleview-propertyname");
+    if (propertyName.textContent == "font-family") {
+      valueSpan = computed.querySelector(".ruleview-propertyvalue");
+      break;
+    }
+  }
 
   // And verify that the tooltip gets shown on this property
   let previewTooltip = await assertShowPreviewTooltip(ruleView, valueSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
   ok(images[0].getAttribute("src")
     .startsWith("data:"), "Tooltip contains a data-uri image as expected");
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -336,16 +336,17 @@ subsuite = clipboard
 [browser_webconsole_shows_reqs_from_netmonitor.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
 [browser_webconsole_sidebar_object_expand_when_message_pruned.js]
 [browser_webconsole_sourcemap_css.js]
 [browser_webconsole_sourcemap_error.js]
 [browser_webconsole_sourcemap_invalid.js]
 [browser_webconsole_sourcemap_nosource.js]
 [browser_webconsole_split.js]
+skip-if = os == 'win' && !debug # Bug 1454123 disabled on Win for frequent failures
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
 [browser_webconsole_strict_mode_errors.js]
 [browser_webconsole_string.js]
 [browser_webconsole_time_methods.js]
--- a/devtools/shared/css/generated/mach_commands.py
+++ b/devtools/shared/css/generated/mach_commands.py
@@ -5,16 +5,17 @@
 """
 This script implements the `mach devtools-css-db` command. It runs an xpcshell
 script that uses InspectorUtils to query the CSS properties used by the browser.
 This information is used to generate the properties-db.js file.
 """
 
 import json
 import os
+import runpy
 import sys
 import string
 import subprocess
 from mozbuild import shellutil
 from mozbuild.base import (
     MozbuildObject,
     MachCommandBase,
 )
@@ -48,25 +49,22 @@ class MachCommands(MachCommandBase):
             'cssProperties': stringify(db['cssProperties']),
             'pseudoElements': stringify(db['pseudoElements'])})
 
     def get_preferences(self):
         """Get all of the preferences associated with enabling and disabling a property."""
         # The data takes the following form:
         # [ (name, prop, id, flags, pref, proptype), ... ]
         dataPath = resolve_path(self.topobjdir, 'layout/style/ServoCSSPropList.py')
-        with open(dataPath, "r") as f:
-            data = eval(f.read())
+        data = runpy.run_path(dataPath)['data']
 
         # Map this list
-        # (name, prop, id, flags, pref, proptype) => (name, pref)
         preferences = [
-            (name, pref)
-            for name, prop, id, flags, pref, proptype in data
-            if 'CSSPropFlags::Internal' not in flags and pref]
+            (p.name, p.pref) for p in data
+            if 'CSSPropFlags::Internal' not in p.flags and p.pref]
 
         return preferences
 
     def get_properties_db_from_xpcshell(self):
         """Generate the static css properties db for devtools from an xpcshell script."""
         build = MozbuildObject.from_environment()
 
         # Get the paths
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -13,24 +13,24 @@
 
 /**
  * A list of CSS Properties and their various characteristics.
  */
 exports.CSS_PROPERTIES = {
   "-moz-animation": {
     "isInherited": false,
     "subproperties": [
+      "animation-name",
       "animation-duration",
       "animation-timing-function",
       "animation-delay",
+      "animation-iteration-count",
       "animation-direction",
       "animation-fill-mode",
-      "animation-iteration-count",
-      "animation-play-state",
-      "animation-name"
+      "animation-play-state"
     ],
     "supports": [
       10
     ],
     "values": [
       "alternate",
       "alternate-reverse",
       "backwards",
@@ -341,19 +341,19 @@ exports.CSS_PROPERTIES = {
       "none",
       "unset",
       "url"
     ]
   },
   "-moz-border-end": {
     "isInherited": false,
     "subproperties": [
-      "border-inline-end-width",
+      "border-inline-end-color",
       "border-inline-end-style",
-      "border-inline-end-color"
+      "border-inline-end-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -435,21 +435,21 @@ exports.CSS_PROPERTIES = {
       "thick",
       "thin",
       "unset"
     ]
   },
   "-moz-border-image": {
     "isInherited": false,
     "subproperties": [
-      "border-image-source",
+      "border-image-outset",
+      "border-image-repeat",
       "border-image-slice",
-      "border-image-width",
-      "border-image-outset",
-      "border-image-repeat"
+      "border-image-source",
+      "border-image-width"
     ],
     "supports": [
       4
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
@@ -476,19 +476,19 @@ exports.CSS_PROPERTIES = {
       "stretch",
       "unset",
       "url"
     ]
   },
   "-moz-border-start": {
     "isInherited": false,
     "subproperties": [
-      "border-inline-start-width",
+      "border-inline-start-color",
       "border-inline-start-style",
-      "border-inline-start-color"
+      "border-inline-start-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -818,18 +818,18 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-columns": {
     "isInherited": false,
     "subproperties": [
-      "column-count",
-      "column-width"
+      "column-width",
+      "column-count"
     ],
     "supports": [],
     "values": [
       "auto",
       "inherit",
       "initial",
       "unset"
     ]
@@ -1531,24 +1531,24 @@ exports.CSS_PROPERTIES = {
       "stretch",
       "unsafe",
       "unset"
     ]
   },
   "-webkit-animation": {
     "isInherited": false,
     "subproperties": [
+      "animation-name",
       "animation-duration",
       "animation-timing-function",
       "animation-delay",
+      "animation-iteration-count",
       "animation-direction",
       "animation-fill-mode",
-      "animation-iteration-count",
-      "animation-play-state",
-      "animation-name"
+      "animation-play-state"
     ],
     "supports": [
       10
     ],
     "values": [
       "alternate",
       "alternate-reverse",
       "backwards",
@@ -1777,21 +1777,21 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-border-image": {
     "isInherited": false,
     "subproperties": [
-      "border-image-source",
+      "border-image-outset",
+      "border-image-repeat",
       "border-image-slice",
-      "border-image-width",
-      "border-image-outset",
-      "border-image-repeat"
+      "border-image-source",
+      "border-image-width"
     ],
     "supports": [
       4
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
@@ -2144,25 +2144,25 @@ exports.CSS_PROPERTIES = {
       "stretch",
       "unsafe",
       "unset"
     ]
   },
   "-webkit-mask": {
     "isInherited": false,
     "subproperties": [
-      "mask-image",
+      "mask-mode",
       "mask-repeat",
+      "mask-clip",
+      "mask-origin",
+      "mask-composite",
       "mask-position-x",
       "mask-position-y",
-      "mask-clip",
-      "mask-origin",
       "mask-size",
-      "mask-composite",
-      "mask-mode"
+      "mask-image"
     ],
     "supports": [
       4
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
@@ -2775,351 +2775,347 @@ exports.CSS_PROPERTIES = {
       "stretch",
       "unsafe",
       "unset"
     ]
   },
   "all": {
     "isInherited": false,
     "subproperties": [
-      "align-content",
-      "align-items",
-      "align-self",
-      "animation-delay",
-      "animation-direction",
-      "animation-duration",
-      "animation-fill-mode",
-      "animation-iteration-count",
-      "animation-name",
-      "animation-play-state",
-      "animation-timing-function",
-      "-moz-appearance",
-      "backface-visibility",
-      "background-attachment",
-      "background-blend-mode",
-      "background-clip",
+      "border-block-start-color",
+      "border-block-start-style",
+      "border-block-start-width",
+      "border-block-end-color",
+      "border-block-end-style",
+      "border-block-end-width",
+      "border-inline-start-color",
+      "border-inline-start-style",
+      "border-inline-start-width",
+      "border-inline-end-color",
+      "border-inline-end-style",
+      "border-inline-end-width",
+      "margin-block-start",
+      "margin-block-end",
+      "margin-inline-start",
+      "margin-inline-end",
+      "padding-block-start",
+      "padding-block-end",
+      "padding-inline-start",
+      "padding-inline-end",
+      "offset-block-start",
+      "offset-block-end",
+      "offset-inline-start",
+      "offset-inline-end",
+      "block-size",
+      "min-block-size",
+      "max-block-size",
+      "inline-size",
+      "min-inline-size",
+      "max-inline-size",
       "background-color",
       "background-image",
-      "background-origin",
       "background-position-x",
       "background-position-y",
       "background-repeat",
+      "background-attachment",
+      "background-clip",
+      "background-origin",
       "background-size",
-      "-moz-binding",
-      "block-size",
-      "border-block-end-color",
-      "border-block-end-style",
-      "border-block-end-width",
-      "border-block-start-color",
-      "border-block-start-style",
-      "border-block-start-width",
-      "border-bottom-color",
-      "border-bottom-left-radius",
-      "border-bottom-right-radius",
-      "border-bottom-style",
-      "border-bottom-width",
-      "border-collapse",
-      "border-image-outset",
-      "border-image-repeat",
-      "border-image-slice",
-      "border-image-source",
-      "border-image-width",
-      "border-inline-end-color",
-      "border-inline-end-style",
-      "border-inline-end-width",
-      "border-inline-start-color",
-      "border-inline-start-style",
-      "border-inline-start-width",
-      "border-left-color",
-      "border-left-style",
-      "border-left-width",
+      "background-blend-mode",
+      "border-top-color",
+      "border-top-style",
+      "border-top-width",
       "border-right-color",
       "border-right-style",
       "border-right-width",
-      "border-spacing",
-      "border-top-color",
+      "border-bottom-color",
+      "border-bottom-style",
+      "border-bottom-width",
+      "border-left-color",
+      "border-left-style",
+      "border-left-width",
       "border-top-left-radius",
       "border-top-right-radius",
-      "border-top-style",
-      "border-top-width",
-      "bottom",
-      "-moz-box-align",
+      "border-bottom-right-radius",
+      "border-bottom-left-radius",
       "box-decoration-break",
-      "-moz-box-direction",
-      "-moz-box-flex",
-      "-moz-box-ordinal-group",
-      "-moz-box-orient",
-      "-moz-box-pack",
-      "box-shadow",
-      "box-sizing",
-      "caption-side",
-      "caret-color",
+      "-moz-float-edge",
+      "border-image-source",
+      "border-image-outset",
+      "border-image-repeat",
+      "border-image-width",
+      "border-image-slice",
+      "display",
+      "position",
+      "float",
       "clear",
-      "clip",
-      "clip-path",
-      "clip-rule",
+      "vertical-align",
+      "overflow-clip-box-inline",
+      "overflow-clip-box-block",
+      "overflow-x",
+      "overflow-y",
+      "transition-duration",
+      "transition-timing-function",
+      "transition-property",
+      "transition-delay",
+      "animation-name",
+      "animation-duration",
+      "animation-timing-function",
+      "animation-iteration-count",
+      "animation-direction",
+      "animation-play-state",
+      "animation-fill-mode",
+      "animation-delay",
+      "scroll-snap-points-x",
+      "scroll-snap-points-y",
+      "scroll-snap-destination",
+      "scroll-snap-coordinate",
+      "transform",
+      "rotate",
+      "scale",
+      "translate",
+      "scroll-behavior",
+      "scroll-snap-type-x",
+      "scroll-snap-type-y",
+      "overscroll-behavior-x",
+      "overscroll-behavior-y",
+      "isolation",
+      "page-break-after",
+      "page-break-before",
+      "page-break-inside",
+      "resize",
+      "perspective",
+      "perspective-origin",
+      "backface-visibility",
+      "transform-box",
+      "transform-style",
+      "transform-origin",
+      "contain",
+      "-moz-appearance",
+      "-moz-binding",
+      "-moz-orient",
+      "will-change",
+      "shape-image-threshold",
+      "shape-margin",
+      "shape-outside",
+      "touch-action",
       "color",
-      "color-adjust",
-      "color-interpolation",
-      "color-interpolation-filters",
+      "column-width",
       "column-count",
       "column-fill",
-      "column-gap",
+      "column-rule-width",
       "column-rule-color",
-      "column-rule-style",
-      "column-rule-width",
       "column-span",
-      "column-width",
-      "contain",
+      "column-rule-style",
       "content",
-      "-moz-context-properties",
-      "-moz-control-character-visibility",
       "counter-increment",
       "counter-reset",
-      "cursor",
-      "display",
-      "dominant-baseline",
-      "empty-cells",
-      "fill",
-      "fill-opacity",
-      "fill-rule",
+      "opacity",
+      "box-shadow",
+      "clip",
       "filter",
-      "flex-basis",
-      "flex-direction",
-      "flex-grow",
-      "flex-shrink",
-      "flex-wrap",
-      "float",
-      "-moz-float-edge",
-      "flood-color",
-      "flood-opacity",
+      "mix-blend-mode",
       "font-family",
-      "font-feature-settings",
-      "font-kerning",
-      "font-language-override",
-      "font-optical-sizing",
+      "font-style",
+      "font-variant-caps",
+      "font-weight",
       "font-size",
       "font-size-adjust",
-      "-moz-font-smoothing-background-color",
+      "font-synthesis",
       "font-stretch",
-      "font-style",
-      "font-synthesis",
+      "font-kerning",
       "font-variant-alternates",
-      "font-variant-caps",
       "font-variant-east-asian",
       "font-variant-ligatures",
       "font-variant-numeric",
       "font-variant-position",
+      "font-feature-settings",
       "font-variation-settings",
-      "font-weight",
-      "-moz-force-broken-image-icon",
-      "grid-auto-columns",
-      "grid-auto-flow",
-      "grid-auto-rows",
-      "grid-column-end",
-      "grid-column-start",
-      "grid-row-end",
-      "grid-row-start",
-      "grid-template-areas",
-      "grid-template-columns",
-      "grid-template-rows",
-      "height",
+      "font-language-override",
+      "font-optical-sizing",
+      "-moz-osx-font-smoothing",
+      "visibility",
+      "writing-mode",
+      "text-orientation",
+      "color-adjust",
+      "image-rendering",
+      "image-orientation",
+      "border-collapse",
+      "empty-cells",
+      "caption-side",
+      "border-spacing",
+      "line-height",
+      "text-transform",
       "hyphens",
-      "image-orientation",
-      "-moz-image-region",
-      "image-rendering",
-      "ime-mode",
-      "initial-letter",
-      "inline-size",
-      "isolation",
-      "justify-content",
-      "justify-items",
-      "justify-self",
-      "left",
+      "-moz-text-size-adjust",
+      "text-indent",
+      "overflow-wrap",
+      "word-break",
+      "text-justify",
+      "text-align-last",
+      "text-align",
       "letter-spacing",
-      "lighting-color",
-      "line-height",
-      "list-style-image",
+      "word-spacing",
+      "white-space",
+      "text-shadow",
+      "text-emphasis-style",
+      "text-emphasis-position",
+      "text-emphasis-color",
+      "-moz-tab-size",
+      "-webkit-text-fill-color",
+      "-webkit-text-stroke-color",
+      "-webkit-text-stroke-width",
+      "ruby-align",
+      "ruby-position",
+      "text-combine-upright",
+      "text-rendering",
+      "-moz-control-character-visibility",
       "list-style-position",
       "list-style-type",
-      "margin-block-end",
-      "margin-block-start",
-      "margin-bottom",
-      "margin-inline-end",
-      "margin-inline-start",
-      "margin-left",
-      "margin-right",
+      "list-style-image",
+      "quotes",
+      "-moz-image-region",
       "margin-top",
-      "marker-end",
-      "marker-mid",
-      "marker-start",
-      "mask-clip",
-      "mask-composite",
-      "mask-image",
-      "mask-mode",
-      "mask-origin",
-      "mask-position-x",
-      "mask-position-y",
-      "mask-repeat",
-      "mask-size",
-      "mask-type",
-      "max-block-size",
+      "margin-right",
+      "margin-bottom",
+      "margin-left",
+      "outline-color",
+      "outline-style",
+      "outline-width",
+      "-moz-outline-radius-topleft",
+      "-moz-outline-radius-topright",
+      "-moz-outline-radius-bottomright",
+      "-moz-outline-radius-bottomleft",
+      "outline-offset",
+      "padding-top",
+      "padding-right",
+      "padding-bottom",
+      "padding-left",
+      "cursor",
+      "pointer-events",
+      "-moz-user-input",
+      "-moz-user-modify",
+      "-moz-user-focus",
+      "caret-color",
+      "top",
+      "right",
+      "bottom",
+      "left",
+      "z-index",
+      "flex-direction",
+      "flex-wrap",
+      "justify-content",
+      "align-content",
+      "align-items",
+      "justify-items",
+      "flex-grow",
+      "flex-shrink",
+      "align-self",
+      "justify-self",
+      "order",
+      "flex-basis",
+      "width",
+      "min-width",
+      "max-width",
+      "height",
+      "min-height",
       "max-height",
-      "max-inline-size",
-      "max-width",
-      "min-block-size",
-      "-moz-min-font-size-ratio",
-      "min-height",
-      "min-inline-size",
-      "min-width",
-      "mix-blend-mode",
+      "box-sizing",
       "object-fit",
       "object-position",
-      "offset-block-end",
-      "offset-block-start",
-      "offset-inline-end",
-      "offset-inline-start",
-      "opacity",
-      "order",
-      "-moz-orient",
-      "-moz-osx-font-smoothing",
-      "outline-color",
-      "outline-offset",
-      "-moz-outline-radius-bottomleft",
-      "-moz-outline-radius-bottomright",
-      "-moz-outline-radius-topleft",
-      "-moz-outline-radius-topright",
-      "outline-style",
-      "outline-width",
-      "overflow-clip-box-block",
-      "overflow-clip-box-inline",
-      "overflow-wrap",
-      "overflow-x",
-      "overflow-y",
-      "overscroll-behavior-x",
-      "overscroll-behavior-y",
-      "padding-block-end",
-      "padding-block-start",
-      "padding-bottom",
-      "padding-inline-end",
-      "padding-inline-start",
-      "padding-left",
-      "padding-right",
-      "padding-top",
-      "page-break-after",
-      "page-break-before",
-      "page-break-inside",
-      "paint-order",
-      "perspective",
-      "perspective-origin",
-      "pointer-events",
-      "position",
-      "quotes",
-      "resize",
-      "right",
-      "rotate",
+      "grid-row-start",
+      "grid-row-end",
+      "grid-auto-rows",
+      "grid-template-rows",
+      "grid-column-start",
+      "grid-column-end",
+      "grid-auto-columns",
+      "grid-template-columns",
+      "grid-auto-flow",
+      "grid-template-areas",
+      "column-gap",
       "row-gap",
-      "ruby-align",
-      "ruby-position",
-      "scale",
-      "scroll-behavior",
-      "scroll-snap-coordinate",
-      "scroll-snap-destination",
-      "scroll-snap-points-x",
-      "scroll-snap-points-y",
-      "scroll-snap-type-x",
-      "scroll-snap-type-y",
-      "shape-image-threshold",
-      "shape-margin",
-      "shape-outside",
+      "table-layout",
+      "text-overflow",
+      "text-decoration-line",
+      "text-decoration-style",
+      "text-decoration-color",
+      "initial-letter",
+      "ime-mode",
+      "-moz-user-select",
+      "-moz-window-dragging",
+      "-moz-window-opacity",
+      "-moz-window-transform",
+      "-moz-window-transform-origin",
+      "-moz-force-broken-image-icon",
+      "text-anchor",
+      "color-interpolation",
+      "color-interpolation-filters",
+      "fill",
+      "fill-opacity",
+      "fill-rule",
       "shape-rendering",
-      "-moz-stack-sizing",
-      "stop-color",
-      "stop-opacity",
       "stroke",
-      "stroke-dasharray",
-      "stroke-dashoffset",
+      "stroke-width",
       "stroke-linecap",
       "stroke-linejoin",
       "stroke-miterlimit",
       "stroke-opacity",
-      "stroke-width",
-      "-moz-tab-size",
-      "table-layout",
-      "text-align",
-      "text-align-last",
-      "text-anchor",
-      "text-combine-upright",
-      "text-decoration-color",
-      "text-decoration-line",
-      "text-decoration-style",
-      "text-emphasis-color",
-      "text-emphasis-position",
-      "text-emphasis-style",
-      "-webkit-text-fill-color",
-      "text-indent",
-      "text-justify",
-      "text-orientation",
-      "text-overflow",
-      "text-rendering",
-      "text-shadow",
-      "-moz-text-size-adjust",
-      "-webkit-text-stroke-color",
-      "-webkit-text-stroke-width",
-      "text-transform",
-      "top",
-      "-moz-top-layer",
-      "touch-action",
-      "transform",
-      "transform-box",
-      "transform-origin",
-      "transform-style",
-      "transition-delay",
-      "transition-duration",
-      "transition-property",
-      "transition-timing-function",
-      "translate",
-      "-moz-user-focus",
-      "-moz-user-input",
-      "-moz-user-modify",
-      "-moz-user-select",
+      "stroke-dasharray",
+      "stroke-dashoffset",
+      "clip-rule",
+      "marker-start",
+      "marker-mid",
+      "marker-end",
+      "paint-order",
+      "-moz-context-properties",
+      "dominant-baseline",
       "vector-effect",
-      "vertical-align",
-      "visibility",
-      "white-space",
-      "width",
-      "will-change",
-      "-moz-window-dragging",
-      "-moz-window-opacity",
-      "-moz-window-shadow",
-      "-moz-window-transform",
-      "-moz-window-transform-origin",
-      "word-break",
-      "word-spacing",
-      "writing-mode",
-      "z-index"
+      "stop-color",
+      "stop-opacity",
+      "flood-color",
+      "flood-opacity",
+      "lighting-color",
+      "mask-type",
+      "clip-path",
+      "mask-mode",
+      "mask-repeat",
+      "mask-position-x",
+      "mask-position-y",
+      "mask-clip",
+      "mask-origin",
+      "mask-size",
+      "mask-composite",
+      "mask-image",
+      "-moz-box-align",
+      "-moz-box-direction",
+      "-moz-box-flex",
+      "-moz-box-orient",
+      "-moz-box-pack",
+      "-moz-stack-sizing",
+      "-moz-box-ordinal-group"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
       "unset"
     ]
   },
   "animation": {
     "isInherited": false,
     "subproperties": [
+      "animation-name",
       "animation-duration",
       "animation-timing-function",
       "animation-delay",
+      "animation-iteration-count",
       "animation-direction",
       "animation-fill-mode",
-      "animation-iteration-count",
-      "animation-play-state",
-      "animation-name"
+      "animation-play-state"
     ],
     "supports": [
       10
     ],
     "values": [
       "alternate",
       "alternate-reverse",
       "backwards",
@@ -3279,24 +3275,24 @@ exports.CSS_PROPERTIES = {
       "unset",
       "visible"
     ]
   },
   "background": {
     "isInherited": false,
     "subproperties": [
       "background-color",
-      "background-image",
+      "background-position-x",
+      "background-position-y",
       "background-repeat",
       "background-attachment",
-      "background-clip",
+      "background-image",
+      "background-size",
       "background-origin",
-      "background-position-x",
-      "background-position-y",
-      "background-size"
+      "background-clip"
     ],
     "supports": [
       2,
       4
     ],
     "values": [
       "COLOR",
       "-moz-element",
@@ -3570,33 +3566,33 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border": {
     "isInherited": false,
     "subproperties": [
+      "border-top-color",
+      "border-top-style",
       "border-top-width",
+      "border-right-color",
+      "border-right-style",
       "border-right-width",
+      "border-bottom-color",
+      "border-bottom-style",
       "border-bottom-width",
-      "border-left-width",
-      "border-top-style",
-      "border-right-style",
-      "border-bottom-style",
+      "border-left-color",
       "border-left-style",
-      "border-top-color",
-      "border-right-color",
-      "border-bottom-color",
-      "border-left-color",
+      "border-left-width",
+      "border-image-outset",
+      "border-image-repeat",
+      "border-image-slice",
       "border-image-source",
-      "border-image-slice",
-      "border-image-width",
-      "border-image-outset",
-      "border-image-repeat"
+      "border-image-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -3620,19 +3616,19 @@ exports.CSS_PROPERTIES = {
       "thin",
       "transparent",
       "unset"
     ]
   },
   "border-block-end": {
     "isInherited": false,
     "subproperties": [
-      "border-block-end-width",
+      "border-block-end-color",
       "border-block-end-style",
-      "border-block-end-color"
+      "border-block-end-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -3714,19 +3710,19 @@ exports.CSS_PROPERTIES = {
       "thick",
       "thin",
       "unset"
     ]
   },
   "border-block-start": {
     "isInherited": false,
     "subproperties": [
-      "border-block-start-width",
+      "border-block-start-color",
       "border-block-start-style",
-      "border-block-start-color"
+      "border-block-start-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -3808,19 +3804,19 @@ exports.CSS_PROPERTIES = {
       "thick",
       "thin",
       "unset"
     ]
   },
   "border-bottom": {
     "isInherited": false,
     "subproperties": [
-      "border-bottom-width",
+      "border-bottom-color",
       "border-bottom-style",
-      "border-bottom-color"
+      "border-bottom-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -3964,21 +3960,21 @@ exports.CSS_PROPERTIES = {
       "rgba",
       "transparent",
       "unset"
     ]
   },
   "border-image": {
     "isInherited": false,
     "subproperties": [
-      "border-image-source",
+      "border-image-outset",
+      "border-image-repeat",
       "border-image-slice",
-      "border-image-width",
-      "border-image-outset",
-      "border-image-repeat"
+      "border-image-source",
+      "border-image-width"
     ],
     "supports": [
       4
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
@@ -4090,19 +4086,19 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border-inline-end": {
     "isInherited": false,
     "subproperties": [
-      "border-inline-end-width",
+      "border-inline-end-color",
       "border-inline-end-style",
-      "border-inline-end-color"
+      "border-inline-end-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -4184,19 +4180,19 @@ exports.CSS_PROPERTIES = {
       "thick",
       "thin",
       "unset"
     ]
   },
   "border-inline-start": {
     "isInherited": false,
     "subproperties": [
-      "border-inline-start-width",
+      "border-inline-start-color",
       "border-inline-start-style",
-      "border-inline-start-color"
+      "border-inline-start-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -4278,19 +4274,19 @@ exports.CSS_PROPERTIES = {
       "thick",
       "thin",
       "unset"
     ]
   },
   "border-left": {
     "isInherited": false,
     "subproperties": [
-      "border-left-width",
+      "border-left-color",
       "border-left-style",
-      "border-left-color"
+      "border-left-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -4387,19 +4383,19 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border-right": {
     "isInherited": false,
     "subproperties": [
-      "border-right-width",
+      "border-right-color",
       "border-right-style",
-      "border-right-color"
+      "border-right-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -4518,19 +4514,19 @@ exports.CSS_PROPERTIES = {
       "ridge",
       "solid",
       "unset"
     ]
   },
   "border-top": {
     "isInherited": false,
     "subproperties": [
-      "border-top-width",
+      "border-top-color",
       "border-top-style",
-      "border-top-color"
+      "border-top-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "currentColor",
       "dashed",
@@ -5041,18 +5037,18 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "columns": {
     "isInherited": false,
     "subproperties": [
-      "column-count",
-      "column-width"
+      "column-width",
+      "column-count"
     ],
     "supports": [],
     "values": [
       "auto",
       "inherit",
       "initial",
       "unset"
     ]
@@ -5502,34 +5498,34 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "font": {
     "isInherited": true,
     "subproperties": [
-      "font-family",
       "font-style",
+      "font-variant-caps",
       "font-weight",
+      "font-stretch",
       "font-size",
       "line-height",
+      "font-family",
       "font-size-adjust",
-      "font-stretch",
-      "font-feature-settings",
-      "font-language-override",
       "font-kerning",
       "font-optical-sizing",
-      "font-variation-settings",
       "font-variant-alternates",
-      "font-variant-caps",
       "font-variant-east-asian",
       "font-variant-ligatures",
       "font-variant-numeric",
-      "font-variant-position"
+      "font-variant-position",
+      "font-language-override",
+      "font-feature-settings",
+      "font-variation-settings"
     ],
     "supports": [],
     "values": [
       "-moz-button",
       "-moz-desktop",
       "-moz-dialog",
       "-moz-document",
       "-moz-field",
@@ -5727,18 +5723,18 @@ exports.CSS_PROPERTIES = {
       "style",
       "unset",
       "weight"
     ]
   },
   "font-variant": {
     "isInherited": true,
     "subproperties": [
+      "font-variant-caps",
       "font-variant-alternates",
-      "font-variant-caps",
       "font-variant-east-asian",
       "font-variant-ligatures",
       "font-variant-numeric",
       "font-variant-position"
     ],
     "supports": [],
     "values": [
       "all-petite-caps",
@@ -5948,22 +5944,22 @@ exports.CSS_PROPERTIES = {
       "initial",
       "normal",
       "unset"
     ]
   },
   "grid": {
     "isInherited": false,
     "subproperties": [
-      "grid-template-areas",
       "grid-template-rows",
       "grid-template-columns",
-      "grid-auto-flow",
+      "grid-template-areas",
       "grid-auto-rows",
-      "grid-auto-columns"
+      "grid-auto-columns",
+      "grid-auto-flow"
     ],
     "supports": [],
     "values": [
       "auto",
       "column",
       "dense",
       "fit-content",
       "inherit",
@@ -5976,18 +5972,18 @@ exports.CSS_PROPERTIES = {
       "row",
       "unset"
     ]
   },
   "grid-area": {
     "isInherited": false,
     "subproperties": [
       "grid-row-start",
+      "grid-row-end",
       "grid-column-start",
-      "grid-row-end",
       "grid-column-end"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
       "unset"
     ]
@@ -6153,19 +6149,19 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "grid-template": {
     "isInherited": false,
     "subproperties": [
-      "grid-template-areas",
       "grid-template-rows",
-      "grid-template-columns"
+      "grid-template-columns",
+      "grid-template-areas"
     ],
     "supports": [],
     "values": [
       "auto",
       "fit-content",
       "inherit",
       "initial",
       "max-content",
@@ -6480,19 +6476,19 @@ exports.CSS_PROPERTIES = {
       "initial",
       "normal",
       "unset"
     ]
   },
   "list-style": {
     "isInherited": true,
     "subproperties": [
-      "list-style-type",
+      "list-style-position",
       "list-style-image",
-      "list-style-position"
+      "list-style-type"
     ],
     "supports": [],
     "values": [
       "arabic-indic",
       "armenian",
       "bengali",
       "cambodian",
       "circle",
@@ -6772,18 +6768,18 @@ exports.CSS_PROPERTIES = {
       "initial",
       "unset"
     ]
   },
   "marker": {
     "isInherited": true,
     "subproperties": [
       "marker-start",
-      "marker-mid",
-      "marker-end"
+      "marker-end",
+      "marker-mid"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
       "none",
       "unset",
       "url"
@@ -6829,25 +6825,25 @@ exports.CSS_PROPERTIES = {
       "none",
       "unset",
       "url"
     ]
   },
   "mask": {
     "isInherited": false,
     "subproperties": [
-      "mask-image",
+      "mask-mode",
       "mask-repeat",
+      "mask-clip",
+      "mask-origin",
+      "mask-composite",
       "mask-position-x",
       "mask-position-y",
-      "mask-clip",
-      "mask-origin",
       "mask-size",
-      "mask-composite",
-      "mask-mode"
+      "mask-image"
     ],
     "supports": [
       4
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
@@ -7364,19 +7360,19 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "unset"
     ]
   },
   "outline": {
     "isInherited": false,
     "subproperties": [
-      "outline-width",
+      "outline-color",
       "outline-style",
-      "outline-color"
+      "outline-width"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "auto",
       "currentColor",
@@ -8439,19 +8435,19 @@ exports.CSS_PROPERTIES = {
       "initial",
       "none",
       "unset"
     ]
   },
   "text-decoration": {
     "isInherited": false,
     "subproperties": [
-      "text-decoration-color",
       "text-decoration-line",
-      "text-decoration-style"
+      "text-decoration-style",
+      "text-decoration-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "-moz-none",
       "blink",
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3746,26 +3746,17 @@ nsIDocument::SetHeaderData(nsAtom* aHead
     }
   }
 
   if (aHeaderField == nsGkAtoms::headerContentLanguage) {
     CopyUTF16toUTF8(aData, mContentLanguage);
   }
 
   if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
-    // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
-    // spec.
-    if (DOMStringIsNull(mLastStyleSheetSet)) {
-      // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
-      // per spec.  The idea here is that we're changing our preferred set and
-      // that shouldn't change the value of lastStyleSheetSet.  Also, we're
-      // using the Internal version so we can update the CSSLoader and not have
-      // to worry about null strings.
-      EnableStyleSheetsForSetInternal(aData, true);
-    }
+    SetPreferredStyleSheetSet(aData);
   }
 
   if (aHeaderField == nsGkAtoms::refresh) {
     // We get into this code before we have a script global yet, so get to
     // our container via mDocumentContainer.
     nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
     if (refresher) {
       // Note: using mDocumentURI instead of mBaseURI here, for consistency
@@ -6046,25 +6037,29 @@ nsIDocument::SetSelectedStyleSheetSet(co
 
   // Must update mLastStyleSheetSet before doing anything else with stylesheets
   // or CSSLoaders.
   mLastStyleSheetSet = aSheetSet;
   EnableStyleSheetsForSetInternal(aSheetSet, true);
 }
 
 void
-nsIDocument::GetLastStyleSheetSet(nsAString& aSheetSet)
-{
-  aSheetSet = mLastStyleSheetSet;
-}
-
-void
-nsIDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet)
-{
-  GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet);
+nsIDocument::SetPreferredStyleSheetSet(const nsAString& aSheetSet)
+{
+  mPreferredStyleSheetSet = aSheetSet;
+  // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
+  // spec.
+  if (DOMStringIsNull(mLastStyleSheetSet)) {
+    // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
+    // per spec.  The idea here is that we're changing our preferred set and
+    // that shouldn't change the value of lastStyleSheetSet.  Also, we're
+    // using the Internal version so we can update the CSSLoader and not have
+    // to worry about null strings.
+    EnableStyleSheetsForSetInternal(aSheetSet, true);
+  }
 }
 
 DOMStringList*
 nsIDocument::StyleSheetSets()
 {
   if (!mStyleSheetSetList) {
     mStyleSheetSetList = new nsDOMStyleSheetSetList(this);
   }
@@ -6081,32 +6076,32 @@ nsIDocument::EnableStyleSheetsForSet(con
     // non-null) or to our preferredStyleSheetSet.  And this method doesn't
     // change either of those.
     EnableStyleSheetsForSetInternal(aSheetSet, false);
   }
 }
 
 void
 nsIDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
-                                            bool aUpdateCSSLoader)
+                                             bool aUpdateCSSLoader)
 {
   BeginUpdate(UPDATE_STYLE);
   size_t count = SheetCount();
   nsAutoString title;
   for (size_t index = 0; index < count; index++) {
     StyleSheet* sheet = SheetAt(index);
     NS_ASSERTION(sheet, "Null sheet in sheet list!");
 
     sheet->GetTitle(title);
     if (!title.IsEmpty()) {
       sheet->SetEnabled(title.Equals(aSheetSet));
     }
   }
   if (aUpdateCSSLoader) {
-    CSSLoader()->SetPreferredSheet(aSheetSet);
+    CSSLoader()->DocumentStyleSheetSetChanged();
   }
   EndUpdate(UPDATE_STYLE);
 }
 
 void
 nsIDocument::GetCharacterSet(nsAString& aCharacterSet) const
 {
   nsAutoCString charset;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3259,18 +3259,31 @@ public:
   }
   mozilla::dom::VisibilityState VisibilityState() const
   {
     return mVisibilityState;
   }
 #endif
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   void SetSelectedStyleSheetSet(const nsAString& aSheetSet);
-  void GetLastStyleSheetSet(nsAString& aSheetSet);
-  void GetPreferredStyleSheetSet(nsAString& aSheetSet);
+  void GetLastStyleSheetSet(nsAString& aSheetSet)
+  {
+    aSheetSet = mLastStyleSheetSet;
+  }
+  const nsString& GetCurrentStyleSheetSet() const
+  {
+    return mLastStyleSheetSet.IsEmpty()
+      ? mPreferredStyleSheetSet
+      : mLastStyleSheetSet;
+  }
+  void SetPreferredStyleSheetSet(const nsAString&);
+  void GetPreferredStyleSheetSet(nsAString& aSheetSet)
+  {
+    aSheetSet = mPreferredStyleSheetSet;
+  }
   mozilla::dom::DOMStringList* StyleSheetSets();
   void EnableStyleSheetsForSet(const nsAString& aSheetSet);
 
   /**
    * Retrieve the location of the caret position (DOM node and character
    * offset within that node), given a point.
    *
    * @param aX Horizontal point at which to determine the caret position, in
@@ -4432,16 +4445,18 @@ protected:
   nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
   nsCOMPtr<nsIRequest> mOnloadBlocker;
 
   nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
   nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
 
   // Member to store out last-selected stylesheet set.
   nsString mLastStyleSheetSet;
+  nsString mPreferredStyleSheetSet;
+
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
 
   // We lazily calculate declaration blocks for SVG elements with mapped
   // attributes in Servo mode. This list contains all elements which need lazy
   // resolution.
   nsTHashtable<nsPtrHashKey<nsSVGElement>> mLazySVGPresElements;
 
   // Restyle root for servo's style system.
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -1,35 +1,37 @@
 # 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/.
 
 import sys
 import string
 import argparse
+import runpy
 
 # Generates a line of WebIDL with the given spelling of the property name
 # (whether camelCase, _underscorePrefixed, etc.) and the given array of
 # extended attributes.
 def generateLine(propName, extendedAttrs):
     return "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
                                                  propName)
 def generate(output, idlFilename, dataFile):
-    with open(dataFile, "r") as f:
-        propList = eval(f.read())
+    propList = runpy.run_path(dataFile)["data"]
     props = ""
-    for name, prop, id, flags, pref, proptype in propList:
-        if "CSSPropFlags::Internal" in flags:
+    for p in propList:
+        if "CSSPropFlags::Internal" in p.flags:
             continue
         # Unfortunately, even some of the getters here are fallible
         # (e.g. on nsComputedDOMStyle).
         extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
                          "SetterNeedsSubjectPrincipal=NonSystem"]
-        if pref is not "":
-            extendedAttrs.append('Pref="%s"' % pref)
+        if p.pref is not "":
+            extendedAttrs.append('Pref="%s"' % p.pref)
+
+        prop = p.method
 
         # webkit properties get a camelcase "webkitFoo" accessor
         # as well as a capitalized "WebkitFoo" alias (added here).
         if (prop.startswith("Webkit")):
             extendedAttrs.append('BindingAlias="%s"' % prop)
 
         # Generate a name with camelCase spelling of property-name (or capitalized,
         # for Moz-prefixed properties):
@@ -47,18 +49,18 @@ def generate(output, idlFilename, dataFi
         # Note that "float" will cause a property called "float" to exist due to (1)
         # in that list.
         #
         # In practice, cssFloat is the only case in which "name" doesn't contain
         # "-" but also doesn't match "prop".  So the generateLine() call will
         # cover (3) and all of (1) except "float".  If we now add an alias
         # for all the cases where "name" doesn't match "prop", that will cover
         # "float" and (2).
-        if prop != name:
-            extendedAttrs.append('BindingAlias="%s"' % name)
+        if prop != p.name:
+            extendedAttrs.append('BindingAlias="%s"' % p.name)
 
         props += generateLine(prop, extendedAttrs)
 
 
     idlFile = open(idlFilename, "r")
     idlTemplate = idlFile.read()
     idlFile.close()
 
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextComposition.h"
+#include "mozilla/TextEditor.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DragEvent.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FrameLoaderBinding.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/TabChild.h"
@@ -901,16 +902,28 @@ EventStateManager::PreHandleEvent(nsPres
     NotifyTargetUserActivation(aEvent, aTargetContent);
     break;
   default:
     break;
   }
   return NS_OK;
 }
 
+static bool
+IsTextInput(nsIContent* aContent)
+{
+  MOZ_ASSERT(aContent);
+  if (!aContent->IsElement()) {
+    return false;
+  }
+  TextEditor* textEditor =
+    aContent->AsElement()->GetTextEditorInternal();
+  return textEditor && !textEditor->IsReadonly();
+}
+
 void
 EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
                                               nsIContent* aTargetContent)
 {
   if (!aEvent->IsTrusted()) {
     return;
   }
 
@@ -924,16 +937,34 @@ EventStateManager::NotifyTargetUserActiv
     return;
   }
 
   nsIDocument* doc = node->OwnerDoc();
   if (!doc || doc->HasBeenUserActivated()) {
     return;
   }
 
+  // Don't activate if the target content of the event is contentEditable or
+  // is inside an editable document, or is a text input control. Activating
+  // due to typing/clicking on a text input would be surprising user experience.
+  if (aTargetContent->IsEditable() ||
+      IsTextInput(aTargetContent)) {
+    return;
+  }
+
+  // Don't gesture activate for key events for keys which are likely
+  // to be interaction with the browser, OS, or likely to be scrolling.
+  WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
+  if (keyEvent && (!keyEvent->PseudoCharCode() ||
+                   (keyEvent->IsControl() && !keyEvent->IsAltGraph()) ||
+                   (keyEvent->IsAlt() && !keyEvent->IsAltGraph()) ||
+                   keyEvent->IsMeta() || keyEvent->IsOS())) {
+    return;
+  }
+
   MOZ_ASSERT(aEvent->mMessage == eKeyDown   ||
              aEvent->mMessage == eMouseDown ||
              aEvent->mMessage == ePointerDown ||
              aEvent->mMessage == eTouchEnd);
   doc->NotifyUserActivation();
 }
 
 already_AddRefed<EventStateManager>
@@ -5376,19 +5407,17 @@ EventStateManager::ResetLastOverForConte
   if (aElemWrapper && aElemWrapper->mLastOverElement &&
       nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
                                             aContent)) {
     aElemWrapper->mLastOverElement = nullptr;
   }
 }
 
 void
-EventStateManager::ContentRemoved(nsIDocument* aDocument,
-                                  nsIContent* aMaybeContainer,
-                                  nsIContent* aContent)
+EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
 {
   /*
    * Anchor and area elements when focused or hovered might make the UI to show
    * the current link. We want to make sure that the UI gets informed when they
    * are actually removed from the DOM.
    */
   if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
       (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS |
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -142,18 +142,17 @@ public:
    * @return  Whether the content was able to change all states. Returns false
    *                  if a resulting DOM event causes the content node passed in
    *                  to not change states. Note, the frame for the content may
    *                  change as a result of the content state change, because of
    *                  frame reconstructions that may occur, but this does not
    *                  affect the return value.
    */
   bool SetContentState(nsIContent* aContent, EventStates aState);
-  void ContentRemoved(nsIDocument* aDocument, nsIContent* aMaybeContainer,
-                      nsIContent* aContent);
+  void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
 
   bool EventStatusOK(WidgetGUIEvent* aEvent);
 
   /**
    * EventStateManager stores IMEContentObserver while it's observing contents.
    * Following mehtods are called by IMEContentObserver when it starts to
    * observe or stops observing the content.
    */
--- a/dom/file/nsHostObjectProtocolHandler.cpp
+++ b/dom/file/nsHostObjectProtocolHandler.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHostObjectProtocolHandler.h"
 
+#include "DOMMediaStream.h"
 #include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/BlobImpl.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/MediaSource.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
@@ -36,36 +37,45 @@ using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   enum ObjectType {
     eBlobImpl,
+    eMediaStream,
     eMediaSource
   };
 
   DataInfo(BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal)
     : mObjectType(eBlobImpl)
     , mBlobImpl(aBlobImpl)
     , mPrincipal(aPrincipal)
     , mRevoked(false)
   {}
 
+  DataInfo(DOMMediaStream* aMediaStream, nsIPrincipal* aPrincipal)
+    : mObjectType(eMediaStream)
+    , mMediaStream(aMediaStream)
+    , mPrincipal(aPrincipal)
+    , mRevoked(false)
+  {}
+
   DataInfo(MediaSource* aMediaSource, nsIPrincipal* aPrincipal)
     : mObjectType(eMediaSource)
     , mMediaSource(aMediaSource)
     , mPrincipal(aPrincipal)
     , mRevoked(false)
   {}
 
   ObjectType mObjectType;
 
   RefPtr<BlobImpl> mBlobImpl;
+  RefPtr<DOMMediaStream> mMediaStream;
   RefPtr<MediaSource> mMediaSource;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCString mStack;
 
   // When a blobURL is revoked, we keep it alive for RELEASING_TIMER
   // milliseconds in order to support pending operations such as navigation,
   // download and so on.
@@ -293,19 +303,20 @@ class BlobURLsReporter final : public ns
               UNITS_COUNT,
               1,
               descString,
               aData);
         }
         continue;
       }
 
-      // Just report the path for the MediaSource.
+      // Just report the path for the DOMMediaStream or MediaSource.
       nsAutoCString path;
-      path = "media-source-urls/";
+      path = iter.UserData()->mObjectType == DataInfo::eMediaSource
+               ? "media-source-urls/" : "dom-media-stream-urls/";
       BuildPath(path, key, info, aAnonymize);
 
       NS_NAMED_LITERAL_CSTRING(desc,
         "An object URL allocated with URL.createObjectURL; the referenced "
         "data cannot be freed until all URLs for it have been explicitly "
         "invalidated with URL.revokeObjectURL.");
 
       aCallback->Callback(EmptyCString(), path, KIND_OTHER, UNITS_COUNT, 1,
@@ -614,16 +625,32 @@ nsHostObjectProtocolHandler::AddDataEntr
   rv = AddDataEntryInternal(aUri, aBlobImpl, aPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   BroadcastBlobURLRegistration(aUri, aBlobImpl, aPrincipal);
   return NS_OK;
 }
 
 /* static */ nsresult
+nsHostObjectProtocolHandler::AddDataEntry(DOMMediaStream* aMediaStream,
+                                          nsIPrincipal* aPrincipal,
+                                          nsACString& aUri)
+{
+  Init();
+
+  nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = AddDataEntryInternal(aUri, aMediaStream, aPrincipal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+/* static */ nsresult
 nsHostObjectProtocolHandler::AddDataEntry(MediaSource* aMediaSource,
                                           nsIPrincipal* aPrincipal,
                                           nsACString& aUri)
 {
   Init();
 
   nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -792,16 +819,19 @@ nsHostObjectProtocolHandler::Traverse(co
     return;
   }
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mBlobImpl");
   aCallback.NoteXPCOMChild(res->mBlobImpl);
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mMediaSource");
   aCallback.NoteXPCOMChild(res->mMediaSource);
+
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mMediaStream");
+  aCallback.NoteXPCOMChild(res->mMediaStream);
 }
 
 // -----------------------------------------------------------------------
 // Protocol handler
 
 NS_IMPL_ISUPPORTS(nsHostObjectProtocolHandler, nsIProtocolHandler,
     nsISupportsWeakReference)
 
@@ -1039,16 +1069,29 @@ NS_GetStreamForBlobURI(nsIURI* aURI, nsI
   blobImpl->CreateInputStream(aStream, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   return NS_OK;
 }
 
+nsresult
+NS_GetStreamForMediaStreamURI(nsIURI* aURI, DOMMediaStream** aStream)
+{
+  DataInfo* info = GetDataInfoFromURI(aURI);
+  if (!info || info->mObjectType != DataInfo::eMediaStream) {
+    return NS_ERROR_DOM_BAD_URI;
+  }
+
+  RefPtr<DOMMediaStream> mediaStream = info->mMediaStream;
+  mediaStream.forget(aStream);
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsFontTableProtocolHandler::NewURI(const nsACString& aSpec,
                                    const char *aCharset,
                                    nsIURI *aBaseURI,
                                    nsIURI **aResult)
 {
   nsresult rv;
   nsCOMPtr<nsIURI> uri;
@@ -1139,12 +1182,17 @@ bool IsType(nsIURI* aUri, DataInfo::Obje
   return info->mObjectType == aType;
 }
 
 bool IsBlobURI(nsIURI* aUri)
 {
   return IsType(aUri, DataInfo::eBlobImpl);
 }
 
+bool IsMediaStreamURI(nsIURI* aUri)
+{
+  return IsType(aUri, DataInfo::eMediaStream);
+}
+
 bool IsMediaSourceURI(nsIURI* aUri)
 {
   return IsType(aUri, DataInfo::eMediaSource);
 }
--- a/dom/file/nsHostObjectProtocolHandler.h
+++ b/dom/file/nsHostObjectProtocolHandler.h
@@ -18,16 +18,17 @@
 #define BLOBURI_SCHEME "blob"
 #define FONTTABLEURI_SCHEME "moz-fonttable"
 #define RTSPURI_SCHEME "rtsp"
 
 class nsIPrincipal;
 
 namespace mozilla {
 class BlobURLsReporter;
+class DOMMediaStream;
 
 namespace dom {
 class BlobImpl;
 class BlobURLRegistrationData;
 class ContentParent;
 class MediaSource;
 } // namespace dom
 } // namespace mozilla
@@ -59,16 +60,19 @@ public:
   static nsresult GenerateURIStringForBlobURL(nsIPrincipal* aPrincipal,
                                               nsACString &aUri);
 
   // Methods for managing uri->object mapping
   // AddDataEntry creates the URI with the given scheme and returns it in aUri
   static nsresult AddDataEntry(mozilla::dom::BlobImpl* aBlobImpl,
                                nsIPrincipal* aPrincipal,
                                nsACString& aUri);
+  static nsresult AddDataEntry(mozilla::DOMMediaStream* aMediaStream,
+                               nsIPrincipal* aPrincipal,
+                               nsACString& aUri);
   static nsresult AddDataEntry(mozilla::dom::MediaSource* aMediaSource,
                                nsIPrincipal* aPrincipal,
                                nsACString& aUri);
   // IPC only
   static nsresult AddDataEntry(const nsACString& aURI,
                                nsIPrincipal* aPrincipal,
                                mozilla::dom::BlobImpl* aBlobImpl);
 
@@ -107,16 +111,17 @@ public:
   NS_IMETHOD GetScheme(nsACString &result) override;
   NS_IMETHOD NewURI(const nsACString & aSpec,
                     const char *aOriginCharset,
                     nsIURI *aBaseURI,
                     nsIURI **_retval) override;
 };
 
 bool IsBlobURI(nsIURI* aUri);
+bool IsMediaStreamURI(nsIURI* aUri);
 bool IsMediaSourceURI(nsIURI* aUri);
 
 inline bool IsRtspURI(nsIURI* aUri)
 {
   bool isRtsp;
   return NS_SUCCEEDED(aUri->SchemeIs(RTSPURI_SCHEME, &isRtsp)) && isRtsp;
 }
 
@@ -131,11 +136,14 @@ NS_GetBlobForBlobURI(nsIURI* aURI, mozil
 
 extern nsresult
 NS_GetBlobForBlobURISpec(const nsACString& aSpec, mozilla::dom::BlobImpl** aBlob);
 
 extern nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
 
 extern nsresult
+NS_GetStreamForMediaStreamURI(nsIURI* aURI, mozilla::DOMMediaStream** aStream);
+
+extern nsresult
 NS_GetSourceForMediaSourceURI(nsIURI* aURI, mozilla::dom::MediaSource** aSource);
 
 #endif /* nsHostObjectProtocolHandler_h */
--- a/dom/file/nsHostObjectURI.h
+++ b/dom/file/nsHostObjectURI.h
@@ -14,18 +14,19 @@
 #include "nsIPrincipal.h"
 #include "nsISerializable.h"
 #include "nsIURIWithPrincipal.h"
 #include "nsSimpleURI.h"
 #include "nsIIPCSerializableURI.h"
 #include "nsProxyRelease.h"
 
 /**
- * These URIs refer to host objects with "blob" scheme. The underlying objects
- * can be Blobs or MediaSources.
+ * These URIs refer to host objects: Blobs, with scheme "blob",
+ * MediaStreams, with scheme "mediastream", and MediaSources, with scheme
+ * "mediasource".
  */
 class nsHostObjectURI final
   : public mozilla::net::nsSimpleURI
   , public nsIURIWithPrincipal
 {
 private:
   explicit nsHostObjectURI(nsIPrincipal* aPrincipal)
     : mozilla::net::nsSimpleURI()
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2092,17 +2092,18 @@ void HTMLMediaElement::SelectResource()
       mLoadingSrc = uri;
       mLoadingSrcTriggeringPrincipal = mSrcAttrTriggeringPrincipal;
       DDLOG(DDLogCategory::Property,
             "loading_src",
             nsCString(NS_ConvertUTF16toUTF8(src)));
       mMediaSource = mSrcMediaSource;
       DDLINKCHILD("mediasource", mMediaSource.get());
       UpdatePreloadAction();
-      if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE && !mMediaSource) {
+      if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
+          !IsMediaStreamURI(mLoadingSrc) && !mMediaSource) {
         // preload:none media, suspend the load here before we make any
         // network requests.
         SuspendLoad();
         return;
       }
 
       rv = LoadResource();
       if (NS_SUCCEEDED(rv)) {
@@ -2421,17 +2422,18 @@ void HTMLMediaElement::LoadFromSourceChi
     DDLOG(DDLogCategory::Property,
           "loading_src",
           nsCString(NS_ConvertUTF16toUTF8(src)));
     mMediaSource = childSrc->GetSrcMediaSource();
     DDLINKCHILD("mediasource", mMediaSource.get());
     NS_ASSERTION(mNetworkState == NETWORK_LOADING,
                  "Network state should be loading");
 
-    if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE && !mMediaSource) {
+    if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
+        !IsMediaStreamURI(mLoadingSrc) && !mMediaSource) {
       // preload:none media, suspend the load here before we make any
       // network requests.
       SuspendLoad();
       return;
     }
 
     if (NS_SUCCEEDED(LoadResource())) {
       return;
@@ -2570,16 +2572,30 @@ HTMLMediaElement::LoadResource()
     // Clone it.
     // TODO: remove the cast by storing ChannelMediaDecoder in the URI table.
     nsresult rv = InitializeDecoderAsClone(
       static_cast<ChannelMediaDecoder*>(other->mDecoder.get()));
     if (NS_SUCCEEDED(rv))
       return rv;
   }
 
+  if (IsMediaStreamURI(mLoadingSrc)) {
+    RefPtr<DOMMediaStream> stream;
+    nsresult rv = NS_GetStreamForMediaStreamURI(mLoadingSrc, getter_AddRefs(stream));
+    if (NS_FAILED(rv)) {
+      nsAutoString spec;
+      GetCurrentSrc(spec);
+      const char16_t* params[] = { spec.get() };
+      ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
+      return MediaResult(rv, "MediaLoadInvalidURI");
+    }
+    SetupSrcMediaStreamPlayback(stream);
+    return NS_OK;
+  }
+
   if (mMediaSource) {
     MediaDecoderInit decoderInit(
       this,
       mMuted ? 0.0 : mVolume,
       mPreservesPitch,
       mPlaybackRate,
       mPreloadAction == HTMLMediaElement::PRELOAD_METADATA,
       mHasSuspendTaint,
new file mode 100644
--- /dev/null
+++ b/dom/media/test/file_autoplay_policy_key_blacklist.html
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+  <title>Autoplay policy window</title>
+  <style>
+    video {
+      width: 50%;
+      height: 50%;
+    }
+    :focus {
+      background-color: blue;
+    }
+  </style>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
+  <script type="text/javascript" src="AutoplayTestUtils.js"></script>
+</head>
+
+<body>
+  <div id="x">This is a div with id=x.</div>
+  <pre id="test">
+      <input type="text" id="text-input"/>
+      <script>
+
+        window.ok = window.opener.ok;
+        window.is = window.opener.is;
+        window.info = window.opener.info;
+
+        // Keys that are expected to be not considered interaction with the page, and
+        // so not gesture activate the document.
+        let blacklistKeyPresses = [
+          "Tab",
+          "CapsLock",
+          "NumLock",
+          "ScrollLock",
+          "FnLock",
+          "Meta",
+          "OS",
+          "Hyper",
+          "Super",
+          "ContextMenu",
+          "ArrowUp",
+          "ArrowDown",
+          "ArrowLeft",
+          "ArrowRight",
+          "PageUp",
+          "PageDown",
+          "Home",
+          "End",
+          "Backspace",
+          "Fn",
+          "Alt",
+          "AltGraph",
+          "Control",
+          "Shift",
+          "Escape",
+        ];
+
+        let modifiedKeys = [
+          { key: "c", modifiers: { ctrlKey: true } },
+          { key: "V", modifiers: { ctrlKey: true, shiftKey: true } },
+          { key: "a", modifiers: { altKey: true } },
+          { key: "KEY_ArrowRight", modifiers: { metaKey: true } },
+          { key: "KEY_ArrowRight", modifiers: { altKey: true } },
+        ];
+
+        async function sendInput(element, name, input) {
+          synthesizeMouseAtCenter(input, {});
+          let played = await element.play().then(() => true, () => false);
+          ok(!played, "Clicking " + name + " should not activate document and should not unblock play");
+
+          synthesizeCompositionChange({
+            composition: {
+              string: "\u30E9\u30FC\u30E1\u30F3",
+              clauses: [
+                { length: 4, attr: COMPOSITION_ATTR_RAW_CLAUSE }
+              ]
+            },
+            caret: { start: 4, length: 0 }
+          });
+          synthesizeComposition({ type: "compositioncommitasis" });
+          played = await element.play().then(() => true, () => false);
+          ok(!played, "Entering text to " + name + " via IME should not activate document and should not unblock play");
+
+          input.focus();
+          sendString("ascii text");
+          played = await element.play().then(() => true, () => false);
+          ok(!played, "Entering ASCII text into " + name + " should not activate document and should not unblock play");
+
+          input.blur();
+        }
+
+        async function testAutoplayKeyBlacklist(testCase, parent_window) {
+          let element = document.createElement("video");
+          element.preload = "auto";
+          element.src = "short.mp4";
+          document.body.appendChild(element);
+
+          await once(element, "loadedmetadata");
+
+          let played = await element.play().then(() => true, () => false);
+          is(played, false, "Document should start out not activated, with playback blocked.");
+
+          // Try pressing all the keys in the blacklist, then playing.
+          // Document should not be activated, so play should fail.
+
+          for (let key of blacklistKeyPresses) {
+            document.body.focus();
+            synthesizeKey("KEY_" + key);
+            played = await element.play().then(() => true, () => false);
+            is(played, false, "Key " + key + " should not activate document and should not unblock play");
+          }
+
+          // Try pressing some keys with modifiers.
+          let keyNames = (m) => Object.keys(m).join("+");
+          for (let x of modifiedKeys) {
+            document.body.focus();
+            synthesizeKey(x.key, x.modifiers);
+            played = await element.play().then(() => true, () => false);
+            is(played, false, "Key (" + x.key + "+" + keyNames(x.modifiers) + ") should not activate document and should not unblock play");
+          }
+
+          // Test that clicking/typing into an input element doesn't activate.
+          let input = document.getElementById("text-input");
+          await sendInput(element, "input", input);
+
+          // Test that clicking/typing into a contentEditable div element doesn't activate.
+          let div = document.getElementById("x");
+          div.contentEditable = "true";
+          await sendInput(element, "contentEditable div", div);
+          div.contentEditable = "false";
+
+          // Test that clicking/typing into a div inside a designMode document doesn't activate.
+          document.designMode = "on";
+          await sendInput(element, "div in designMode=on", div);
+          document.designMode = "off";
+
+          // Try pressing a key not in the blacklist, then playing.
+          // Document should be activated, and media should play.
+
+          is(document.activeElement, document.body, "Focus needs to be the document, not an editable or text control.");
+          synthesizeKey(" ");
+          played = await element.play().then(() => true, () => false);
+          is(played, true, "Space key should activate document and should unblock play");
+
+          removeNodeAndSource(element);
+        }
+
+        nextWindowMessage().then(
+          async (event) => {
+            try {
+              await testAutoplayKeyBlacklist(event.data, event.source);
+            } catch (e) {
+              ok(false, "Caught exception " + e + " " + e.message + " " + e.stackTrace);
+            }
+            event.source.postMessage("done", "*");
+          });
+
+      </script>
+    </pre>
+</body>
+
+</html>
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -433,16 +433,17 @@ support-files =
   detodos-short.opus
   detodos-short.opus^headers^
   dirac.ogg
   dirac.ogg^headers^
   dynamic_resource.sjs
   eme.js
   file_access_controls.html
   file_autoplay_policy_eventdown_activation.html
+  file_autoplay_policy_key_blacklist.html
   file_autoplay_policy_unmute_pauses.html
   file_autoplay_policy_activation_window.html
   file_autoplay_policy_activation_frame.html
   file_autoplay_policy_play_before_loadedmetadata.html
   flac-s24.flac
   flac-s24.flac^headers^
   flac-noheader-s16.flac
   flac-noheader-s16.flac^headers^
@@ -692,16 +693,18 @@ skip-if = true # bug 475110 - disabled s
 [test_autoplay_contentEditable.html]
 skip-if = android_version == '15' || android_version == '17' || android_version == '22' # android(bug 1232305, bug 1232318, bug 1372457)
 [test_autoplay_policy.html]
 skip-if = android_version == '23' # bug 1424903
 [test_autoplay_policy_activation.html]
 skip-if = android_version == '23' # bug 1424903
 [test_autoplay_policy_eventdown_activation.html]
 skip-if = android_version == '23' # bug 1424903
+[test_autoplay_policy_key_blacklist.html]
+skip-if = android_version == '23' # bug 1424903
 [test_autoplay_policy_unmute_pauses.html]
 skip-if = android_version == '23' # bug 1424903
 [test_autoplay_policy_play_before_loadedmetadata.html]
 skip-if = android_version == '23' # bug 1424903
 [test_buffered.html]
 skip-if = android_version == '15' || android_version == '22' # bug 1308388, android(bug 1232305)
 [test_bug448534.html]
 [test_bug463162.xhtml]
@@ -1125,16 +1128,19 @@ skip-if = toolkit == 'android' # bug 137
 [test_streams_autoplay.html]
 tags=msg capturestream
 [test_streams_capture_origin.html]
 skip-if = toolkit == 'android' # bug 1372457
 tags=msg capturestream
 [test_streams_element_capture.html]
 skip-if = toolkit == 'android' # bug 1372457
 tags=msg capturestream
+[test_streams_element_capture_createObjectURL.html]
+skip-if = android_version == '15' || android_version == '17' || (android_version == '19' && debug) # android(bug 1232305)
+tags=msg capturestream
 [test_streams_element_capture_playback.html]
 skip-if = toolkit == 'android' # android(bug 1232305)
 tags=msg capturestream
 [test_streams_element_capture_reset.html]
 skip-if = toolkit == 'android' # android(bug 1232305)
 tags=msg capturestream
 [test_streams_gc.html]
 skip-if = android_version == '15' || android_version == '17' || (android_version == '19' && debug) # android(bug 1232305)
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_autoplay_policy_key_blacklist.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+  <title>Autoplay policy test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+  <script type="text/javascript" src="AutoplayTestUtils.js"></script>
+</head>
+
+<body>
+  <pre id="test">
+      <script>
+
+        // Tests that keypresses for non-printable characters,
+        // and mouse/keyboard interaction with editable elements,
+        // don't gesture activate documents, and don't unblock
+        // audible autoplay.
+
+        gTestPrefs.push(["media.autoplay.enabled", false],
+          ["media.autoplay.enabled.user-gestures-needed", true]);
+
+        SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => {
+          runTest();
+        });
+
+        let child_url = "file_autoplay_policy_key_blacklist.html";
+
+        async function runTest() {
+          // Run test in a new window, to ensure its user gesture
+          // activation state isn't tainted by preceeding tests.
+          let child = window.open(child_url, "", "width=500,height=500");
+          await once(child, "load");
+          child.postMessage("run test", window.origin);
+          let result = await nextWindowMessage();
+          child.close();
+          SimpleTest.finish();
+        }
+
+        SimpleTest.waitForExplicitFinish();
+
+      </script>
+    </pre>
+</body>
+
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_streams_element_capture_createObjectURL.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that a MediaStream captured from one element plays back in another</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var manager = new MediaTestManager;
+
+function checkDrawImage(vout) {
+  var canvas = document.createElement("canvas");
+  var ctx = canvas.getContext("2d");
+  ctx.drawImage(vout, 0, 0);
+  var imgData = ctx.getImageData(0, 0, 1, 1);
+  is(imgData.data[3], 255, "Check video frame pixel has been drawn");
+}
+
+function isGreaterThanOrEqualEps(a, b, msg) {
+  ok(a >= b - 0.01,
+     "Got " + a + ", expected at least " + b + "; " + msg);
+}
+
+function startTest(test, token) {
+  manager.started(token);
+
+  var v = document.createElement('video');
+  var vout = document.createElement('video');
+  vout.token = token;
+
+  v.src = test.name;
+  v.preload = "metadata"
+  var stream;
+
+  var checkEnded = function() {
+    is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
+    if (test.duration) {
+      isGreaterThanOrEqualEps(vout.currentTime, test.duration,
+         test.name + " current time at end");
+    }
+    is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
+    ok(vout.ended, test.name + " checking playback has ended");
+    if (test.type.match(/^video/)) {
+      checkDrawImage(vout);
+    }
+    vout.remove();
+    URL.revokeObjectURL(vout.src);
+    manager.finished(vout.token);
+  };
+  vout.addEventListener("ended", checkEnded);
+
+  document.body.appendChild(vout);
+  v.onloadedmetadata = function () {
+    stream = v.mozCaptureStreamUntilEnded();
+    is(stream.currentTime, 0, test.name + " stream initial currentTime");
+    vout.src = URL.createObjectURL(stream);
+    v.play();
+    vout.play();
+  };
+}
+
+SpecialPowers.pushPrefEnv(
+  { "set": [["privacy.reduceTimerPrecision", false]]},
+  function() {
+    manager.runTests([getPlayableVideo(gSmallTests)], startTest);
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/test/test_streams_individual_pause.html
+++ b/dom/media/test/test_streams_individual_pause.html
@@ -26,18 +26,19 @@ async function startTest() {
   try {
     // This test expects fake devices so that the video color will change
     // over time, explicitly request fakes.
     await pushGetUserMediaTestPrefs({fakeAudio: true, fakeVideo: true});
     let stream = await navigator.mediaDevices.getUserMedia({video: true});
     let video1 = document.getElementById('video1');
     let video2 = document.getElementById('video2');
 
-    video1.srcObject = stream;
-    video2.srcObject = stream;
+    let src = URL.createObjectURL(stream);
+    video1.src = src;
+    video2.src = src;
 
     video1.onplaying = () => video1.pause();
 
     let v1PausedImageData;
     let v2PausedImageData;
 
     video1.onpause = function() {
       v1PausedImageData = getVideoImagePixelData(video1);
--- a/dom/media/test/test_video_dimensions.html
+++ b/dom/media/test/test_video_dimensions.html
@@ -49,17 +49,17 @@ var startTest = function(test, token) {
 
     numVideoElementsFinished += 1;
     if (v === v1) {
       removeNodeAndSource(v1);
       v2.load();
     }
 
     if (v === v2) {
-      vout.srcObject = v2.mozCaptureStreamUntilEnded();
+      vout.src = URL.createObjectURL(v2.mozCaptureStreamUntilEnded());
       v2.play();
       vout.play();
     }
 
     if (numVideoElementsFinished === 3) {
       removeNodeAndSource(v2);
       removeNodeAndSource(vout);
       manager.finished(token);
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -59,16 +59,27 @@ URL::CreateObjectURL(const GlobalObject&
   if (NS_IsMainThread()) {
     URLMainThread::CreateObjectURL(aGlobal, aBlob, aResult, aRv);
   } else {
     URLWorker::CreateObjectURL(aGlobal, aBlob, aResult, aRv);
   }
 }
 
 void
+URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
+                     nsAString& aResult, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  DeprecationWarning(aGlobal, nsIDocument::eURLCreateObjectURL_MediaStream);
+
+  URLMainThread::CreateObjectURL(aGlobal, aStream, aResult, aRv);
+}
+
+void
 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
                      nsAString& aResult, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   URLMainThread::CreateObjectURL(aGlobal, aSource, aResult, aRv);
 }
 
 void
--- a/dom/url/URL.h
+++ b/dom/url/URL.h
@@ -14,16 +14,17 @@
 #include "nsWrapperCache.h"
 
 class nsISupports;
 class nsIURI;
 
 namespace mozilla {
 
 class ErrorResult;
+class DOMMediaStream;
 
 namespace dom {
 
 class Blob;
 class MediaSource;
 class GlobalObject;
 
 class URL : public URLSearchParamsObserver
@@ -56,16 +57,20 @@ public:
                     const nsAString& aBase, ErrorResult& aRv);
 
 
   static void
   CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
                   nsAString& aResult, ErrorResult& aRv);
 
   static void
+  CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
+                  nsAString& aResult, ErrorResult& aRv);
+
+  static void
   CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
                   nsAString& aResult, ErrorResult& aRv);
 
   static void
   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
                   ErrorResult& aRv);
 
   static bool
--- a/dom/url/URLMainThread.cpp
+++ b/dom/url/URLMainThread.cpp
@@ -13,16 +13,44 @@
 #include "nsHostObjectProtocolHandler.h"
 #include "nsIURL.h"
 #include "nsIURIMutator.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace dom {
 
+namespace {
+
+template<typename T>
+void
+CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject,
+                        nsAString& aResult, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  if (NS_WARN_IF(!global)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal =
+    nsContentUtils::ObjectPrincipal(aGlobal.Get());
+
+  nsAutoCString url;
+  aRv = nsHostObjectProtocolHandler::AddDataEntry(aObject, principal, url);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  global->RegisterHostObjectURI(url);
+  CopyASCIItoUTF16(url, aResult);
+}
+
+} // anonymous namespace
+
 /* static */ already_AddRefed<URLMainThread>
 URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
                            const Optional<nsAString>& aBase, ErrorResult& aRv)
 {
   if (aBase.WasPassed()) {
     return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv);
   }
 
@@ -67,34 +95,26 @@ URLMainThread::Constructor(nsISupports* 
   return url.forget();
 }
 
 /* static */ void
 URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
                                nsAString& aResult, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
-  if (NS_WARN_IF(!global)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
+  CreateObjectURLInternal(aGlobal, aBlob.Impl(), aResult, aRv);
+}
 
-  nsCOMPtr<nsIPrincipal> principal =
-    nsContentUtils::ObjectPrincipal(aGlobal.Get());
-
-  nsAutoCString url;
-  aRv = nsHostObjectProtocolHandler::AddDataEntry(aBlob.Impl(), principal, url);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  global->RegisterHostObjectURI(url);
-  CopyASCIItoUTF16(url, aResult);
+/* static */ void
+URLMainThread::CreateObjectURL(const GlobalObject& aGlobal,
+                               DOMMediaStream& aStream,
+                               nsAString& aResult, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  CreateObjectURLInternal(aGlobal, &aStream, aResult, aRv);
 }
 
 /* static */ void
 URLMainThread::CreateObjectURL(const GlobalObject& aGlobal,
                                MediaSource& aSource,
                                nsAString& aResult, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/url/URLMainThread.h
+++ b/dom/url/URLMainThread.h
@@ -28,16 +28,20 @@ public:
   Constructor(nsISupports* aParent, const nsAString& aURL, nsIURI* aBase,
               ErrorResult& aRv);
 
   static void
   CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
                   nsAString& aResult, ErrorResult& aRv);
 
   static void
+  CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
+                  nsAString& aResult, ErrorResult& aRv);
+
+  static void
   CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
                   nsAString& aResult, ErrorResult& aRv);
 
   static void
   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
                   ErrorResult& aRv);
 
   static bool
--- a/dom/webidl/URL.webidl
+++ b/dom/webidl/URL.webidl
@@ -1,16 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  *
  * The origins of this IDL file are
  * http://url.spec.whatwg.org/#api
  * http://dev.w3.org/2006/webapi/FileAPI/#creating-revoking
+ * http://dev.w3.org/2011/webrtc/editor/getusermedia.html#url
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Constructor(USVString url, optional USVString base),
  Exposed=(Window,Worker,WorkerDebugger)]
 interface URL {
@@ -39,16 +40,18 @@ interface URL {
 
   USVString toJSON();
 };
 
 partial interface URL {
   [Throws]
   static DOMString createObjectURL(Blob blob);
   [Throws]
+  static DOMString createObjectURL(MediaStream stream);
+  [Throws]
   static void revokeObjectURL(DOMString url);
   [ChromeOnly, Throws]
   static boolean isValidURL(DOMString url);
 };
 
 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html
 partial interface URL {
   [Throws]
--- a/dom/xul/nsXULContentSink.cpp
+++ b/dom/xul/nsXULContentSink.cpp
@@ -274,39 +274,20 @@ XULContentSinkImpl::GetTarget()
 nsresult
 XULContentSinkImpl::Init(nsIDocument* aDocument,
                          nsXULPrototypeDocument* aPrototype)
 {
     NS_PRECONDITION(aDocument != nullptr, "null ptr");
     if (! aDocument)
         return NS_ERROR_NULL_POINTER;
 
-    nsresult rv;
-
     mDocument    = do_GetWeakReference(aDocument);
     mPrototype   = aPrototype;
 
     mDocumentURL = mPrototype->GetURI();
-
-    // XXX this presumes HTTP header info is already set in document
-    // XXX if it isn't we need to set it here...
-    // XXXbz not like GetHeaderData on the proto doc _does_ anything....
-    nsAutoString preferredStyle;
-    rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle,
-                                   preferredStyle);
-    if (NS_FAILED(rv)) return rv;
-
-    if (!preferredStyle.IsEmpty()) {
-        aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
-                                 preferredStyle);
-    }
-
-    // Set the right preferred style on the document's CSSLoader.
-    aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
-
     mNodeInfoManager = aPrototype->GetNodeInfoManager();
     if (! mNodeInfoManager)
         return NS_ERROR_UNEXPECTED;
 
     mState = eInProlog;
     return NS_OK;
 }
 
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -322,17 +322,19 @@ AsyncImagePipelineManager::ApplyAsyncIma
                                 nullptr,
                                 nullptr,
                                 &opacity,
                                 pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
                                 wr::TransformStyle::Flat,
                                 nullptr,
                                 pipeline->mMixBlendMode,
                                 nsTArray<wr::WrFilterOp>(),
-                                true);
+                                true,
+                                // This is fine to do unconditionally because we only push images here.
+                                wr::GlyphRasterSpace::Screen());
 
     LayoutDeviceRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
     if (pipeline->mScaleToSize.isSome()) {
       rect = LayoutDeviceRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
     }
 
     if (pipeline->mUseExternalImage) {
       MOZ_ASSERT(pipeline->mCurrentTexture->AsWebRenderTextureHost());
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -12,61 +12,70 @@
 namespace mozilla {
 namespace layers {
 
 StackingContextHelper::StackingContextHelper()
   : mBuilder(nullptr)
   , mScale(1.0f, 1.0f)
   , mAffectsClipPositioning(false)
   , mIsPreserve3D(false)
+  , mRasterizeLocally(false)
 {
   // mOrigin remains at 0,0
 }
 
 StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
                                              wr::DisplayListBuilder& aBuilder,
                                              const nsTArray<wr::WrFilterOp>& aFilters,
                                              const LayoutDeviceRect& aBounds,
                                              const gfx::Matrix4x4* aBoundTransform,
                                              const wr::WrAnimationProperty* aAnimation,
                                              float* aOpacityPtr,
                                              gfx::Matrix4x4* aTransformPtr,
                                              gfx::Matrix4x4* aPerspectivePtr,
                                              const gfx::CompositionOp& aMixBlendMode,
                                              bool aBackfaceVisible,
                                              bool aIsPreserve3D,
-                                             const Maybe<gfx::Matrix4x4>& aTransformForScrollData)
+                                             const Maybe<gfx::Matrix4x4>& aTransformForScrollData,
+                                             const wr::WrClipId* aClipNodeId,
+                                             bool aRasterizeLocally)
   : mBuilder(&aBuilder)
   , mScale(1.0f, 1.0f)
   , mTransformForScrollData(aTransformForScrollData)
   , mIsPreserve3D(aIsPreserve3D)
+  , mRasterizeLocally(aRasterizeLocally || aParentSC.mRasterizeLocally)
 {
   // Compute scale for fallback rendering. We don't try to guess a scale for 3d
   // transformed items
   gfx::Matrix transform2d;
   if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d)
       && !aPerspectivePtr
       && !aParentSC.mIsPreserve3D) {
     mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
     mScale = mInheritedTransform.ScaleFactors(true);
   } else {
     mInheritedTransform = aParentSC.mInheritedTransform;
     mScale = aParentSC.mScale;
   }
 
+  auto rasterSpace = mRasterizeLocally
+    ? wr::GlyphRasterSpace::Local(std::max(mScale.width, mScale.height))
+    : wr::GlyphRasterSpace::Screen();
+
   mBuilder->PushStackingContext(wr::ToLayoutRect(aBounds),
-                                nullptr,
+                                aClipNodeId,
                                 aAnimation,
                                 aOpacityPtr,
                                 aTransformPtr,
                                 aIsPreserve3D ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat,
                                 aPerspectivePtr,
                                 wr::ToMixBlendMode(aMixBlendMode),
                                 aFilters,
-                                aBackfaceVisible);
+                                aBackfaceVisible,
+                                rasterSpace);
 
   mAffectsClipPositioning =
       (aTransformPtr && !aTransformPtr->IsIdentity()) ||
       (aBounds.TopLeft() != LayoutDevicePoint());
 }
 
 StackingContextHelper::~StackingContextHelper()
 {
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -34,17 +34,19 @@ public:
                         const gfx::Matrix4x4* aBoundTransform = nullptr,
                         const wr::WrAnimationProperty* aAnimation = nullptr,
                         float* aOpacityPtr = nullptr,
                         gfx::Matrix4x4* aTransformPtr = nullptr,
                         gfx::Matrix4x4* aPerspectivePtr = nullptr,
                         const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER,
                         bool aBackfaceVisible = true,
                         bool aIsPreserve3D = false,
-                        const Maybe<gfx::Matrix4x4>& aTransformForScrollData = Nothing());
+                        const Maybe<gfx::Matrix4x4>& aTransformForScrollData = Nothing(),
+                        const wr::WrClipId* aClipNodeId = nullptr,
+                        bool aRasterizeLocally = false);
   // This version of the constructor should only be used at the root level
   // of the tree, so that we have a StackingContextHelper to pass down into
   // the RenderLayer traversal, but don't actually want it to push a stacking
   // context on the display list builder.
   StackingContextHelper();
 
   // Pops the stacking context, if one was pushed during the constructor.
   ~StackingContextHelper();
@@ -63,14 +65,15 @@ public:
 
 private:
   wr::DisplayListBuilder* mBuilder;
   gfx::Size mScale;
   gfx::Matrix mInheritedTransform;
   bool mAffectsClipPositioning;
   Maybe<gfx::Matrix4x4> mTransformForScrollData;
   bool mIsPreserve3D;
+  bool mRasterizeLocally;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_STACKINGCONTEXTHELPER_H */
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -769,34 +769,38 @@ DisplayListBuilder::PushStackingContext(
                                         const wr::WrClipId* aClipNodeId,
                                         const WrAnimationProperty* aAnimation,
                                         const float* aOpacity,
                                         const gfx::Matrix4x4* aTransform,
                                         wr::TransformStyle aTransformStyle,
                                         const gfx::Matrix4x4* aPerspective,
                                         const wr::MixBlendMode& aMixBlendMode,
                                         const nsTArray<wr::WrFilterOp>& aFilters,
-                                        bool aIsBackfaceVisible)
+                                        bool aIsBackfaceVisible,
+                                        const wr::GlyphRasterSpace& aRasterSpace)
 {
   wr::LayoutTransform matrix;
   if (aTransform) {
     matrix = ToLayoutTransform(*aTransform);
   }
   const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
   wr::LayoutTransform perspective;
   if (aPerspective) {
     perspective = ToLayoutTransform(*aPerspective);
   }
+
   const wr::LayoutTransform* maybePerspective = aPerspective ? &perspective : nullptr;
   const size_t* maybeClipNodeId = aClipNodeId ? &aClipNodeId->id : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState, Stringify(aBounds).c_str(),
       aTransform ? Stringify(*aTransform).c_str() : "none");
-  wr_dp_push_stacking_context(mWrState, aBounds, maybeClipNodeId, aAnimation, aOpacity,
-                              maybeTransform, aTransformStyle, maybePerspective,
-                              aMixBlendMode, aFilters.Elements(), aFilters.Length(), aIsBackfaceVisible);
+  wr_dp_push_stacking_context(mWrState, aBounds, maybeClipNodeId, aAnimation,
+                              aOpacity, maybeTransform, aTransformStyle,
+                              maybePerspective, aMixBlendMode,
+                              aFilters.Elements(), aFilters.Length(),
+                              aIsBackfaceVisible, aRasterSpace);
 }
 
 void
 DisplayListBuilder::PopStackingContext()
 {
   WRDL_LOG("PopStackingContext\n", mWrState);
   wr_dp_pop_stacking_context(mWrState);
 }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -261,17 +261,18 @@ public:
                            const wr::WrClipId* aClipNodeId,
                            const wr::WrAnimationProperty* aAnimation,
                            const float* aOpacity,
                            const gfx::Matrix4x4* aTransform,
                            wr::TransformStyle aTransformStyle,
                            const gfx::Matrix4x4* aPerspective,
                            const wr::MixBlendMode& aMixBlendMode,
                            const nsTArray<wr::WrFilterOp>& aFilters,
-                           bool aIsBackfaceVisible);
+                           bool aIsBackfaceVisible,
+                           const wr::GlyphRasterSpace& aRasterSpace);
   void PopStackingContext();
 
   wr::WrClipId DefineClip(const Maybe<wr::WrScrollId>& aAncestorScrollId,
                           const Maybe<wr::WrClipId>& aAncestorClipId,
                           const wr::LayoutRect& aClipRect,
                           const nsTArray<wr::ComplexClipRegion>* aComplex = nullptr,
                           const wr::WrImageMask* aMask = nullptr);
   void PushClip(const wr::WrClipId& aClipId, const DisplayItemClipChain* aParent = nullptr);
--- a/gfx/webrender_bindings/cbindgen.toml
+++ b/gfx/webrender_bindings/cbindgen.toml
@@ -25,13 +25,14 @@ postfix = "WR_FUNC"
 args = "Vertical"
 rename_args = "GeckoCase"
 
 [struct]
 derive_eq = true
 
 [enum]
 add_sentinel = true
+derive_helper_methods = true
 
 [defines]
 "target_os = windows" = "XP_WIN"
 "target_os = macos" = "XP_MACOSX"
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1572,17 +1572,18 @@ pub extern "C" fn wr_dp_push_stacking_co
                                               animation: *const WrAnimationProperty,
                                               opacity: *const f32,
                                               transform: *const LayoutTransform,
                                               transform_style: TransformStyle,
                                               perspective: *const LayoutTransform,
                                               mix_blend_mode: MixBlendMode,
                                               filters: *const WrFilterOp,
                                               filter_count: usize,
-                                              is_backface_visible: bool) {
+                                              is_backface_visible: bool,
+                                              glyph_raster_space: GlyphRasterSpace) {
     debug_assert!(unsafe { !is_in_render_thread() });
 
     let c_filters = make_slice(filters, filter_count);
     let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
         match c_filter.filter_type {
             WrFilterOpType::Blur => FilterOp::Blur(c_filter.argument),
             WrFilterOpType::Brightness => FilterOp::Brightness(c_filter.argument),
             WrFilterOpType::Contrast => FilterOp::Contrast(c_filter.argument),
@@ -1642,17 +1643,17 @@ pub extern "C" fn wr_dp_push_stacking_co
          .push_stacking_context(&prim_info,
                                 clip_node_id,
                                 ScrollPolicy::Scrollable,
                                 transform_binding,
                                 transform_style,
                                 perspective,
                                 mix_blend_mode,
                                 filters,
-                                GlyphRasterSpace::Screen);
+                                glyph_raster_space);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
     debug_assert!(unsafe { !is_in_render_thread() });
     state.frame_builder.dl_builder.pop_stacking_context();
 }
 
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -701,16 +701,61 @@ using LayoutTransform = TypedTransform3D
 struct WrFilterOp {
   WrFilterOpType filter_type;
   float argument;
   LayoutVector2D offset;
   ColorF color;
   float matrix[20];
 };
 
+union GlyphRasterSpace {
+  enum class Tag : uint32_t {
+    Local,
+    Screen,
+
+    Sentinel /* this must be last for serialization purposes. */
+  };
+
+  struct Local_Body {
+    Tag tag;
+    float _0;
+
+    bool operator==(const Local_Body& aOther) const {
+      return tag == aOther.tag &&
+             _0 == aOther._0;
+    }
+  };
+
+  struct {
+    Tag tag;
+  };
+  Local_Body local;
+
+  static GlyphRasterSpace Local(float const& a0) {
+    GlyphRasterSpace result;
+    result.local._0 = a0;
+    result.tag = Tag::Local;
+    return result;
+  }
+
+  static GlyphRasterSpace Screen() {
+    GlyphRasterSpace result;
+    result.tag = Tag::Screen;
+    return result;
+  }
+
+  bool IsLocal() const {
+    return tag == Tag::Local;
+  }
+
+  bool IsScreen() const {
+    return tag == Tag::Screen;
+  }
+};
+
 struct FontInstanceKey {
   IdNamespace mNamespace;
   uint32_t mHandle;
 
   bool operator==(const FontInstanceKey& aOther) const {
     return mNamespace == aOther.mNamespace &&
            mHandle == aOther.mHandle;
   }
@@ -1284,17 +1329,18 @@ void wr_dp_push_stacking_context(WrState
                                  const WrAnimationProperty *aAnimation,
                                  const float *aOpacity,
                                  const LayoutTransform *aTransform,
                                  TransformStyle aTransformStyle,
                                  const LayoutTransform *aPerspective,
                                  MixBlendMode aMixBlendMode,
                                  const WrFilterOp *aFilters,
                                  uintptr_t aFilterCount,
-                                 bool aIsBackfaceVisible)
+                                 bool aIsBackfaceVisible,
+                                 GlyphRasterSpace aGlyphRasterSpace)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_text(WrState *aState,
                      LayoutRect aBounds,
                      LayoutRect aClip,
                      bool aIsBackfaceVisible,
                      ColorF aColor,
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -39,17 +39,16 @@ using namespace js;
 const Class js::TypedObjectModuleObject::class_ = {
     "TypedObject",
     JSCLASS_HAS_RESERVED_SLOTS(SlotCount) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_TypedObject)
 };
 
 static const JSFunctionSpec TypedObjectMethods[] = {
     JS_SELF_HOSTED_FN("objectType", "TypeOfTypedObject", 1, 0),
-    JS_SELF_HOSTED_FN("storage", "StorageOfTypedObject", 1, 0),
     JS_FS_END
 };
 
 static void
 ReportCannotConvertTo(JSContext* cx, HandleValue fromValue, const char* toType)
 {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
                               InformalValueTypeName(fromValue), toType);
@@ -2277,106 +2276,39 @@ LengthForType(TypeDescr& descr)
 
       case type::Array:
         return descr.as<ArrayTypeDescr>().length();
     }
 
     MOZ_CRASH("Invalid kind");
 }
 
-static bool
-CheckOffset(uint32_t offset, uint32_t size, uint32_t alignment, uint32_t bufferLength)
-{
-    // Offset (plus size) must be fully contained within the buffer.
-    if (offset > bufferLength)
-        return false;
-    if (offset + size < offset)
-        return false;
-    if (offset + size > bufferLength)
-        return false;
-
-    // Offset must be aligned.
-    if ((offset % alignment) != 0)
-        return false;
-
-    return true;
-}
-
-template<typename T, typename U, typename V, typename W>
-inline bool CheckOffset(T, U, V, W) = delete;
-
 /*static*/ bool
 TypedObject::construct(JSContext* cx, unsigned int argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     MOZ_ASSERT(args.callee().is<TypeDescr>());
     Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
 
-    // Typed object constructors are overloaded in three ways, in order of
-    // precedence:
+    // Typed object constructors are overloaded in two ways:
     //
     //   new TypeObj()
-    //   new TypeObj(buffer, [offset])
     //   new TypeObj(data)
 
     // Zero argument constructor:
     if (args.length() == 0) {
         int32_t length = LengthForType(*callee);
         Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
-    // Buffer constructor.
-    if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
-        Rooted<ArrayBufferObject*> buffer(cx);
-        buffer = &args[0].toObject().as<ArrayBufferObject>();
-
-        if (callee->opaque() || buffer->isDetached()) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
-            return false;
-        }
-
-        uint32_t offset;
-        if (args.length() >= 2 && !args[1].isUndefined()) {
-            if (!args[1].isInt32() || args[1].toInt32() < 0) {
-                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
-                return false;
-            }
-
-            offset = args[1].toInt32();
-        } else {
-            offset = 0;
-        }
-
-        if (args.length() >= 3 && !args[2].isUndefined()) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
-            return false;
-        }
-
-        if (!CheckOffset(offset, callee->size(), callee->alignment(),
-                         buffer->byteLength()))
-        {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
-            return false;
-        }
-
-        Rooted<OutlineTypedObject*> obj(cx);
-        obj = OutlineTypedObject::createUnattached(cx, callee, LengthForType(*callee));
-        if (!obj)
-            return false;
-
-        obj->attach(cx, *buffer, offset);
-        args.rval().setObject(*obj);
-        return true;
-    }
-
     // Data constructor.
     if (args[0].isObject()) {
         // Create the typed object.
         int32_t length = LengthForType(*callee);
         Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
         if (!obj)
             return false;
 
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -901,43 +901,16 @@ function ArrayShorthand(...dims) {
     ThrowTypeError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   var accum = this;
   for (var i = dims.length - 1; i >= 0; i--)
     accum = new AT(accum, dims[i]);
   return accum;
 }
 
-// This is the `storage()` function defined in the spec.  When
-// provided with a *transparent* typed object, it returns an object
-// containing buffer, byteOffset, byteLength. When given an opaque
-// typed object, it returns null. Otherwise it throws.
-//
-// Warning: user exposed!
-function StorageOfTypedObject(obj) {
-  if (IsObject(obj)) {
-    if (ObjectIsOpaqueTypedObject(obj))
-      return null;
-
-    if (ObjectIsTransparentTypedObject(obj)) {
-      if (!TypedObjectIsAttached(obj))
-          ThrowTypeError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
-
-      var descr = TypedObjectTypeDescr(obj);
-      var byteLength = DESCR_SIZE(descr);
-
-      return { buffer: TypedObjectBuffer(obj),
-               byteLength,
-               byteOffset: TypedObjectByteOffset(obj) };
-    }
-  }
-
-  ThrowTypeError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-}
-
 // This is the `objectType()` function defined in the spec.
 // It returns the type of its argument.
 //
 // Warning: user exposed!
 function TypeOfTypedObject(obj) {
   if (IsObject(obj) && ObjectIsTypedObject(obj))
     return TypedObjectTypeDescr(obj);
 
--- a/js/src/jit-test/tests/TypedObject/aggregate-set-neutered.js
+++ b/js/src/jit-test/tests/TypedObject/aggregate-set-neutered.js
@@ -9,19 +9,17 @@ load(libdir + "asserts.js")
 var StructType = TypedObject.StructType;
 var uint32 = TypedObject.uint32;
 
 function main()
 {
   var Point = new StructType({ x: uint32, y: uint32 });
   var Line = new StructType({ from: Point, to: Point });
 
-  var buf = new ArrayBuffer(16);
-  var line = new Line(buf);
+  var line = new Line();
 
-  assertThrowsInstanceOf(function()
-  {
-    line.to = { x: 22,
-                get y() { detachArrayBuffer(buf); return 44; } };
-  }, TypeError, "setting into a detached buffer is bad mojo");
+  line.to = { x: 22, get y() { return 44; } };
+
+  assertEq(line.to.x, 22);
+  assertEq(line.to.y, 44);
 }
 
 main();
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/atopneuteredbuffer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Bug 976697. Check for various quirks when instantiating a typed
-// object atop a detached buffer.
-
-if (typeof TypedObject === "undefined")
-  quit();
-
-load(libdir + "asserts.js")
-
-var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
-
-function main() { // once a C programmer, always a C programmer.
-  var Uints = uint32.array(0);
-  var Unit = new StructType({});   // Empty struct type
-  var buffer = new ArrayBuffer(0); // Empty buffer
-  var p = new Unit(buffer);        // OK
-  detachArrayBuffer(buffer);
-  assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
-                         "Able to instantiate atop detached buffer");
-  assertThrowsInstanceOf(() => new Uints(buffer), TypeError,
-                         "Able to instantiate atop detached buffer");
-}
-
-main();
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/bug-1415313.js
+++ /dev/null
@@ -1,13 +0,0 @@
-if (!this.hasOwnProperty("TypedObject"))
-  quit();
-
-var Uint32Array = TypedObject.float32.array(3);
-const ONE_MINUS_EPSILON = 1 - Math.pow(2, -53);
-const f = new Float64Array([0, 0]);
-const u = new Uint32Array(f.buffer);
-const diff = function(a, b) {
-    f[1] = b;
-    u[3 - ENDIAN];
-};
-ENDIAN = 1;
-diff(1, ONE_MINUS_EPSILON)
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/bug1082649.js
+++ /dev/null
@@ -1,16 +0,0 @@
-if (typeof TypedObject === "undefined")
-  quit();
-
-var {StructType, uint32, storage} = TypedObject;
-var S = new StructType({f: uint32, g: uint32});
-function main() {
-  var s = new S({f: 22, g: 44});
-  detachArrayBuffer(storage(s).buffer);
-  print(storage(s).byteOffset);
-}
-try {
-    main();
-    assertEq(true, false);
-} catch (e) {
-    assertEq(e instanceof TypeError, true);
-}
--- a/js/src/jit-test/tests/TypedObject/bug1103273-2.js
+++ b/js/src/jit-test/tests/TypedObject/bug1103273-2.js
@@ -1,18 +1,18 @@
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
 var Vec3u16Type = TypedObject.uint16.array(3);
 
 function foo() {
     var x = 0;
     for (var i = 0; i < 3; i++) {
-        var obj = new Vec3u16Type;
-        var buf = TypedObject.storage(obj).buffer;
+        var obj = new Uint16Array(3);
+        var buf = obj.buffer;
         var arr = new Uint8Array(buf, 3);
         arr[0] = i + 1;
         arr[1] = i + 2;
         arr[2] = i + 3;
         for (var j = 0; j < arr.length; j++) {
             minorgc();
             x += arr[j];
         }
--- a/js/src/jit-test/tests/TypedObject/function-names.js
+++ b/js/src/jit-test/tests/TypedObject/function-names.js
@@ -1,8 +1,7 @@
 
 if (typeof TypedObject === "undefined")
     quit();
 
 // Make sure some builtin TypedObject functions are given sensible names.
 assertEq(TypedObject.ArrayType.name, "ArrayType");
 assertEq(TypedObject.StructType.name, "StructType");
-assertEq(TypedObject.storage.name, "storage");
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/inlinetransparent.js
+++ /dev/null
@@ -1,35 +0,0 @@
-if (!this.hasOwnProperty("TypedObject"))
-    quit();
-
-var TO = TypedObject;
-
-var PointType = new TO.StructType({x: TO.int32, y: TO.int32});
-var LineType = new TO.StructType({from: PointType, to: PointType});
-
-function testBasic(how) {
-    var line = new LineType();
-    var from = line.from;
-    var to = line.to;
-    TO.storage(to).buffer.expando = "hello";
-    var dataview = new DataView(TO.storage(from).buffer);
-    line.from.x = 12;
-    line.to.x = 3;
-    if (how == 1)
-        minorgc();
-    else if (how == 2)
-	gc();
-    assertEq(from.x, 12);
-    assertEq(from.y, 0);
-    assertEq(to.x, 3);
-    assertEq(to.y, 0);
-    assertEq(TO.storage(to).byteOffset, 8);
-    dataview.setInt32(8, 10, true);
-    assertEq(to.x, 10);
-    assertEq(TO.storage(line).buffer.expando, "hello");
-}
-for (var i = 0; i < 5; i++)
-    testBasic(0);
-for (var i = 0; i < 5; i++)
-    testBasic(1);
-for (var i = 0; i < 5; i++)
-    testBasic(2);
--- a/js/src/jit-test/tests/TypedObject/neutertypedobj.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobj.js
@@ -1,32 +1,18 @@
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var {StructType, uint32, storage} = TypedObject;
+var {StructType, uint32} = TypedObject;
 var S = new StructType({f: uint32, g: uint32});
 
 function readFromS(s) {
   return s.f + s.g;
 }
 
 function main() {
   var s = new S({f: 22, g: 44});
 
   for (var i = 0; i < 10; i++)
     assertEq(readFromS(s), 66);
-
-  detachArrayBuffer(storage(s).buffer);
-
-  for (var i = 0; i < 10; i++) {
-    var ok = false;
-
-    try {
-      readFromS(s);
-    } catch (e) {
-      ok = e instanceof TypeError;
-    }
-
-    assertEq(ok, true);
-  }
 }
 
 main();
--- a/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
@@ -1,40 +1,26 @@
 // Test the case where we detach the buffer underlying a fixed-sized array.
 // This is a bit of a tricky case because we cannot (necessarily) fold
 // the detached check into the bounds check, as we obtain the bounds
 // directly from the type.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var {StructType, uint32, storage} = TypedObject;
+var {StructType, uint32} = TypedObject;
 var S = new StructType({f: uint32, g: uint32});
 var A = S.array(10);
 
 function readFrom(a) {
   return a[2].f + a[2].g;
 }
 
 function main() {
   var a = new A();
   a[2].f = 22;
   a[2].g = 44;
 
   for (var i = 0; i < 10; i++)
     assertEq(readFrom(a), 66);
-
-  detachArrayBuffer(storage(a).buffer);
-
-  for (var i = 0; i < 10; i++) {
-    var ok = false;
-
-    try {
-      readFrom(a);
-    } catch (e) {
-      ok = e instanceof TypeError;
-    }
-
-    assertEq(ok, true);
-  }
 }
 
 main();
--- a/js/src/jit-test/tests/TypedObject/neutertypedobjunsizedarray.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjunsizedarray.js
@@ -1,38 +1,24 @@
 // Test the case where we detach the buffer underlying a variable-length array.
 // Here we can fold the detached check into the bounds check.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var {StructType, uint32, storage} = TypedObject;
+var {StructType, uint32} = TypedObject;
 var S = new StructType({f: uint32, g: uint32});
 var A = S.array(10);
 
 function readFrom(a) {
   return a[2].f + a[2].g;
 }
 
 function main() {
   var a = new A();
   a[2].f = 22;
   a[2].g = 44;
 
   for (var i = 0; i < 10; i++)
     assertEq(readFrom(a), 66);
-
-  detachArrayBuffer(storage(a).buffer);
-
-  for (var i = 0; i < 10; i++) {
-    var ok = false;
-
-    try {
-      readFrom(a);
-    } catch (e) {
-      ok = e instanceof TypeError;
-    }
-
-    assertEq(ok, true);
-  }
 }
 
 main();
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/opaqueatopbuffer.js
+++ /dev/null
@@ -1,19 +0,0 @@
-if (typeof TypedObject === "undefined")
-  quit();
-
-load(libdir + "asserts.js")
-
-var {StructType, ArrayType, uint32, Object,
-     Any, storage, objectType} = TypedObject;
-
-var anArray = new Uint32Array(100);
-anArray[0] = 22;
-var buffer = anArray.buffer;
-
-var Unit = new StructType(({ f : Object, } ));
-assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
-                       "Able to instantiate opaque type atop buffer");
-
-var Units = new ArrayType(Unit, 2);
-assertThrowsInstanceOf(() => new Units(buffer), TypeError,
-                       "Able to instantiate opaque type atop buffer");
--- a/js/src/jit-test/tests/TypedObject/prototypes.js
+++ b/js/src/jit-test/tests/TypedObject/prototypes.js
@@ -2,17 +2,17 @@
 // of type objects has no effect, and that mutating
 // the prototypes of typed objects is an error.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
 load(libdir + "asserts.js");
 
-var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+var {StructType, uint32, Object, Any, objectType} = TypedObject;
 
 function main() { // once a C programmer, always a C programmer.
   var Uints = new StructType({f: uint32, g: uint32});
   var p = Uints.prototype;
   Uints.prototype = {}; // no effect
   assertEq(p, Uints.prototype);
 
   var uints = new Uints();
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/inlining/TypedObject-storage-opaque.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-/* Used to verify that the JIT resolves the transparent/opaque type
- * tests internal to storage().
- *
- * In this case the argument type is always an opaque object, so
- * ObjectIsOpaqueTypedObject resolves to true and
- * ObjectIsTransparentTypedObject resolves to false.
- *
- * Load this into the js shell with IONFLAGS=logs, then exit and run
- * iongraph.  func01 will likely be the one we want (look for calls to
- * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
- * graph for pass00).
- */
-
-if (!this.TypedObject)
-  quit();
-
-var T = TypedObject;
-
-function check(v) {
-    return T.storage(v);
-}
-
-function test() {
-    var AT = new T.ArrayType(T.Any,10);
-    var v = new AT();
-    for ( var i=0 ; i < 1000 ; i++ )
-        check(v);
-    return check(v);
-}
-
-test();
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/inlining/TypedObject-storage-transparent.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-/* Used to verify that the JIT resolves the transparent/opaque type
- * tests internal to storage().
- *
- * In this case the argument type is always a transparent object, so
- * ObjectIsOpaqueTypedObject resolves to false and
- * ObjectIsTransparentTypedObject resolves to true.
- *
- * Load this into the js shell with IONFLAGS=logs, then exit and run
- * iongraph.  func01 will likely be the one we want (look for calls to
- * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
- * graph for pass00).
- */
-
-if (!this.TypedObject)
-  quit();
-
-var T = TypedObject;
-
-function check(v) {
-    return T.storage(v);
-}
-
-function test() {
-    var AT = new T.ArrayType(T.int32, 10);
-    var v = new AT();
-    for ( var i=0 ; i < 1000 ; i++ )
-        check(v);
-    return check(v);
-}
-
-test();
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/inlining/TypedObject-storage-unknown.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-/* Used to verify that the JIT resolves the transparent/opaque type
- * tests internal to storage().
- *
- * In this case the argument type is variable and thus unknown to the
- * JIT, so both ObjectIsOpaqueTypedObject and
- * ObjectIsTransparentTypedObject are resolved as uses of the
- * "HasClass" primitive.
- *
- * Load this into the js shell with IONFLAGS=logs, then exit and run
- * iongraph.  func01 will likely be the one we want (look for calls to
- * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
- * graph for pass00).
- */
-
-if (!this.TypedObject)
-  quit();
-
-var T = TypedObject;
-
-function check(v) {
-    return T.storage(v);
-}
-
-function test() {
-    var AT = new T.ArrayType(T.int32,10);
-    var v = new Object;         // Not actually a typed object
-    var w = new AT();           // Actually a typed object
-    var a = [v,w];
-    for ( var i=0 ; i < 1000 ; i++ )
-        try { check(a[i%2]); } catch (e) {}
-    try { return check(a[1]); } catch (e) {}
-}
-
-test();
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/inlining/TypedObject-storage-wrong.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-/* Used to verify that the JIT resolves the transparent/opaque type
- * tests internal to storage().
- *
- * In this case the argument type is always a non-TypedObject, so both
- * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject
- * resolve to false.
- *
- * Load this into the js shell with IONFLAGS=logs, then exit and run
- * iongraph.  func01 will likely be the one we want (look for calls to
- * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
- * graph for pass00).
- */
-
-if (!this.TypedObject)
-  quit();
-
-var T = TypedObject;
-
-function check(v) {
-    return T.storage(v);
-}
-
-function test() {
-    var v = new Object;         // Not actually a typed object
-    for ( var i=0 ; i < 1000 ; i++ )
-        try { check(v); } catch (e) {}
-    try { return check(v); } catch (e) {}
-}
-
-test();
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -14,16 +14,17 @@
  *
  * Frederick Brooks, 'The Second-System Effect'.
  */
 
 #include "jsdate.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/Casting.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/TextUtils.h"
 
 #include <ctype.h>
 #include <math.h>
 #include <string.h>
 
@@ -46,16 +47,17 @@
 #include "vm/Time.h"
 
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 
 using mozilla::Atomic;
 using mozilla::ArrayLength;
+using mozilla::BitwiseCast;
 using mozilla::IsAsciiAlpha;
 using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::NumbersAreIdentical;
 using mozilla::Relaxed;
 
 using JS::AutoCheckCannotGC;
 using JS::ClippedTime;
@@ -1319,17 +1321,17 @@ NowAsMillis(JSContext* cx)
         if (sJitter) {
             // Calculate a random midpoint for jittering. In the browser, we are adversarial:
             // Web Content may try to calculate the midpoint themselves and use that to bypass
             // it's security. In the JS Shell, we are not adversarial, we want to jitter the
             // time to recreate the operating environment, but we do not concern ourselves
             // with trying to prevent an attacker from calculating the midpoint themselves.
             // So we use a very simple, very fast CRC with a hardcoded seed.
 
-            uint64_t midpoint = *((uint64_t*)&clamped);
+            uint64_t midpoint = BitwiseCast<uint64_t>(clamped);
             midpoint ^= 0x0F00DD1E2BAD2DED; // XOR in a 'secret'
             // MurmurHash3 internal component from
             //   https://searchfox.org/mozilla-central/rev/61d400da1c692453c2dc2c1cf37b616ce13dea5b/dom/canvas/MurmurHash3.cpp#85
             midpoint ^= midpoint >> 33;
             midpoint *= uint64_t{0xFF51AFD7ED558CCD};
             midpoint ^= midpoint >> 33;
             midpoint *= uint64_t{0xC4CEB9FE1A85EC53};
             midpoint ^= midpoint >> 33;
deleted file mode 100644
--- a/js/src/tests/non262/TypedObject/atopbuffer.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-var BUGNUMBER = 898356;
-var summary = "";
-
-var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
-
-function main() { // once a C programmer, always a C programmer.
-  print(BUGNUMBER + ": " + summary);
-
-  var Uints = new StructType({f: uint32, g: uint32});
-
-  var anArray = new Uint32Array(2);
-  anArray[0] = 22;
-  anArray[1] = 44;
-
-  var uints = new Uints(anArray.buffer);
-  assertEq(storage(uints).buffer, anArray.buffer);
-  assertEq(uints.f, 22);
-  assertEq(uints.g, 44);
-
-  uints.f++;
-  assertEq(anArray[0], 23);
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-main();
deleted file mode 100644
--- a/js/src/tests/non262/TypedObject/atopbufferwithoffset.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-var BUGNUMBER = 898356;
-var summary = "";
-
-var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
-
-function main() { // once a C programmer, always a C programmer.
-  print(BUGNUMBER + ": " + summary);
-
-  var Uints = new StructType({f: uint32, g: uint32});
-
-  var anArray = new Uint32Array(4);
-  anArray[1] = 22;
-  anArray[2] = 44;
-
-  var uints = new Uints(anArray.buffer, 4);
-  assertEq(storage(uints).buffer, anArray.buffer);
-  assertEq(uints.f, 22);
-  assertEq(uints.g, 44);
-  uints.f++;
-  assertEq(anArray[1], 23);
-
-  // No misaligned byte offsets or offsets that would stretch past the end:
-  assertThrows(() => new Uints(anArray.buffer, -4)); // negative
-  assertThrows(() => new Uints(anArray.buffer, -3)); // negative
-  assertThrows(() => new Uints(anArray.buffer, -2)); // negative
-  assertThrows(() => new Uints(anArray.buffer, -1)); // negative
-  new Uints(anArray.buffer, 0);                      // ok
-  assertThrows(() => new Uints(anArray.buffer, 1));  // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 2));  // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 3));  // misaligned
-  new Uints(anArray.buffer, 4);                      // ok
-  assertThrows(() => new Uints(anArray.buffer, 5));  // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 6));  // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 7));  // misaligned
-  new Uints(anArray.buffer, 8);                      // ok
-  assertThrows(() => new Uints(anArray.buffer, 9));  // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 10)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 11)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 12)); // would extend past end
-  assertThrows(() => new Uints(anArray.buffer, 13)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 14)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 15)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 16)); // would extend past end
-  assertThrows(() => new Uints(anArray.buffer, 17)); // misaligned
-  assertThrows(() => new Uints(anArray.buffer, 4294967292)); // overflows int
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-main();
deleted file mode 100644
--- a/js/src/tests/non262/TypedObject/map-neutered-midway.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject")||!xulRuntime.shell) -- needs TypedObject, detachArrayBuffer()
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var BUGNUMBER = 991981;
-var summary =
-  "Behavior of mapping from an array whose buffer is detached midway through " +
-  "mapping";
-
-function mapOneDimArrayOfUint8()
-{
-  var FourByteArray = TypedObject.uint8.array(4);
-  var FourByteArrayArray = FourByteArray.array(4);
-
-  var buf = new ArrayBuffer(16);
-  var arr = new FourByteArrayArray(buf);
-
-  var count = 0;
-  assertThrowsInstanceOf(function()
-  {
-    arr.map(function(v)
-    {
-      if (count++ > 0)
-        detachArrayBuffer(buf);
-      return new FourByteArray();
-    });
-  }, TypeError, "mapping of a detached object worked?");
-}
-
-function runTests()
-{
-  print(BUGNUMBER + ": " + summary);
-
-  mapOneDimArrayOfUint8();
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-  print("Tests complete");
-}
-
-runTests();
--- a/js/src/tests/non262/TypedObject/storageopaque.js
+++ b/js/src/tests/non262/TypedObject/storageopaque.js
@@ -1,34 +1,29 @@
 // |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 898356;
 var summary = "";
 
-var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+var {StructType, uint32, Object, Any, objectType} = TypedObject;
 
 function main() { // once a C programmer, always a C programmer.
   print(BUGNUMBER + ": " + summary);
 
   var Uints = new StructType({f: uint32, g: uint32});
   var uints = new Uints({f: 0, g: 1});
-  assertEq(storage(uints) != null, true);
 
   var Objects = new StructType({f: Object, g: Object});
   var objects = new Objects({f: 0, g: 1});
-  assertEq(storage(objects), null);
 
   var Anys = new StructType({f: Any, g: Any});
   var anys = new Anys({f: 0, g: 1});
-  assertEq(storage(anys), null);
 
   // Note: test that `mixed.g`, when derived from an opaque buffer,
   // remains opaque.
   var Mixed = new StructType({f: Object, g: Uints});
   var mixed = new Mixed({f: 0, g: {f: 22, g: 44}});
-  assertEq(storage(mixed), null);
   assertEq(objectType(mixed.g), Uints);
-  assertEq(storage(mixed.g), null);
 
   reportCompare(true, true);
   print("Tests complete");
 }
 
 main();
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4541,18 +4541,17 @@ PresShell::ContentRemoved(nsIContent* aC
 {
   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
   NS_PRECONDITION(aChild->OwnerDoc() == mDocument, "Unexpected document");
   nsINode* container = aChild->GetParentNode();
 
   // Notify the ESM that the content has been removed, so that
   // it can clean up any state related to the content.
 
-  mPresContext->EventStateManager()
-    ->ContentRemoved(mDocument, aChild->GetParent(), aChild);
+  mPresContext->EventStateManager()->ContentRemoved(mDocument, aChild);
 
   nsAutoCauseReflowNotifier crNotifier(this);
 
   // Call this here so it only happens for real content mutations and
   // not cases when the frame constructor calls its own methods to force
   // frame reconstruction.
   nsIContent* oldNextSibling = nullptr;
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8573,29 +8573,37 @@ nsDisplayTransform::CreateWebRenderComma
   if (!mFrame->HasPerspective()) {
     // If it has perspective, we create a new scroll data via the
     // UpdateScrollData call because that scenario is more complex. Otherwise
     // we can just stash the transform on the StackingContextHelper and
     // apply it to any scroll data that are created inside this
     // nsDisplayTransform.
     transformForScrollData = Some(GetTransform().GetMatrix());
   }
+
+  // If it looks like we're animated, we should rasterize in local space
+  // (disabling subpixel-aa and global pixel snapping)
+  bool rasterizeLocally = ActiveLayerTracker::IsStyleMaybeAnimated(
+    Frame(), eCSSProperty_transform);
+
   StackingContextHelper sc(aSc,
                            aBuilder,
                            filters,
                            LayoutDeviceRect(position, LayoutDeviceSize()),
                            &newTransformMatrix,
                            animationsId ? &prop : nullptr,
                            nullptr,
                            transformForSC,
                            nullptr,
                            gfx::CompositionOp::OP_OVER,
                            !BackfaceIsHidden(),
                            mFrame->Extend3DContext() && !mNoExtendContext,
-                           transformForScrollData);
+                           transformForScrollData,
+                           nullptr,
+                           rasterizeLocally);
 
   return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                              aManager, aDisplayListBuilder);
 }
 
 bool
 nsDisplayTransform::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                      mozilla::layers::WebRenderLayerScrollData* aLayerData)
@@ -9687,45 +9695,47 @@ nsDisplayMask::CreateWebRenderCommands(m
   bool snap;
   float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel);
 
   Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(this, aBuilder, aResources,
                                                                             aSc, aDisplayListBuilder,
                                                                             bounds);
+  Maybe<StackingContextHelper> layer;
+  const StackingContextHelper* sc = &aSc;
   if (mask) {
     auto layoutBounds = wr::ToRoundedLayoutRect(bounds);
     wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(),
         layoutBounds, nullptr, mask.ptr());
 
     // Create a new stacking context to attach the mask to, ensuring the mask is
     // applied to the aggregate, and not the individual elements.
 
     // The stacking context shouldn't have any offset.
-    layoutBounds.origin.x = 0;
-    layoutBounds.origin.y = 0;
-
-    aBuilder.PushStackingContext(/*aBounds: */ layoutBounds,
-                                 /*aClipNodeId: */ &clipId,
-                                 /*aAnimation: */ nullptr,
-                                 /*aOpacity: */ nullptr,
-                                 /*aTransform: */ nullptr,
-                                 /*aTransformStyle: */ wr::TransformStyle::Flat,
-                                 /*aPerspective: */ nullptr,
-                                 /*aMixBlendMode: */ wr::MixBlendMode::Normal,
-                                 /*aFilters: */ nsTArray<wr::WrFilterOp>(),
-                                 /*aBackfaceVisible: */ true);
-  }
-
-  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
-
-  if (mask) {
-    aBuilder.PopStackingContext();
-  }
+    bounds.MoveTo(0, 0);
+
+    layer.emplace(aSc,
+                  aBuilder,
+                  /*aFilters: */ nsTArray<wr::WrFilterOp>(),
+                  /*aBounds: */ bounds,
+                  /*aBoundTransform: */ nullptr,
+                  /*aAnimation: */ nullptr,
+                  /*aOpacity: */ nullptr,
+                  /*aTransform: */ nullptr,
+                  /*aPerspective: */ nullptr,
+                  /*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
+                  /*aBackfaceVisible: */ true,
+                  /*aIsPreserve3D: */ false,
+                  /*aTransformForScrollData: */ Nothing(),
+                  /*aClipNodeId: */ &clipId);
+    sc = layer.ptr();
+  }
+
+  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
 
   return true;
 }
 
 Maybe<nsRect>
 nsDisplayMask::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
                                        const ActiveScrolledRoot* aASR) const
 {
--- a/layout/style/GenerateCSSPropertyID.py
+++ b/layout/style/GenerateCSSPropertyID.py
@@ -1,35 +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/.
 
+import runpy
 import string
 
 def generate(output, template, dataFile):
     with open(template, "r") as f:
         template = string.Template(f.read())
-    with open(dataFile, "r") as f:
-        data = eval(f.read())
+    data = runpy.run_path(dataFile)["data"]
 
     longhand_count = 0
     shorthand_count = 0
     alias_count = 0
     property_ids = []
-    for name, method, id, flags, pref, prototype in data:
-        if prototype != "alias":
-            if prototype == "longhand":
+    for prop in data:
+        if prop.type() != "alias":
+            if prop.type() == "longhand":
                 assert shorthand_count == 0
                 longhand_count += 1
             else:
                 assert alias_count == 0
                 shorthand_count += 1
-            property_ids.append("eCSSProperty_{}".format(id))
+            property_ids.append("eCSSProperty_{}".format(prop.id))
         else:
             alias_count += 1
-            property_ids.append("eCSSPropertyAlias_{}".format(id[0]))
+            property_ids.append("eCSSPropertyAlias_{}".format(prop.alias_id))
 
     output.write("/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */\n\n")
     output.write(template.substitute({
         "property_ids": "\n".join("  {},".format(p) for p in property_ids),
         "longhand_count": property_ids[longhand_count],
         "shorthand_count": property_ids[longhand_count + shorthand_count],
     }))
--- a/layout/style/GenerateCSSPropsGenerated.py
+++ b/layout/style/GenerateCSSPropsGenerated.py
@@ -1,99 +1,86 @@
 # 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/.
 
+import runpy
 import sys
 import string
 import argparse
 
-def get_properties(dataFile):
-    with open(dataFile, "r") as f:
-        properties = eval(f.read())
-    properties = [{"name":p[0], "prop":p[1], "id":p[2],
-                   "flags":p[3], "pref":p[4], "proptype":p[5]}
-                  for (i, p) in enumerate(properties)]
-
-    # Sort the list so that longhand properties are intermingled first,
-    # shorthand properties follow, then aliases appear last.
-    # This matches the order of the nsCSSPropertyID enum.
+class PropertyWrapper(object):
+    __slots__ = ["index", "prop", "idlname"]
 
-    def property_compare(x, y):
-        property_order = {"longhand": 0, "shorthand": 1, "alias": 2}
-        return property_order[x["proptype"]] - property_order[y["proptype"]]
-
-    properties = sorted(properties, cmp=property_compare)
-
-    for i, p in enumerate(properties):
-        p["index"] = i
-
-    # Record each property's IDL name.
-    for p in properties:
-        if "CSSPropFlags::Internal" in p["flags"]:
-            p["idlname"] = None
+    def __init__(self, index, prop):
+        self.index = index
+        self.prop = prop
+        if "CSSPropFlags::Internal" in prop.flags:
+            self.idlname = None
         else:
-            idl_name = p["prop"]
+            idl_name = prop.method
             if not idl_name.startswith("Moz"):
                 idl_name = idl_name[0].lower() + idl_name[1:]
-            p["idlname"] = idl_name
+            self.idlname = idl_name
+
+    def __getattr__(self, name):
+        return getattr(self.prop, name)
+
+
+def generate(output, dataFile):
+    output.write("""/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */
+
+/* processed file that defines CSS property tables that can't be generated
+   with the pre-processor, designed to be #included in nsCSSProps.cpp */
+
+""")
+
+    properties = runpy.run_path(dataFile)["data"]
+    properties = [PropertyWrapper(i, p)
+                  for i, p in enumerate(properties)
+                  if p.type() != "alias"]
 
-    return properties
+    # Generate kIDLNameTable
+    output.write("const char* const nsCSSProps::"
+                 "kIDLNameTable[eCSSProperty_COUNT] = {\n")
+    for p in properties:
+        if p.idlname is None:
+            output.write("  nullptr,  // {}\n".format(p.name))
+        else:
+            output.write('  "{}",\n'.format(p.idlname))
+    output.write("};\n\n")
 
-def generate_idl_names(properties):
+    # Generate kIDLNameSortPositionTable
+    ps = sorted(properties, key=lambda p: p.idlname)
+    ps = [(p, position) for position, p in enumerate(ps)]
+    ps.sort(key=lambda (p, position): p.index)
+    output.write("const int32_t nsCSSProps::"
+                 "kIDLNameSortPositionTable[eCSSProperty_COUNT] = {\n")
+    for (p, position) in ps:
+        output.write("  {},\n".format(position))
+    output.write("};\n\n")
+
+    # Generate shorthand subprop tables
     names = []
     for p in properties:
-        if p["proptype"] is "alias":
+        if p.type() != "shorthand":
             continue
-        if p["idlname"] is None:
-            names.append("  nullptr,  // %s" % p["name"])
-        else:
-            names.append('  "%s",' % p["idlname"])
-    return "\n".join(names)
-
-def generate_assertions(properties):
-    def enum(p):
-        if p["proptype"] is "alias":
-            return "eCSSPropertyAlias_%s" % p["id"][0]
-        else:
-            return "eCSSProperty_%s" % p["id"]
-    msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
-           'properties in nsCSSPropertyID order");')
-    return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
-
-def generate_idl_name_positions(properties):
-    # Skip aliases.
-    ps = filter(lambda p: p["proptype"] is not "alias", properties)
-
-    # Sort alphabetically by IDL name.
-    ps = sorted(ps, key=lambda p: p["idlname"])
-
-    # Annotate entries with the sorted position.
-    ps = [(p, position) for position, p in enumerate(ps)]
+        name = "g{}SubpropTable".format(p.method)
+        names.append(name)
+        output.write("static const nsCSSPropertyID {}[] = {{\n".format(name))
+        for subprop in p.subprops:
+            output.write("  eCSSProperty_{},\n".format(subprop))
+        output.write("  eCSSProperty_UNKNOWN\n")
+        output.write("};\n\n")
+    output.write("const nsCSSPropertyID* const\n")
+    output.write("nsCSSProps::kSubpropertyTable["
+                 "eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands"
+                 "] = {\n")
+    for name in names:
+        output.write("  {},\n".format(name))
+    output.write("};\n\n")
 
-    # Sort back to nsCSSPropertyID order.
-    ps = sorted(ps, key=lambda (p, position): p["index"])
-
-    return ",\n".join(map(lambda (p, position): "  %d" % position, ps))
-
-def generate(output, cppTemplate, dataFile):
-    cppFile = open(cppTemplate, "r")
-    cppTemplate = cppFile.read()
-    cppFile.close()
-
-    properties = get_properties(dataFile)
-    substitutions = {
-        "idl_names": generate_idl_names(properties),
-        "assertions": generate_assertions(properties),
-        "idl_name_positions": generate_idl_name_positions(properties),
-    }
-    output.write("/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */\n\n" +
-                 string.Template(cppTemplate).substitute(substitutions) + "\n")
-
-def main():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('cppTemplate', help='CSS property file template')
-    parser.add_argument('preprocessorHeader', help='Header file to pass through the preprocessor')
-    args = parser.parse_args()
-    generate(sys.stdout, args.cppTemplate, args.preprocessorHeader)
-
-if __name__ == '__main__':
-    main()
+    # Generate assertions
+    msg = ("GenerateCSSPropsGenerated.py did not list properties "
+           "in nsCSSPropertyID order")
+    for p in properties:
+        output.write('static_assert(eCSSProperty_{} == {}, "{}");\n'
+                     .format(p.id, p.index, msg))
--- a/layout/style/GenerateServoCSSPropList.py
+++ b/layout/style/GenerateServoCSSPropList.py
@@ -1,15 +1,16 @@
 # 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/.
 
 import buildconfig
 import mozpack.path as mozpath
 import os
+import runpy
 import subprocess
 import string
 import sys
 
 SERVO_BASE = mozpath.join(buildconfig.topsrcdir, "servo")
 SERVO_PROP_BASE = mozpath.join(SERVO_BASE, "components", "style", "properties")
 
 
@@ -27,18 +28,17 @@ def generate_data(output, template):
     for path, dirs, files in os.walk(SERVO_PROP_BASE):
         for file in files:
             if os.path.splitext(file)[1] in DEP_EXTS:
                 deps.add(mozpath.join(path, file))
     return deps
 
 
 def generate_header(output, data):
-    with open(data, "r") as f:
-        data = eval(f.read())
+    data = runpy.run_path(data)["data"]
 
     output.write("""/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */
 
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
@@ -63,42 +63,38 @@ def generate_header(output, data):
 
 """)
 
     MACRO_NAMES = {
         "longhand": "CSS_PROP_LONGHAND",
         "shorthand": "CSS_PROP_SHORTHAND",
         "alias": "CSS_PROP_ALIAS",
     }
-    for name, method, id, flags, pref, proptype in data:
-        is_internal = "CSSPropFlags::Internal" in flags
-        pref = '"' + pref + '"'
-        if proptype == "alias":
-            params = [name, id[0], id[1], method, pref]
+    for prop in data:
+        is_internal = "CSSPropFlags::Internal" in prop.flags
+        pref = '"' + prop.pref + '"'
+        if prop.type() == "alias":
+            params = [prop.name, prop.alias_id, prop.prop_id, prop.method, pref]
         else:
+            method = prop.method
             if method == "CssFloat":
                 method = "CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float)"
             elif method.startswith("Moz"):
                 method = "CSS_PROP_DOMPROP_PREFIXED({})".format(method[3:])
-            if flags:
-                flags = " | ".join(flags)
+            if prop.flags:
+                flags = " | ".join(prop.flags)
             else:
                 flags = "CSSPropFlags(0)"
-            params = [name, id, method, flags, pref]
+            params = [prop.name, prop.id, method, flags, pref]
 
-        is_component_of_all = not is_internal and name not in ["direction", "unicode-bidi"]
-        if not is_component_of_all:
-            output.write("#ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND\n")
         if is_internal:
             output.write("#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL\n")
-        output.write("{}({})\n".format(MACRO_NAMES[proptype], ", ".join(params)))
+        output.write("{}({})\n".format(MACRO_NAMES[prop.type()], ", ".join(params)))
         if is_internal:
             output.write("#endif\n")
-        if not is_component_of_all:
-            output.write("#endif\n")
 
     output.write("""
 #ifdef DEFINED_CSS_PROP_ALIAS
 #undef CSS_PROP_ALIAS
 #undef DEFINED_CSS_PROP_ALIAS
 #endif
 
 #ifdef DEFINED_CSS_PROP_SHORTHAND
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -390,21 +390,16 @@ Loader::Loader(DocGroup* aDocGroup)
   mDocGroup = aDocGroup;
 }
 
 Loader::Loader(nsIDocument* aDocument)
   : Loader()
 {
   mDocument = aDocument;
   MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
-
-  // We can just use the preferred set, since there are no sheets in the
-  // document yet (if there are, how did they get there? _we_ load the sheets!)
-  // and hence the selected set makes no sense at this time.
-  mDocument->GetPreferredStyleSheetSet(mPreferredSheet);
 }
 
 Loader::~Loader()
 {
   NS_ASSERTION(!mSheets || mSheets->mLoadingDatas.Count() == 0,
                "How did we get destroyed when there are loading data?");
   NS_ASSERTION(!mSheets || mSheets->mPendingDatas.Count() == 0,
                "How did we get destroyed when there are pending data?");
@@ -420,57 +415,45 @@ Loader::DropDocumentReference(void)
   // Flush out pending datas just so we don't leak by accident.  These
   // loads should short-circuit through the mDocument check in
   // LoadSheet and just end up in SheetComplete immediately
   if (mSheets) {
     StartDeferredLoads();
   }
 }
 
-nsresult
-Loader::SetPreferredSheet(const nsAString& aTitle)
+void
+Loader::DocumentStyleSheetSetChanged()
 {
-#ifdef DEBUG
-  if (mDocument) {
-    nsAutoString currentPreferred;
-    mDocument->GetLastStyleSheetSet(currentPreferred);
-    if (DOMStringIsNull(currentPreferred)) {
-      mDocument->GetPreferredStyleSheetSet(currentPreferred);
-    }
-    NS_ASSERTION(currentPreferred.Equals(aTitle),
-                 "Unexpected argument to SetPreferredSheet");
-  }
-#endif
-
-  mPreferredSheet = aTitle;
+  MOZ_ASSERT(mDocument);
 
   // start any pending alternates that aren't alternates anymore
-  if (mSheets) {
-    LoadDataArray arr(mSheets->mPendingDatas.Count());
-    for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
-      SheetLoadData* data = iter.Data();
-      MOZ_ASSERT(data, "Must have a data");
+  if (!mSheets) {
+    return;
+  }
 
-      // Note that we don't want to affect what the selected style set is, so
-      // use true for aHasAlternateRel.
-      auto isAlternate = data->mLoader->IsAlternateSheet(data->mTitle, true);
-      if (isAlternate == IsAlternate::No) {
-        arr.AppendElement(data);
-        iter.Remove();
-      }
-    }
+  LoadDataArray arr(mSheets->mPendingDatas.Count());
+  for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
+    SheetLoadData* data = iter.Data();
+    MOZ_ASSERT(data, "Must have a data");
 
-    mDatasToNotifyOn += arr.Length();
-    for (uint32_t i = 0; i < arr.Length(); ++i) {
-      --mDatasToNotifyOn;
-      LoadSheet(arr[i], eSheetNeedsParser, false);
+    // Note that we don't want to affect what the selected style set is, so
+    // use true for aHasAlternateRel.
+    auto isAlternate = data->mLoader->IsAlternateSheet(data->mTitle, true);
+    if (isAlternate == IsAlternate::No) {
+      arr.AppendElement(data);
+      iter.Remove();
     }
   }
 
-  return NS_OK;
+  mDatasToNotifyOn += arr.Length();
+  for (uint32_t i = 0; i < arr.Length(); ++i) {
+    --mDatasToNotifyOn;
+    LoadSheet(arr[i], eSheetNeedsParser, false);
+  }
 }
 
 static const char kCharsetSym[] = "@charset \"";
 
 static bool GetCharsetFromData(const char* aStyleSheetData,
                                uint32_t aDataLength,
                                nsACString& aCharset)
 {
@@ -847,26 +830,31 @@ Loader::IsAlternateSheet(const nsAString
   // that's a preferred sheet.
   //
   // FIXME(emilio): This should return false for Shadow DOM regardless of the
   // document.
   if (aTitle.IsEmpty()) {
     return IsAlternate::No;
   }
 
-  if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) {
-    // There's no preferred set yet, and we now have a sheet with a title.
-    // Make that be the preferred set.
-    mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle);
-    // We're definitely not an alternate.
-    return IsAlternate::No;
-  }
+  if (mDocument) {
+    const nsString& currentSheetSet = mDocument->GetCurrentStyleSheetSet();
+    if (!aHasAlternateRel && currentSheetSet.IsEmpty()) {
+      // There's no preferred set yet, and we now have a sheet with a title.
+      // Make that be the preferred set.
+      // FIXME(emilio): This is kinda wild, can we do it somewhere else?
+      mDocument->SetPreferredStyleSheetSet(aTitle);
+      // We're definitely not an alternate. Also, beware that at this point
+      // currentSheetSet may dangle.
+      return IsAlternate::No;
+    }
 
-  if (aTitle.Equals(mPreferredSheet)) {
-    return IsAlternate::No;
+    if (aTitle.Equals(currentSheetSet)) {
+      return IsAlternate::No;
+    }
   }
 
   return IsAlternate::Yes;
 }
 
 nsresult
 Loader::ObsoleteSheet(nsIURI* aURI)
 {
@@ -2680,17 +2668,16 @@ Loader::SizeOfIncludingThis(mozilla::Mal
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mLoadingDatas: transient, and should be small
   // - mPendingDatas: transient, and should be small
   // - mPostedEvents: transient, and should be small
   //
   // The following members aren't measured:
   // - mDocument, because it's a weak backpointer
-  // - mPreferredSheet, because it can be a shared string
 
   return n;
 }
 
 void
 Loader::BlockOnload()
 {
   if (mDocument) {
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -211,17 +211,20 @@ public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Loader)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(Loader)
 
   void DropDocumentReference(); // notification that doc is going away
 
   void SetCompatibilityMode(nsCompatibility aCompatMode)
   { mCompatMode = aCompatMode; }
   nsCompatibility GetCompatibilityMode() { return mCompatMode; }
-  nsresult SetPreferredSheet(const nsAString& aTitle);
+
+  // TODO(emilio): Is the complexity of this method and carrying the titles
+  // around worth it? The alternate sheets will load anyhow eventually...
+  void DocumentStyleSheetSetChanged();
 
   // XXXbz sort out what the deal is with events!  When should they fire?
 
   /**
    * Load an inline style sheet.  If a successful result is returned and
    * result.WillNotify() is true, then aObserver is guaranteed to be notified
    * asynchronously once the sheet is marked complete.  If an error is
    * returned, or if result.WillNotify() is false, aObserver will not be
@@ -623,17 +626,16 @@ private:
 
   // Number of datas still waiting to be notified on if we're notifying on a
   // whole bunch at once (e.g. in one of the stop methods).  This is used to
   // make sure that HasPendingLoads() won't return false until we're notifying
   // on the last data we're working with.
   uint32_t          mDatasToNotifyOn;
 
   nsCompatibility   mCompatMode;
-  nsString          mPreferredSheet;  // title of preferred sheet
 
   bool              mEnabled; // is enabled to load new styles
 
   nsCOMPtr<nsIConsoleReportCollector> mReporter;
 
 #ifdef DEBUG
   bool              mSyncCallback;
 #endif
--- a/layout/style/ServoCSSPropList.mako.py
+++ b/layout/style/ServoCSSPropList.mako.py
@@ -1,12 +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 https://mozilla.org/MPL/2.0/.
 
+def _assign_slots(obj, args):
+    for i, attr in enumerate(obj.__slots__):
+        setattr(obj, attr, args[i])
+
+
+class Longhand(object):
+    __slots__ = ["name", "method", "id", "flags", "pref"]
+
+    def __init__(self, *args):
+        _assign_slots(self, args)
+
+    @staticmethod
+    def type():
+        return "longhand"
+
+
+class Shorthand(object):
+    __slots__ = ["name", "method", "id", "flags", "pref", "subprops"]
+
+    def __init__(self, *args):
+        _assign_slots(self, args)
+
+    @staticmethod
+    def type():
+        return "shorthand"
+
+
+class Alias(object):
+    __slots__ = ["name", "method", "alias_id", "prop_id", "flags", "pref"]
+
+    def __init__(self, *args):
+        _assign_slots(self, args)
+
+    @staticmethod
+    def type():
+        return "alias"
+
 <%!
 # nsCSSPropertyID of longhands and shorthands is ordered alphabetically
 # with vendor prefixes removed. Note that aliases use their alias name
 # as order key directly because they may be duplicate without prefix.
 def order_key(prop):
     if prop.name.startswith("-"):
         return prop.name[prop.name.find("-", 1) + 1:]
     return prop.name
@@ -22,16 +59,23 @@ def is_internal(prop):
         "-moz-context-properties",
         "-moz-control-character-visibility",
         "-moz-window-opacity",
         "-moz-window-transform",
         "-moz-window-transform-origin",
     ]
     return prop.name in OTHER_INTERNALS
 
+def method(prop):
+    if prop.name == "float":
+        return "CssFloat"
+    if prop.name.startswith("-x-"):
+        return prop.camel_case[1:]
+    return prop.camel_case
+
 def flags(prop):
     result = []
     if prop.explicitly_enabled_in_chrome():
         result.append("EnabledInUASheetsAndChrome")
     elif prop.explicitly_enabled_in_ua_sheets():
         result.append("EnabledInUASheets")
     if is_internal(prop):
         result.append("Internal")
@@ -42,50 +86,27 @@ def flags(prop):
     if "CAN_ANIMATE_ON_COMPOSITOR" in prop.flags:
         result.append("CanAnimateOnCompositor")
     return ", ".join('"CSSPropFlags::{}"'.format(flag) for flag in result)
 
 def pref(prop):
     if prop.gecko_pref:
         return '"' + prop.gecko_pref + '"'
     return '""'
+
+def sub_properties(prop):
+    return ", ".join('"{}"'.format(p.ident) for p in prop.sub_properties)
 %>
 
-[
+data = [
     % for prop in sorted(data.longhands, key=order_key):
-    (
-        "${prop.name}",
-        % if prop.name == "float":
-        "CssFloat",
-        % elif prop.name.startswith("-x-"):
-        "${prop.camel_case[1:]}",
-        % else:
-        "${prop.camel_case}",
-        % endif
-        "${prop.ident}",
-        [${flags(prop)}],
-        ${pref(prop)},
-        "longhand",
-    ),
+    Longhand("${prop.name}", "${method(prop)}", "${prop.ident}", [${flags(prop)}], ${pref(prop)}),
     % endfor
 
     % for prop in sorted(data.shorthands, key=order_key):
-    (
-        "${prop.name}",
-        "${prop.camel_case}",
-        "${prop.ident}",
-        [${flags(prop)}],
-        ${pref(prop)},
-        "shorthand",
-    ),
+    Shorthand("${prop.name}", "${prop.camel_case}", "${prop.ident}", [${flags(prop)}], ${pref(prop)},
+              [${sub_properties(prop)}]),
     % endfor
 
     % for prop in sorted(data.all_aliases(), key=lambda x: x.name):
-    (
-        "${prop.name}",
-        "${prop.camel_case}",
-        ("${prop.ident}", "${prop.original.ident}"),
-        [],
-        ${pref(prop)},
-        "alias",
-    ),
+    Alias("${prop.name}", "${prop.camel_case}", "${prop.ident}", "${prop.original.ident}", [], ${pref(prop)}),
     % endfor
 ]
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -297,15 +297,14 @@ servo_props.inputs = [
 if CONFIG['COMPILE_ENVIRONMENT']:
     GENERATED_FILES += [
         'nsCSSPropsGenerated.inc',
     ]
 
     css_props = GENERATED_FILES['nsCSSPropsGenerated.inc']
     css_props.script = 'GenerateCSSPropsGenerated.py:generate'
     css_props.inputs = [
-        'nsCSSPropsGenerated.inc.in',
         '!ServoCSSPropList.py',
     ]
 
     CONFIGURE_SUBST_FILES += [
         'bindgen.toml',
     ]
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1732,462 +1732,16 @@ nsCSSProps::ValueToKeyword(int32_t aValu
 const CSSPropFlags nsCSSProps::kFlagsTable[eCSSProperty_COUNT] = {
 #define CSS_PROP_LONGHAND(name_, id_, method_, flags_, ...) flags_,
 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, ...) flags_,
 #include "mozilla/ServoCSSPropList.h"
 #undef CSS_PROP_SHORTHAND
 #undef CSS_PROP_LONGHAND
 };
 
-static const nsCSSPropertyID gAllSubpropTable[] = {
-#define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
-#define CSS_PROP_LONGHAND(name_, id_, ...) eCSSProperty_##id_,
-#include "mozilla/ServoCSSPropList.h"
-#undef CSS_PROP_LONGHAND
-#undef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gAnimationSubpropTable[] = {
-  eCSSProperty_animation_duration,
-  eCSSProperty_animation_timing_function,
-  eCSSProperty_animation_delay,
-  eCSSProperty_animation_direction,
-  eCSSProperty_animation_fill_mode,
-  eCSSProperty_animation_iteration_count,
-  eCSSProperty_animation_play_state,
-  // List animation-name last so we serialize it last, in case it has
-  // a value that conflicts with one of the other properties.  (See
-  // how Declaration::GetValue serializes 'animation'.
-  eCSSProperty_animation_name,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderRadiusSubpropTable[] = {
-  // Code relies on these being in topleft-topright-bottomright-bottomleft
-  // order.
-  eCSSProperty_border_top_left_radius,
-  eCSSProperty_border_top_right_radius,
-  eCSSProperty_border_bottom_right_radius,
-  eCSSProperty_border_bottom_left_radius,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gOutlineRadiusSubpropTable[] = {
-  // Code relies on these being in topleft-topright-bottomright-bottomleft
-  // order.
-  eCSSProperty__moz_outline_radius_topleft,
-  eCSSProperty__moz_outline_radius_topright,
-  eCSSProperty__moz_outline_radius_bottomright,
-  eCSSProperty__moz_outline_radius_bottomleft,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBackgroundSubpropTable[] = {
-  eCSSProperty_background_color,
-  eCSSProperty_background_image,
-  eCSSProperty_background_repeat,
-  eCSSProperty_background_attachment,
-  eCSSProperty_background_clip,
-  eCSSProperty_background_origin,
-  eCSSProperty_background_position_x,
-  eCSSProperty_background_position_y,
-  eCSSProperty_background_size,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBackgroundPositionSubpropTable[] = {
-  eCSSProperty_background_position_x,
-  eCSSProperty_background_position_y,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderSubpropTable[] = {
-  eCSSProperty_border_top_width,
-  eCSSProperty_border_right_width,
-  eCSSProperty_border_bottom_width,
-  eCSSProperty_border_left_width,
-  eCSSProperty_border_top_style,
-  eCSSProperty_border_right_style,
-  eCSSProperty_border_bottom_style,
-  eCSSProperty_border_left_style,
-  eCSSProperty_border_top_color,
-  eCSSProperty_border_right_color,
-  eCSSProperty_border_bottom_color,
-  eCSSProperty_border_left_color,
-  eCSSProperty_border_image_source,
-  eCSSProperty_border_image_slice,
-  eCSSProperty_border_image_width,
-  eCSSProperty_border_image_outset,
-  eCSSProperty_border_image_repeat,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderBlockEndSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_block_end_width,
-  eCSSProperty_border_block_end_style,
-  eCSSProperty_border_block_end_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderBlockStartSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_block_start_width,
-  eCSSProperty_border_block_start_style,
-  eCSSProperty_border_block_start_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderBottomSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_bottom_width,
-  eCSSProperty_border_bottom_style,
-  eCSSProperty_border_bottom_color,
-  eCSSProperty_UNKNOWN
-};
-
-static_assert(eSideTop == 0 && eSideRight == 1 &&
-              eSideBottom == 2 && eSideLeft == 3,
-              "box side constants not top/right/bottom/left == 0/1/2/3");
-static const nsCSSPropertyID gBorderColorSubpropTable[] = {
-  // Code relies on these being in top-right-bottom-left order.
-  // Code relies on these matching the enum Side constants.
-  eCSSProperty_border_top_color,
-  eCSSProperty_border_right_color,
-  eCSSProperty_border_bottom_color,
-  eCSSProperty_border_left_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderInlineEndSubpropTable[] = {
-  // Declaration.cpp output the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_inline_end_width,
-  eCSSProperty_border_inline_end_style,
-  eCSSProperty_border_inline_end_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderLeftSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_left_width,
-  eCSSProperty_border_left_style,
-  eCSSProperty_border_left_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderRightSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_right_width,
-  eCSSProperty_border_right_style,
-  eCSSProperty_border_right_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderInlineStartSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_inline_start_width,
-  eCSSProperty_border_inline_start_style,
-  eCSSProperty_border_inline_start_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderStyleSubpropTable[] = {
-  // Code relies on these being in top-right-bottom-left order.
-  eCSSProperty_border_top_style,
-  eCSSProperty_border_right_style,
-  eCSSProperty_border_bottom_style,
-  eCSSProperty_border_left_style,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderTopSubpropTable[] = {
-  // Declaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_border_top_width,
-  eCSSProperty_border_top_style,
-  eCSSProperty_border_top_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderWidthSubpropTable[] = {
-  // Code relies on these being in top-right-bottom-left order.
-  eCSSProperty_border_top_width,
-  eCSSProperty_border_right_width,
-  eCSSProperty_border_bottom_width,
-  eCSSProperty_border_left_width,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gFontSubpropTable[] = {
-  eCSSProperty_font_family,
-  eCSSProperty_font_style,
-  eCSSProperty_font_weight,
-  eCSSProperty_font_size,
-  eCSSProperty_line_height,
-  eCSSProperty_font_size_adjust,
-  eCSSProperty_font_stretch,
-  eCSSProperty_font_feature_settings,
-  eCSSProperty_font_language_override,
-  eCSSProperty_font_kerning,
-  eCSSProperty_font_optical_sizing,
-  eCSSProperty_font_variation_settings,
-  eCSSProperty_font_variant_alternates,
-  eCSSProperty_font_variant_caps,
-  eCSSProperty_font_variant_east_asian,
-  eCSSProperty_font_variant_ligatures,
-  eCSSProperty_font_variant_numeric,
-  eCSSProperty_font_variant_position,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gFontVariantSubpropTable[] = {
-  eCSSProperty_font_variant_alternates,
-  eCSSProperty_font_variant_caps,
-  eCSSProperty_font_variant_east_asian,
-  eCSSProperty_font_variant_ligatures,
-  eCSSProperty_font_variant_numeric,
-  eCSSProperty_font_variant_position,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gListStyleSubpropTable[] = {
-  eCSSProperty_list_style_type,
-  eCSSProperty_list_style_image,
-  eCSSProperty_list_style_position,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gMarginSubpropTable[] = {
-  // Code relies on these being in top-right-bottom-left order.
-  eCSSProperty_margin_top,
-  eCSSProperty_margin_right,
-  eCSSProperty_margin_bottom,
-  eCSSProperty_margin_left,
-  eCSSProperty_UNKNOWN
-};
-
-
-static const nsCSSPropertyID gOutlineSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_outline_width,
-  eCSSProperty_outline_style,
-  eCSSProperty_outline_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gColumnsSubpropTable[] = {
-  eCSSProperty_column_count,
-  eCSSProperty_column_width,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gColumnRuleSubpropTable[] = {
-  // nsCSSDeclaration.cpp outputs the subproperties in this order.
-  // It also depends on the color being third.
-  eCSSProperty_column_rule_width,
-  eCSSProperty_column_rule_style,
-  eCSSProperty_column_rule_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gFlexSubpropTable[] = {
-  eCSSProperty_flex_grow,
-  eCSSProperty_flex_shrink,
-  eCSSProperty_flex_basis,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gFlexFlowSubpropTable[] = {
-  eCSSProperty_flex_direction,
-  eCSSProperty_flex_wrap,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGridTemplateSubpropTable[] = {
-  eCSSProperty_grid_template_areas,
-  eCSSProperty_grid_template_rows,
-  eCSSProperty_grid_template_columns,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGridSubpropTable[] = {
-  eCSSProperty_grid_template_areas,
-  eCSSProperty_grid_template_rows,
-  eCSSProperty_grid_template_columns,
-  eCSSProperty_grid_auto_flow,
-  eCSSProperty_grid_auto_rows,
-  eCSSProperty_grid_auto_columns,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGridColumnSubpropTable[] = {
-  eCSSProperty_grid_column_start,
-  eCSSProperty_grid_column_end,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGridRowSubpropTable[] = {
-  eCSSProperty_grid_row_start,
-  eCSSProperty_grid_row_end,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGridAreaSubpropTable[] = {
-  eCSSProperty_grid_row_start,
-  eCSSProperty_grid_column_start,
-  eCSSProperty_grid_row_end,
-  eCSSProperty_grid_column_end,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gGapSubpropTable[] = {
-  eCSSProperty_row_gap,
-  eCSSProperty_column_gap,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gOverflowSubpropTable[] = {
-  eCSSProperty_overflow_x,
-  eCSSProperty_overflow_y,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gOverflowClipBoxSubpropTable[] = {
-  eCSSProperty_overflow_clip_box_block,
-  eCSSProperty_overflow_clip_box_inline,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gPaddingSubpropTable[] = {
-  // Code relies on these being in top-right-bottom-left order.
-  eCSSProperty_padding_top,
-  eCSSProperty_padding_right,
-  eCSSProperty_padding_bottom,
-  eCSSProperty_padding_left,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gTextDecorationSubpropTable[] = {
-  eCSSProperty_text_decoration_color,
-  eCSSProperty_text_decoration_line,
-  eCSSProperty_text_decoration_style,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gTextEmphasisSubpropTable[] = {
-  eCSSProperty_text_emphasis_style,
-  eCSSProperty_text_emphasis_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gWebkitTextStrokeSubpropTable[] = {
-  eCSSProperty__webkit_text_stroke_width,
-  eCSSProperty__webkit_text_stroke_color,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gTransitionSubpropTable[] = {
-  eCSSProperty_transition_property,
-  eCSSProperty_transition_duration,
-  eCSSProperty_transition_timing_function,
-  eCSSProperty_transition_delay,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gBorderImageSubpropTable[] = {
-  eCSSProperty_border_image_source,
-  eCSSProperty_border_image_slice,
-  eCSSProperty_border_image_width,
-  eCSSProperty_border_image_outset,
-  eCSSProperty_border_image_repeat,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gMarkerSubpropTable[] = {
-  eCSSProperty_marker_start,
-  eCSSProperty_marker_mid,
-  eCSSProperty_marker_end,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gPlaceContentSubpropTable[] = {
-  eCSSProperty_align_content,
-  eCSSProperty_justify_content,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gPlaceItemsSubpropTable[] = {
-  eCSSProperty_align_items,
-  eCSSProperty_justify_items,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gPlaceSelfSubpropTable[] = {
-  eCSSProperty_align_self,
-  eCSSProperty_justify_self,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gOverscrollBehaviorSubpropTable[] = {
-  eCSSProperty_overscroll_behavior_x,
-  eCSSProperty_overscroll_behavior_y,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gScrollSnapTypeSubpropTable[] = {
-  eCSSProperty_scroll_snap_type_x,
-  eCSSProperty_scroll_snap_type_y,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gMaskSubpropTable[] = {
-  eCSSProperty_mask_image,
-  eCSSProperty_mask_repeat,
-  eCSSProperty_mask_position_x,
-  eCSSProperty_mask_position_y,
-  eCSSProperty_mask_clip,
-  eCSSProperty_mask_origin,
-  eCSSProperty_mask_size,
-  eCSSProperty_mask_composite,
-  eCSSProperty_mask_mode,
-  eCSSProperty_UNKNOWN
-};
-
-static const nsCSSPropertyID gMaskPositionSubpropTable[] = {
-  eCSSProperty_mask_position_x,
-  eCSSProperty_mask_position_y,
-  eCSSProperty_UNKNOWN
-};
-
-// FIXME: mask-border tables should be added when we implement
-// mask-border properties.
-
-const nsCSSPropertyID *const
-nsCSSProps::kSubpropertyTable[eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands] = {
-#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
-// Need an extra level of macro nesting to force expansion of method_
-// params before they get pasted.
-#define NSCSSPROPS_INNER_MACRO(method_) g##method_##SubpropTable,
-#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
-  NSCSSPROPS_INNER_MACRO(method_)
-#include "mozilla/ServoCSSPropList.h"
-#undef CSS_PROP_SHORTHAND
-#undef NSCSSPROPS_INNER_MACRO
-#undef CSS_PROP_PUBLIC_OR_PRIVATE
-};
-
 /* static */ bool
 nsCSSProps::gPropertyEnabled[eCSSProperty_COUNT_with_aliases] = {
   // If the property has any "ENABLED_IN" flag set, it is disabled by
   // default. Note that, if a property has pref, whatever its default
   // value is, it will later be changed in nsCSSProps::AddRefTable().
   // If the property has "ENABLED_IN" flags but doesn't have a pref,
   // it is an internal property which is disabled elsewhere.
   #define IS_ENABLED_BY_DEFAULT(flags_) \
deleted file mode 100644
--- a/layout/style/nsCSSPropsGenerated.inc.in
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/* processed file that defines CSS property tables that can't be generated
-   with the pre-processor, designed to be #included in nsCSSProps.cpp */
-
-const char* const nsCSSProps::kIDLNameTable[eCSSProperty_COUNT] = {
-${idl_names}
-};
-
-const int32_t nsCSSProps::kIDLNameSortPositionTable[eCSSProperty_COUNT] = {
-${idl_name_positions}
-};
-
-${assertions}
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -117,17 +117,17 @@ android {
                 srcDir "${topsrcdir}/mobile/android/base/java"
                 srcDir "${topsrcdir}/mobile/android/services/src/main/java"
 
                 if (mozconfig.substs.MOZ_ANDROID_MLS_STUMBLER) {
                     srcDir "${topsrcdir}/mobile/android/stumbler/java"
                 }
 
                 if (!mozconfig.substs.MOZ_CRASHREPORTER) {
-                    exclude 'org/mozilla/gecko/CrashReporterActivity.java'
+                    exclude 'org/mozilla/gecko/CrashReporter.java'
                 }
 
                 if (!mozconfig.substs.MOZ_NATIVE_DEVICES) {
                     exclude 'org/mozilla/gecko/ChromeCastDisplay.java'
                     exclude 'org/mozilla/gecko/ChromeCastPlayer.java'
                     exclude 'org/mozilla/gecko/GeckoMediaPlayer.java'
                     exclude 'org/mozilla/gecko/GeckoPresentationDisplay.java'
                     exclude 'org/mozilla/gecko/MediaPlayerManager.java'
--- a/mobile/android/app/lint.xml
+++ b/mobile/android/app/lint.xml
@@ -59,17 +59,17 @@
         <ignore path="**/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java"/>
         <ignore path="**/mobile/android/base/java/org/mozilla/gecko/IntentHelper.java"/>
         <ignore path="**/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioEffects.java"/>
         <ignore path="**/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioRecord.java"/>
         <ignore path="src/photon/res/values/styles.xml"/>
     </issue>
 
     <!-- We fixed all "Registered" lint errors. However the current gradle plugin has a bug where
-         it ignores @SuppressLint annotations for this check. See CrashReporterActivity class and
+         it ignores @SuppressLint annotations for this check. See CrashReporter class and
          https://code.google.com/p/android/issues/detail?id=204846 -->
     <issue id="Registered" severity="warning" />
 
     <issue id="ObjectAnimatorBinding" severity="error">
         <!-- Two animated properties are provided by the underlying
              View implementation. -->
         <ignore path="**/mobile/android/base/java/org/mozilla/gecko/firstrun/FirstrunPager.java"/>
     </issue>
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -267,17 +267,17 @@
                 <data android:scheme="moz-notification" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </receiver>
 
 #include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
 
 #ifdef MOZ_CRASHREPORTER
-  <activity android:name="org.mozilla.gecko.CrashReporterActivity"
+  <activity android:name="org.mozilla.gecko.CrashReporter"
             android:process="@ANDROID_PACKAGE_NAME@.CrashReporter"
             android:label="@string/crash_reporter_title"
             android:icon="@drawable/crash_reporter"
             android:theme="@style/Gecko"
             android:exported="false"
             android:excludeFromRecents="true">
           <intent-filter>
             <action android:name="org.mozilla.gecko.reportCrash" />
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/CrashReporter.java
@@ -0,0 +1,599 @@
+/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.security.MessageDigest;
+import java.util.zip.GZIPOutputStream;
+
+import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.mozglue.GeckoLoader;
+import org.mozilla.gecko.mozglue.MinidumpAnalyzer;
+import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCrashPingBuilder;
+import org.mozilla.gecko.telemetry.TelemetryDispatcher;
+import org.mozilla.gecko.util.INIParser;
+import org.mozilla.gecko.util.INISection;
+import org.mozilla.gecko.util.ProxySelector;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+
+// Registered: This activity is only registered in the manifest if MOZ_CRASHREPORTER is set.
+// CutPasteId: This lint is not worth fixing.  To fix it, cache all the findViewById results.
+@SuppressLint("Registered,CutPasteId")
+public class CrashReporter extends AppCompatActivity
+{
+    private static final String LOGTAG = "GeckoCrashReporter";
+
+    private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
+    private static final String PASSED_MINI_DUMP_SUCCESS_KEY = "minidumpSuccess";
+    private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
+    private static final String PAGE_URL_KEY = "URL";
+    private static final String NOTES_KEY = "Notes";
+    private static final String SERVER_URL_KEY = "ServerURL";
+
+    private static final String CRASH_REPORT_SUFFIX = "/mozilla/Crash Reports/";
+    private static final String PENDING_SUFFIX = CRASH_REPORT_SUFFIX + "pending";
+    private static final String SUBMITTED_SUFFIX = CRASH_REPORT_SUFFIX + "submitted";
+
+    private static final String PREFS_SEND_REPORT   = "sendReport";
+    private static final String PREFS_INCLUDE_URL   = "includeUrl";
+    private static final String PREFS_ALLOW_CONTACT = "allowContact";
+    private static final String PREFS_CONTACT_EMAIL = "contactEmail";
+
+    private Handler mHandler;
+    private ProgressDialog mProgressDialog;
+    private File mPendingMinidumpFile;
+    private File mPendingExtrasFile;
+    private HashMap<String, String> mExtrasStringMap;
+    private boolean mMinidumpSucceeded;
+
+    private boolean moveFile(File inFile, File outFile) {
+        Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
+        if (inFile.renameTo(outFile))
+            return true;
+        try {
+            outFile.createNewFile();
+            Log.i(LOGTAG, "couldn't rename minidump file");
+            // so copy it instead
+            FileChannel inChannel = new FileInputStream(inFile).getChannel();
+            FileChannel outChannel = new FileOutputStream(outFile).getChannel();
+            long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
+            inChannel.close();
+            outChannel.close();
+
+            if (transferred > 0)
+                inFile.delete();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while copying minidump file: ", e);
+            return false;
+        }
+        return true;
+    }
+
+    private void doFinish() {
+        if (mHandler != null) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    finish();
+                }
+            });
+        }
+    }
+
+    @Override
+    public void finish() {
+        try {
+            if (mProgressDialog.isShowing()) {
+                mProgressDialog.dismiss();
+            }
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while closing progress dialog: ", e);
+        }
+        super.finish();
+    }
+
+    @Override
+    @SuppressLint("WrongThread") // We don't have a worker thread for the TelemetryDispatcher
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // mHandler is created here so runnables can be run on the main thread
+        mHandler = new Handler();
+        setContentView(R.layout.crash_reporter);
+        mProgressDialog = new ProgressDialog(this);
+        mProgressDialog.setMessage(getString(R.string.sending_crash_report));
+
+        mMinidumpSucceeded = getIntent().getBooleanExtra(PASSED_MINI_DUMP_SUCCESS_KEY, false);
+        if (!mMinidumpSucceeded) {
+            Log.i(LOGTAG, "Failed to get minidump.");
+        }
+        String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
+        File passedMinidumpFile = new File(passedMinidumpPath);
+        File pendingDir = new File(getFilesDir(), PENDING_SUFFIX);
+        pendingDir.mkdirs();
+        mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
+        moveFile(passedMinidumpFile, mPendingMinidumpFile);
+
+        File extrasFile = new File(passedMinidumpPath.replaceAll("\\.dmp", ".extra"));
+        mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
+        moveFile(extrasFile, mPendingExtrasFile);
+
+        // Compute the minidump hash and generate the stack traces
+        computeMinidumpHash(mPendingExtrasFile, mPendingMinidumpFile);
+
+        try {
+            GeckoLoader.loadMozGlue(this);
+
+            if (!MinidumpAnalyzer.GenerateStacks(mPendingMinidumpFile.getPath(), /* fullStacks */ false)) {
+                Log.e(LOGTAG, "Could not generate stacks for this minidump: " + passedMinidumpPath);
+            }
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(LOGTAG, "Could not load libmozglue.so, stacks for this crash won't be generated");
+        }
+
+        // Extract the annotations from the .extra file
+        mExtrasStringMap = new HashMap<String, String>();
+        readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
+
+        try {
+            // Find the profile name and path. Since we don't have any other way of getting it within
+            // this context we extract it from the crash dump path.
+            final File profileDir = passedMinidumpFile.getParentFile().getParentFile();
+            final String profileName = getProfileName(profileDir);
+
+            if (profileName != null) {
+                // Extract the crash dump ID and telemetry client ID, we need profile access for the latter.
+                final String passedMinidumpName = passedMinidumpFile.getName();
+                // Strip the .dmp suffix from the minidump name to obtain the crash ID.
+                final String crashId = passedMinidumpName.substring(0, passedMinidumpName.length() - 4);
+                final GeckoProfile profile = GeckoProfile.get(this, profileName, profileDir);
+                final String clientId = profile.getClientId();
+
+                // Assemble and send the crash ping
+                final TelemetryCrashPingBuilder pingBuilder =
+                    new TelemetryCrashPingBuilder(crashId, clientId, mExtrasStringMap);
+                final TelemetryDispatcher dispatcher = new TelemetryDispatcher(profileDir.getPath(), profileName);
+                dispatcher.queuePingForUpload(this, pingBuilder);
+            }
+        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
+            Log.e(LOGTAG, "Cannot send the crash ping: ", e);
+        }
+
+        // Notify GeckoApp that we've crashed, so it can react appropriately during the next start.
+        try {
+            File crashFlag = new File(GeckoProfileDirectories.getMozillaDirectory(this), "CRASHED");
+            crashFlag.createNewFile();
+        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
+            Log.e(LOGTAG, "Cannot set crash flag: ", e);
+        }
+
+        final CheckBox allowContactCheckBox = (CheckBox) findViewById(R.id.allow_contact);
+        final CheckBox includeUrlCheckBox = (CheckBox) findViewById(R.id.include_url);
+        final CheckBox sendReportCheckBox = (CheckBox) findViewById(R.id.send_report);
+        final EditText commentsEditText = (EditText) findViewById(R.id.comment);
+        final EditText emailEditText = (EditText) findViewById(R.id.email);
+
+        // Load CrashReporter preferences to avoid redundant user input.
+        SharedPreferences prefs = GeckoSharedPrefs.forCrashReporter(this);
+        final boolean sendReport   = prefs.getBoolean(PREFS_SEND_REPORT, true);
+        final boolean includeUrl   = prefs.getBoolean(PREFS_INCLUDE_URL, false);
+        final boolean allowContact = prefs.getBoolean(PREFS_ALLOW_CONTACT, false);
+        final String contactEmail  = prefs.getString(PREFS_CONTACT_EMAIL, "");
+
+        allowContactCheckBox.setChecked(allowContact);
+        includeUrlCheckBox.setChecked(includeUrl);
+        sendReportCheckBox.setChecked(sendReport);
+        emailEditText.setText(contactEmail);
+
+        sendReportCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton checkbox, boolean isChecked) {
+                commentsEditText.setEnabled(isChecked);
+                commentsEditText.requestFocus();
+
+                includeUrlCheckBox.setEnabled(isChecked);
+                allowContactCheckBox.setEnabled(isChecked);
+                emailEditText.setEnabled(isChecked && allowContactCheckBox.isChecked());
+            }
+        });
+
+        allowContactCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton checkbox, boolean isChecked) {
+                // We need to check isEnabled() here because this listener is
+                // fired on rotation -- even when the checkbox is disabled.
+                emailEditText.setEnabled(checkbox.isEnabled() && isChecked);
+                emailEditText.requestFocus();
+            }
+        });
+
+        emailEditText.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // Even if the email EditText is disabled, allow it to be
+                // clicked and focused.
+                if (sendReportCheckBox.isChecked() && !v.isEnabled()) {
+                    allowContactCheckBox.setChecked(true);
+                    v.setEnabled(true);
+                    v.requestFocus();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onBackPressed() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setMessage(R.string.crash_closing_alert);
+        builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dialog.dismiss();
+            }
+        });
+        builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                CrashReporter.this.finish();
+            }
+        });
+        builder.show();
+    }
+
+    private void backgroundSendReport() {
+        final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
+        if (!sendReportCheckbox.isChecked()) {
+            doFinish();
+            return;
+        }
+
+        // Persist settings to avoid redundant user input.
+        savePrefs();
+
+        mProgressDialog.show();
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
+            }
+        }, "CrashReporter Thread").start();
+    }
+
+    private void savePrefs() {
+        SharedPreferences.Editor editor = GeckoSharedPrefs.forCrashReporter(this).edit();
+
+        final boolean allowContact = ((CheckBox) findViewById(R.id.allow_contact)).isChecked();
+        final boolean includeUrl   = ((CheckBox) findViewById(R.id.include_url)).isChecked();
+        final boolean sendReport   = ((CheckBox) findViewById(R.id.send_report)).isChecked();
+        final String contactEmail  = ((EditText) findViewById(R.id.email)).getText().toString();
+
+        editor.putBoolean(PREFS_ALLOW_CONTACT, allowContact);
+        editor.putBoolean(PREFS_INCLUDE_URL, includeUrl);
+        editor.putBoolean(PREFS_SEND_REPORT, sendReport);
+        editor.putString(PREFS_CONTACT_EMAIL, contactEmail);
+
+        // A slight performance improvement via async apply() vs. blocking on commit().
+        editor.apply();
+    }
+
+    public void onCloseClick(View v) {  // bound via crash_reporter.xml
+        backgroundSendReport();
+    }
+
+    public void onRestartClick(View v) {  // bound via crash_reporter.xml
+        doRestart();
+        backgroundSendReport();
+    }
+
+    private String getProfileName(File profileDir) throws GeckoProfileDirectories.NoMozillaDirectoryException {
+        final File mozillaDir = GeckoProfileDirectories.getMozillaDirectory(this);
+        final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
+        String profileName = null;
+
+        if (parser.getSections() != null) {
+            for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) {
+                final INISection section = e.nextElement();
+                final String path = section.getStringProperty("Path");
+                final boolean isRelative = (section.getIntProperty("IsRelative") == 1);
+
+                if ((isRelative && path.equals(profileDir.getName())) ||
+                    path.equals(profileDir.getPath())) {
+                    profileName = section.getStringProperty("Name");
+                    break;
+                }
+            }
+        }
+
+        return profileName;
+    }
+
+
+    private void computeMinidumpHash(File extraFile, File minidump) {
+        try {
+            FileInputStream stream = new FileInputStream(minidump);
+            MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+            try {
+                byte[] buffer = new byte[4096];
+                int readBytes;
+
+                while ((readBytes = stream.read(buffer)) != -1) {
+                    md.update(buffer, 0, readBytes);
+                }
+            } finally {
+              stream.close();
+            }
+
+            byte[] digest = md.digest();
+            StringBuilder hash = new StringBuilder(84);
+
+            hash.append("MinidumpSha256Hash=");
+
+            for (int i = 0; i < digest.length; i++) {
+              hash.append(Integer.toHexString((digest[i] & 0xf0) >> 4));
+              hash.append(Integer.toHexString(digest[i] & 0x0f));
+            }
+
+            hash.append('\n');
+
+            FileWriter writer = new FileWriter(extraFile, /* append */ true);
+
+            try {
+                writer.write(hash.toString());
+            } finally {
+                writer.close();
+            }
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while computing the minidump hash: ", e);
+        }
+    }
+
+    private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
+        try {
+            BufferedReader reader = new BufferedReader(new FileReader(filePath));
+            return readStringsFromReader(reader, stringMap);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while reading strings: ", e);
+            return false;
+        }
+    }
+
+    private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
+        String line;
+        while ((line = reader.readLine()) != null) {
+            int equalsPos = -1;
+            if ((equalsPos = line.indexOf('=')) != -1) {
+                String key = line.substring(0, equalsPos);
+                String val = unescape(line.substring(equalsPos + 1));
+                stringMap.put(key, val);
+            }
+        }
+        reader.close();
+        return true;
+    }
+
+    private String generateBoundary() {
+        // Generate some random numbers to fill out the boundary
+        int r0 = (int)(Integer.MAX_VALUE * Math.random());
+        int r1 = (int)(Integer.MAX_VALUE * Math.random());
+        return String.format("---------------------------%08X%08X", r0, r1);
+    }
+
+    private void sendPart(OutputStream os, String boundary, String name, String data) {
+        try {
+            os.write(("--" + boundary + "\r\n" +
+                      "Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
+                      "\r\n" +
+                      data + "\r\n"
+                     ).getBytes());
+        } catch (Exception ex) {
+            Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
+        }
+    }
+
+    private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
+        os.write(("--" + boundary + "\r\n" +
+                  "Content-Disposition: form-data; name=\"" + name + "\"; " +
+                  "filename=\"" + file.getName() + "\"\r\n" +
+                  "Content-Type: application/octet-stream\r\n" +
+                  "\r\n"
+                 ).getBytes());
+        FileChannel fc = new FileInputStream(file).getChannel();
+        fc.transferTo(0, fc.size(), Channels.newChannel(os));
+        fc.close();
+    }
+
+    private String readLogcat() {
+        final String crashReporterProc = " " + android.os.Process.myPid() + ' ';
+        BufferedReader br = null;
+        try {
+            // get at most the last 400 lines of logcat
+            Process proc = Runtime.getRuntime().exec(new String[] {
+                "logcat", "-v", "threadtime", "-t", "400", "-d", "*:D"
+            });
+            StringBuilder sb = new StringBuilder();
+            br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+            for (String s = br.readLine(); s != null; s = br.readLine()) {
+                if (s.contains(crashReporterProc)) {
+                    // Don't include logs from the crash reporter's process.
+                    break;
+                }
+                sb.append(s).append('\n');
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            return "Unable to get logcat: " + e.toString();
+        } finally {
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
+        Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
+        final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
+
+        String spec = extras.get(SERVER_URL_KEY);
+        if (spec == null) {
+            doFinish();
+            return;
+        }
+
+        Log.i(LOGTAG, "server url: " + spec);
+        try {
+            final URL url = new URL(URLDecoder.decode(spec, "UTF-8"));
+            final URI uri = new URI(url.getProtocol(), url.getUserInfo(),
+                                    url.getHost(), url.getPort(),
+                                    url.getPath(), url.getQuery(), url.getRef());
+            HttpURLConnection conn = (HttpURLConnection)ProxySelector.openConnectionWithProxy(uri);
+            conn.setRequestMethod("POST");
+            String boundary = generateBoundary();
+            conn.setDoOutput(true);
+            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+            conn.setRequestProperty("Content-Encoding", "gzip");
+
+            OutputStream os = new GZIPOutputStream(conn.getOutputStream());
+            for (String key : extras.keySet()) {
+                if (key.equals(PAGE_URL_KEY)) {
+                    if (includeURLCheckbox.isChecked())
+                        sendPart(os, boundary, key, extras.get(key));
+                } else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
+                    sendPart(os, boundary, key, extras.get(key));
+                }
+            }
+
+            // Add some extra information to notes so its displayed by
+            // crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
+            StringBuilder sb = new StringBuilder();
+            sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
+            sb.append(Build.MANUFACTURER).append(' ')
+              .append(Build.MODEL).append('\n')
+              .append(Build.FINGERPRINT);
+            sendPart(os, boundary, NOTES_KEY, sb.toString());
+
+            sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
+            sendPart(os, boundary, "Android_Model", Build.MODEL);
+            sendPart(os, boundary, "Android_Board", Build.BOARD);
+            sendPart(os, boundary, "Android_Brand", Build.BRAND);
+            sendPart(os, boundary, "Android_Device", Build.DEVICE);
+            sendPart(os, boundary, "Android_Display", Build.DISPLAY);
+            sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
+            sendPart(os, boundary, "Android_APP_ABI", AppConstants.MOZ_APP_ABI);
+            sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
+            sendPart(os, boundary, "Android_MIN_SDK", Integer.toString(AppConstants.Versions.MIN_SDK_VERSION));
+            sendPart(os, boundary, "Android_MAX_SDK", Integer.toString(AppConstants.Versions.MAX_SDK_VERSION));
+            try {
+                sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
+                sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
+            } catch (Exception ex) {
+                Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
+            }
+            sendPart(os, boundary, "Android_Version",  Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
+            if (Versions.feature16Plus && includeURLCheckbox.isChecked()) {
+                sendPart(os, boundary, "Android_Logcat", readLogcat());
+            }
+
+            String comment = ((EditText) findViewById(R.id.comment)).getText().toString();
+            if (!TextUtils.isEmpty(comment)) {
+                sendPart(os, boundary, "Comments", comment);
+            }
+
+            if (((CheckBox) findViewById(R.id.allow_contact)).isChecked()) {
+                String email = ((EditText) findViewById(R.id.email)).getText().toString();
+                sendPart(os, boundary, "Email", email);
+            }
+
+            sendPart(os, boundary, PASSED_MINI_DUMP_SUCCESS_KEY, mMinidumpSucceeded ? "True" : "False");
+            sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
+            os.write(("\r\n--" + boundary + "--\r\n").getBytes());
+            os.flush();
+            os.close();
+            BufferedReader br = new BufferedReader(
+                new InputStreamReader(conn.getInputStream()));
+            HashMap<String, String>  responseMap = new HashMap<String, String>();
+            readStringsFromReader(br, responseMap);
+
+            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                File submittedDir = new File(getFilesDir(),
+                                             SUBMITTED_SUFFIX);
+                submittedDir.mkdirs();
+                minidumpFile.delete();
+                extrasFile.delete();
+                String crashid = responseMap.get("CrashID");
+                File file = new File(submittedDir, crashid + ".txt");
+                FileOutputStream fos = new FileOutputStream(file);
+                fos.write("Crash ID: ".getBytes());
+                fos.write(crashid.getBytes());
+                fos.close();
+            } else {
+                Log.i(LOGTAG, "Received failure HTTP response code from server: " + conn.getResponseCode());
+            }
+        } catch (IOException e) {
+            Log.e(LOGTAG, "exception during send: ", e);
+        } catch (URISyntaxException e) {
+            Log.e(LOGTAG, "exception during new URI: ", e);
+        }
+
+        doFinish();
+    }
+
+    private void doRestart() {
+        try {
+            String action = "android.intent.action.MAIN";
+            Intent intent = new Intent(action);
+            intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
+                                AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+            intent.putExtra("didRestart", true);
+            Log.i(LOGTAG, intent.toString());
+            startActivity(intent);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "error while trying to restart", e);
+        }
+    }
+
+    private String unescape(String string) {
+        return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
+    }
+}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/CrashReporterActivity.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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/. */
-
-package org.mozilla.gecko;
-
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.security.MessageDigest;
-import java.util.zip.GZIPOutputStream;
-
-import org.mozilla.gecko.AppConstants.Versions;
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.mozglue.MinidumpAnalyzer;
-import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCrashPingBuilder;
-import org.mozilla.gecko.telemetry.TelemetryDispatcher;
-import org.mozilla.gecko.util.INIParser;
-import org.mozilla.gecko.util.INISection;
-import org.mozilla.gecko.util.ProxySelector;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v7.app.AppCompatActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.EditText;
-
-// Registered: This activity is only registered in the manifest if MOZ_CRASHREPORTER is set.
-// CutPasteId: This lint is not worth fixing.  To fix it, cache all the findViewById results.
-@SuppressLint("Registered,CutPasteId")
-public class CrashReporterActivity extends AppCompatActivity
-{
-    private static final String LOGTAG = "GeckoCrashReporter";
-
-    private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
-    private static final String PASSED_MINI_DUMP_SUCCESS_KEY = "minidumpSuccess";
-    private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
-    private static final String PAGE_URL_KEY = "URL";
-    private static final String NOTES_KEY = "Notes";
-    private static final String SERVER_URL_KEY = "ServerURL";
-
-    private static final String CRASH_REPORT_SUFFIX = "/mozilla/Crash Reports/";
-    private static final String PENDING_SUFFIX = CRASH_REPORT_SUFFIX + "pending";
-    private static final String SUBMITTED_SUFFIX = CRASH_REPORT_SUFFIX + "submitted";
-
-    private static final String PREFS_SEND_REPORT   = "sendReport";
-    private static final String PREFS_INCLUDE_URL   = "includeUrl";
-    private static final String PREFS_ALLOW_CONTACT = "allowContact";
-    private static final String PREFS_CONTACT_EMAIL = "contactEmail";
-
-    private Handler mHandler;
-    private ProgressDialog mProgressDialog;
-    private File mPendingMinidumpFile;
-    private File mPendingExtrasFile;
-    private HashMap<String, String> mExtrasStringMap;
-    private boolean mMinidumpSucceeded;
-
-    private boolean moveFile(File inFile, File outFile) {
-        Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
-        if (inFile.renameTo(outFile))
-            return true;
-        try {
-            outFile.createNewFile();
-            Log.i(LOGTAG, "couldn't rename minidump file");
-            // so copy it instead
-            FileChannel inChannel = new FileInputStream(inFile).getChannel();
-            FileChannel outChannel = new FileOutputStream(outFile).getChannel();
-            long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
-            inChannel.close();
-            outChannel.close();
-
-            if (transferred > 0)
-                inFile.delete();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while copying minidump file: ", e);
-            return false;
-        }
-        return true;
-    }
-
-    private void doFinish() {
-        if (mHandler != null) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    finish();
-                }
-            });
-        }
-    }
-
-    @Override
-    public void finish() {
-        try {
-            if (mProgressDialog.isShowing()) {
-                mProgressDialog.dismiss();
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while closing progress dialog: ", e);
-        }
-        super.finish();
-    }
-
-    @Override
-    @SuppressLint("WrongThread") // We don't have a worker thread for the TelemetryDispatcher
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        // mHandler is created here so runnables can be run on the main thread
-        mHandler = new Handler();
-        setContentView(R.layout.crash_reporter);
-        mProgressDialog = new ProgressDialog(this);
-        mProgressDialog.setMessage(getString(R.string.sending_crash_report));
-
-        mMinidumpSucceeded = getIntent().getBooleanExtra(PASSED_MINI_DUMP_SUCCESS_KEY, false);
-        if (!mMinidumpSucceeded) {
-            Log.i(LOGTAG, "Failed to get minidump.");
-        }
-        String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
-        File passedMinidumpFile = new File(passedMinidumpPath);
-        File pendingDir = new File(getFilesDir(), PENDING_SUFFIX);
-        pendingDir.mkdirs();
-        mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
-        moveFile(passedMinidumpFile, mPendingMinidumpFile);
-
-        File extrasFile = new File(passedMinidumpPath.replaceAll("\\.dmp", ".extra"));
-        mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
-        moveFile(extrasFile, mPendingExtrasFile);
-
-        // Compute the minidump hash and generate the stack traces
-        computeMinidumpHash(mPendingExtrasFile, mPendingMinidumpFile);
-
-        try {
-            GeckoLoader.loadMozGlue(this);
-
-            if (!MinidumpAnalyzer.GenerateStacks(mPendingMinidumpFile.getPath(), /* fullStacks */ false)) {
-                Log.e(LOGTAG, "Could not generate stacks for this minidump: " + passedMinidumpPath);
-            }
-        } catch (UnsatisfiedLinkError e) {
-            Log.e(LOGTAG, "Could not load libmozglue.so, stacks for this crash won't be generated");
-        }
-
-        // Extract the annotations from the .extra file
-        mExtrasStringMap = new HashMap<String, String>();
-        readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
-
-        try {
-            // Find the profile name and path. Since we don't have any other way of getting it within
-            // this context we extract it from the crash dump path.
-            final File profileDir = passedMinidumpFile.getParentFile().getParentFile();
-            final String profileName = getProfileName(profileDir);
-
-            if (profileName != null) {
-                // Extract the crash dump ID and telemetry client ID, we need profile access for the latter.
-                final String passedMinidumpName = passedMinidumpFile.getName();
-                // Strip the .dmp suffix from the minidump name to obtain the crash ID.
-                final String crashId = passedMinidumpName.substring(0, passedMinidumpName.length() - 4);
-                final GeckoProfile profile = GeckoProfile.get(this, profileName, profileDir);
-                final String clientId = profile.getClientId();
-
-                // Assemble and send the crash ping
-                final TelemetryCrashPingBuilder pingBuilder =
-                    new TelemetryCrashPingBuilder(crashId, clientId, mExtrasStringMap);
-                final TelemetryDispatcher dispatcher = new TelemetryDispatcher(profileDir.getPath(), profileName);
-                dispatcher.queuePingForUpload(this, pingBuilder);
-            }
-        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
-            Log.e(LOGTAG, "Cannot send the crash ping: ", e);
-        }
-
-        // Notify GeckoApp that we've crashed, so it can react appropriately during the next start.
-        try {
-            File crashFlag = new File(GeckoProfileDirectories.getMozillaDirectory(this), "CRASHED");
-            crashFlag.createNewFile();
-        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
-            Log.e(LOGTAG, "Cannot set crash flag: ", e);
-        }
-
-        final CheckBox allowContactCheckBox = (CheckBox) findViewById(R.id.allow_contact);
-        final CheckBox includeUrlCheckBox = (CheckBox) findViewById(R.id.include_url);
-        final CheckBox sendReportCheckBox = (CheckBox) findViewById(R.id.send_report);
-        final EditText commentsEditText = (EditText) findViewById(R.id.comment);
-        final EditText emailEditText = (EditText) findViewById(R.id.email);
-
-        // Load CrashReporterActivity preferences to avoid redundant user input.
-        SharedPreferences prefs = GeckoSharedPrefs.forCrashReporter(this);
-        final boolean sendReport   = prefs.getBoolean(PREFS_SEND_REPORT, true);
-        final boolean includeUrl   = prefs.getBoolean(PREFS_INCLUDE_URL, false);
-        final boolean allowContact = prefs.getBoolean(PREFS_ALLOW_CONTACT, false);
-        final String contactEmail  = prefs.getString(PREFS_CONTACT_EMAIL, "");
-
-        allowContactCheckBox.setChecked(allowContact);
-        includeUrlCheckBox.setChecked(includeUrl);
-        sendReportCheckBox.setChecked(sendReport);
-        emailEditText.setText(contactEmail);
-
-        sendReportCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton checkbox, boolean isChecked) {
-                commentsEditText.setEnabled(isChecked);
-                commentsEditText.requestFocus();
-
-                includeUrlCheckBox.setEnabled(isChecked);
-                allowContactCheckBox.setEnabled(isChecked);
-                emailEditText.setEnabled(isChecked && allowContactCheckBox.isChecked());
-            }
-        });
-
-        allowContactCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton checkbox, boolean isChecked) {
-                // We need to check isEnabled() here because this listener is
-                // fired on rotation -- even when the checkbox is disabled.
-                emailEditText.setEnabled(checkbox.isEnabled() && isChecked);
-                emailEditText.requestFocus();
-            }
-        });
-
-        emailEditText.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // Even if the email EditText is disabled, allow it to be
-                // clicked and focused.
-                if (sendReportCheckBox.isChecked() && !v.isEnabled()) {
-                    allowContactCheckBox.setChecked(true);
-                    v.setEnabled(true);
-                    v.requestFocus();
-                }
-            }
-        });
-    }
-
-    @Override
-    public void onBackPressed() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setMessage(R.string.crash_closing_alert);
-        builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                dialog.dismiss();
-            }
-        });
-        builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                CrashReporterActivity.this.finish();
-            }
-        });
-        builder.show();
-    }
-
-    private void backgroundSendReport() {
-        final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
-        if (!sendReportCheckbox.isChecked()) {
-            doFinish();
-            return;
-        }
-
-        // Persist settings to avoid redundant user input.
-        savePrefs();
-
-        mProgressDialog.show();
-        new Thread(new Runnable() {
-            @Override
-            public void run() {
-                sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
-            }
-        }, "CrashReporterActivity Thread").start();
-    }
-
-    private void savePrefs() {
-        SharedPreferences.Editor editor = GeckoSharedPrefs.forCrashReporter(this).edit();
-
-        final boolean allowContact = ((CheckBox) findViewById(R.id.allow_contact)).isChecked();
-        final boolean includeUrl   = ((CheckBox) findViewById(R.id.include_url)).isChecked();
-        final boolean sendReport   = ((CheckBox) findViewById(R.id.send_report)).isChecked();
-        final String contactEmail  = ((EditText) findViewById(R.id.email)).getText().toString();
-
-        editor.putBoolean(PREFS_ALLOW_CONTACT, allowContact);
-        editor.putBoolean(PREFS_INCLUDE_URL, includeUrl);
-        editor.putBoolean(PREFS_SEND_REPORT, sendReport);
-        editor.putString(PREFS_CONTACT_EMAIL, contactEmail);
-
-        // A slight performance improvement via async apply() vs. blocking on commit().
-        editor.apply();
-    }
-
-    public void onCloseClick(View v) {  // bound via crash_reporter.xml
-        backgroundSendReport();
-    }
-
-    public void onRestartClick(View v) {  // bound via crash_reporter.xml
-        doRestart();
-        backgroundSendReport();
-    }
-
-    private String getProfileName(File profileDir) throws GeckoProfileDirectories.NoMozillaDirectoryException {
-        final File mozillaDir = GeckoProfileDirectories.getMozillaDirectory(this);
-        final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
-        String profileName = null;
-
-        if (parser.getSections() != null) {
-            for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) {
-                final INISection section = e.nextElement();
-                final String path = section.getStringProperty("Path");
-                final boolean isRelative = (section.getIntProperty("IsRelative") == 1);
-
-                if ((isRelative && path.equals(profileDir.getName())) ||
-                    path.equals(profileDir.getPath())) {
-                    profileName = section.getStringProperty("Name");
-                    break;
-                }
-            }
-        }
-
-        return profileName;
-    }
-
-
-    private void computeMinidumpHash(File extraFile, File minidump) {
-        try {
-            FileInputStream stream = new FileInputStream(minidump);
-            MessageDigest md = MessageDigest.getInstance("SHA-256");
-
-            try {
-                byte[] buffer = new byte[4096];
-                int readBytes;
-
-                while ((readBytes = stream.read(buffer)) != -1) {
-                    md.update(buffer, 0, readBytes);
-                }
-            } finally {
-              stream.close();
-            }
-
-            byte[] digest = md.digest();
-            StringBuilder hash = new StringBuilder(84);
-
-            hash.append("MinidumpSha256Hash=");
-
-            for (int i = 0; i < digest.length; i++) {
-              hash.append(Integer.toHexString((digest[i] & 0xf0) >> 4));
-              hash.append(Integer.toHexString(digest[i] & 0x0f));
-            }
-
-            hash.append('\n');
-
-            FileWriter writer = new FileWriter(extraFile, /* append */ true);
-
-            try {
-                writer.write(hash.toString());
-            } finally {
-                writer.close();
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while computing the minidump hash: ", e);
-        }
-    }
-
-    private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
-        try {
-            BufferedReader reader = new BufferedReader(new FileReader(filePath));
-            return readStringsFromReader(reader, stringMap);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while reading strings: ", e);
-            return false;
-        }
-    }
-
-    private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
-        String line;
-        while ((line = reader.readLine()) != null) {
-            int equalsPos = -1;
-            if ((equalsPos = line.indexOf('=')) != -1) {
-                String key = line.substring(0, equalsPos);
-                String val = unescape(line.substring(equalsPos + 1));
-                stringMap.put(key, val);
-            }
-        }
-        reader.close();
-        return true;
-    }
-
-    private String generateBoundary() {
-        // Generate some random numbers to fill out the boundary
-        int r0 = (int)(Integer.MAX_VALUE * Math.random());
-        int r1 = (int)(Integer.MAX_VALUE * Math.random());
-        return String.format("---------------------------%08X%08X", r0, r1);
-    }
-
-    private void sendPart(OutputStream os, String boundary, String name, String data) {
-        try {
-            os.write(("--" + boundary + "\r\n" +
-                      "Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
-                      "\r\n" +
-                      data + "\r\n"
-                     ).getBytes());
-        } catch (Exception ex) {
-            Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
-        }
-    }
-
-    private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
-        os.write(("--" + boundary + "\r\n" +
-                  "Content-Disposition: form-data; name=\"" + name + "\"; " +
-                  "filename=\"" + file.getName() + "\"\r\n" +
-                  "Content-Type: application/octet-stream\r\n" +
-                  "\r\n"
-                 ).getBytes());
-        FileChannel fc = new FileInputStream(file).getChannel();
-        fc.transferTo(0, fc.size(), Channels.newChannel(os));
-        fc.close();
-    }
-
-    private String readLogcat() {
-        final String crashReporterProc = " " + android.os.Process.myPid() + ' ';
-        BufferedReader br = null;
-        try {
-            // get at most the last 400 lines of logcat
-            Process proc = Runtime.getRuntime().exec(new String[] {
-                "logcat", "-v", "threadtime", "-t", "400", "-d", "*:D"
-            });
-            StringBuilder sb = new StringBuilder();
-            br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
-            for (String s = br.readLine(); s != null; s = br.readLine()) {
-                if (s.contains(crashReporterProc)) {
-                    // Don't include logs from the crash reporter's process.
-                    break;
-                }
-                sb.append(s).append('\n');
-            }
-            return sb.toString();
-        } catch (Exception e) {
-            return "Unable to get logcat: " + e.toString();
-        } finally {
-            if (br != null) {
-                try {
-                    br.close();
-                } catch (Exception e) {
-                    // ignore
-                }
-            }
-        }
-    }
-
-    private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
-        Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
-        final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
-
-        String spec = extras.get(SERVER_URL_KEY);
-        if (spec == null) {
-            doFinish();
-            return;
-        }
-
-        Log.i(LOGTAG, "server url: " + spec);
-        try {
-            final URL url = new URL(URLDecoder.decode(spec, "UTF-8"));
-            final URI uri = new URI(url.getProtocol(), url.getUserInfo(),
-                                    url.getHost(), url.getPort(),
-                                    url.getPath(), url.getQuery(), url.getRef());
-            HttpURLConnection conn = (HttpURLConnection)ProxySelector.openConnectionWithProxy(uri);
-            conn.setRequestMethod("POST");
-            String boundary = generateBoundary();
-            conn.setDoOutput(true);
-            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
-            conn.setRequestProperty("Content-Encoding", "gzip");
-
-            OutputStream os = new GZIPOutputStream(conn.getOutputStream());
-            for (String key : extras.keySet()) {
-                if (key.equals(PAGE_URL_KEY)) {
-                    if (includeURLCheckbox.isChecked())
-                        sendPart(os, boundary, key, extras.get(key));
-                } else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
-                    sendPart(os, boundary, key, extras.get(key));
-                }
-            }
-
-            // Add some extra information to notes so its displayed by
-            // crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
-            StringBuilder sb = new StringBuilder();
-            sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
-            sb.append(Build.MANUFACTURER).append(' ')
-              .append(Build.MODEL).append('\n')
-              .append(Build.FINGERPRINT);
-            sendPart(os, boundary, NOTES_KEY, sb.toString());
-
-            sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
-            sendPart(os, boundary, "Android_Model", Build.MODEL);
-            sendPart(os, boundary, "Android_Board", Build.BOARD);
-            sendPart(os, boundary, "Android_Brand", Build.BRAND);
-            sendPart(os, boundary, "Android_Device", Build.DEVICE);
-            sendPart(os, boundary, "Android_Display", Build.DISPLAY);
-            sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
-            sendPart(os, boundary, "Android_APP_ABI", AppConstants.MOZ_APP_ABI);
-            sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
-            sendPart(os, boundary, "Android_MIN_SDK", Integer.toString(AppConstants.Versions.MIN_SDK_VERSION));
-            sendPart(os, boundary, "Android_MAX_SDK", Integer.toString(AppConstants.Versions.MAX_SDK_VERSION));
-            try {
-                sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
-                sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
-            } catch (Exception ex) {
-                Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
-            }
-            sendPart(os, boundary, "Android_Version",  Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
-            if (Versions.feature16Plus && includeURLCheckbox.isChecked()) {
-                sendPart(os, boundary, "Android_Logcat", readLogcat());
-            }
-
-            String comment = ((EditText) findViewById(R.id.comment)).getText().toString();
-            if (!TextUtils.isEmpty(comment)) {
-                sendPart(os, boundary, "Comments", comment);
-            }
-
-            if (((CheckBox) findViewById(R.id.allow_contact)).isChecked()) {
-                String email = ((EditText) findViewById(R.id.email)).getText().toString();
-                sendPart(os, boundary, "Email", email);
-            }
-
-            sendPart(os, boundary, PASSED_MINI_DUMP_SUCCESS_KEY, mMinidumpSucceeded ? "True" : "False");
-            sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
-            os.write(("\r\n--" + boundary + "--\r\n").getBytes());
-            os.flush();
-            os.close();
-            BufferedReader br = new BufferedReader(
-                new InputStreamReader(conn.getInputStream()));
-            HashMap<String, String>  responseMap = new HashMap<String, String>();
-            readStringsFromReader(br, responseMap);
-
-            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
-                File submittedDir = new File(getFilesDir(),
-                                             SUBMITTED_SUFFIX);
-                submittedDir.mkdirs();
-                minidumpFile.delete();
-                extrasFile.delete();
-                String crashid = responseMap.get("CrashID");
-                File file = new File(submittedDir, crashid + ".txt");
-                FileOutputStream fos = new FileOutputStream(file);
-                fos.write("Crash ID: ".getBytes());
-                fos.write(crashid.getBytes());
-                fos.close();
-            } else {
-                Log.i(LOGTAG, "Received failure HTTP response code from server: " + conn.getResponseCode());
-            }
-        } catch (IOException e) {
-            Log.e(LOGTAG, "exception during send: ", e);
-        } catch (URISyntaxException e) {
-            Log.e(LOGTAG, "exception during new URI: ", e);
-        }
-
-        doFinish();
-    }
-
-    private void doRestart() {
-        try {
-            String action = "android.intent.action.MAIN";
-            Intent intent = new Intent(action);
-            intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
-                                AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
-            intent.putExtra("didRestart", true);
-            Log.i(LOGTAG, intent.toString());
-            startActivity(intent);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "error while trying to restart", e);
-        }
-    }
-
-    private String unescape(String string) {
-        return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
-    }
-}
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -130,20 +130,16 @@ android {
                     exclude 'com/google/android/exoplayer2/**'
                     exclude 'org/mozilla/gecko/media/GeckoHlsAudioRenderer.java'
                     exclude 'org/mozilla/gecko/media/GeckoHlsPlayer.java'
                     exclude 'org/mozilla/gecko/media/GeckoHlsRendererBase.java'
                     exclude 'org/mozilla/gecko/media/GeckoHlsVideoRenderer.java'
                     exclude 'org/mozilla/gecko/media/Utils.java'
                 }
 
-                if (!mozconfig.substs.MOZ_CRASHREPORTER) {
-                    exclude 'org/mozilla/gecko/CrashReporterService.java'
-                }
-
                 if (mozconfig.substs.MOZ_WEBRTC) {
                     srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/base/java/src"
                     srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src"
                     srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src"
                 }
             }
 
             assets {
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
@@ -115,20 +115,16 @@ public class TestRunnerActivity extends 
             final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
                 new GeckoRuntimeSettings.Builder();
             runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" });
             final Bundle extras = intent.getExtras();
             if (extras != null) {
                 runtimeSettingsBuilder.extras(extras);
             }
 
-            runtimeSettingsBuilder
-                    .nativeCrashReportingEnabled(true)
-                    .javaCrashReportingEnabled(true);
-
             sRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
             sRuntime.setDelegate(new GeckoRuntime.Delegate() {
                 @Override
                 public void onShutdown() {
                     mKillProcessOnDestroy = true;
                     finish();
                 }
             });
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -842,20 +842,17 @@ public class GeckoSessionTestRule extend
         final Class<?>[] classes = CALLBACK_CLASSES.toArray(new Class<?>[CALLBACK_CLASSES.size()]);
         mCallbackProxy = Proxy.newProxyInstance(GeckoSession.class.getClassLoader(),
                                                 classes, recorder);
 
         if (sRuntime == null) {
             final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
                 new GeckoRuntimeSettings.Builder();
             runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" })
-                    .extras(InstrumentationRegistry.getArguments())
-                    .nativeCrashReportingEnabled(true)
-                    .javaCrashReportingEnabled(true);
-
+                                  .extras(InstrumentationRegistry.getArguments());
             sRuntime = GeckoRuntime.create(
                 InstrumentationRegistry.getTargetContext(),
                 runtimeSettingsBuilder.build());
         }
 
         sRuntime.getSettings().setRemoteDebuggingEnabled(mWithDevTools);
 
         mMainSession = new GeckoSession(settings);
--- a/mobile/android/geckoview/src/main/AndroidManifest.xml
+++ b/mobile/android/geckoview/src/main/AndroidManifest.xml
@@ -1,100 +1,73 @@
-<?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="org.mozilla.geckoview">
+    package="org.mozilla.geckoview">
 
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
     <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
+
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
 
-    <uses-feature
-            android:name="android.hardware.location"
-            android:required="false"/>
-    <uses-feature
-            android:name="android.hardware.location.gps"
-            android:required="false"/>
+    <uses-feature android:name="android.hardware.location" android:required="false"/>
+    <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
     <uses-feature android:name="android.hardware.touchscreen"/>
 
-    <uses-permission android:name="android.permission.CAMERA"/>
-
-    <uses-feature
-            android:name="android.hardware.camera"
-            android:required="false"/>
-    <uses-feature
-            android:name="android.hardware.camera.autofocus"
-            android:required="false"/>
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-feature android:name="android.hardware.camera" android:required="false"/>
+    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
 
-    <!-- #ifdef MOZ_WEBRTC -->
-    <!--
-         TODO preprocess AndroidManifest.xml so that we can
-         conditionally include WebRTC permissions based on MOZ_WEBRTC.
-    -->
-    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
-    -->
-    <uses-feature
-            android:name="android.hardware.audio.low_latency"
-            android:required="false"/>
-    -->
-    <uses-feature
-            android:name="android.hardware.microphone"
-            android:required="false"/>
-    -->
-    <uses-feature
-            android:name="android.hardware.camera.any"
-            android:required="false"/>
-    -->
-    <!-- #endif -->
-
+    <!--#ifdef MOZ_WEBRTC-->
+    <!-- TODO preprocess AndroidManifest.xml so that we can
+         conditionally include WebRTC permissions based on MOZ_WEBRTC. -->
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>-->
+    <uses-feature android:name="android.hardware.audio.low_latency" android:required="false"/>-->
+    <uses-feature android:name="android.hardware.microphone" android:required="false"/>-->
+    <uses-feature android:name="android.hardware.camera.any" android:required="false"/>-->
+    <!--#endif-->
 
     <!-- App requires OpenGL ES 2.0 -->
-    <uses-feature
-            android:glEsVersion="0x00020000"
-            android:required="true"/>
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
 
     <application>
-
         <!-- New child services must also be added to the Fennec AndroidManifest.xml.in -->
         <service
-                android:name="org.mozilla.gecko.media.MediaManager"
-                android:enabled="true"
-                android:exported="false"
-                android:isolatedProcess="false"
-                android:process=":media">
+            android:name="org.mozilla.gecko.media.MediaManager"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":media"
+            android:isolatedProcess="false">
         </service>
+
         <service
-                android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
-                android:enabled="true"
-                android:exported="false"
-                android:isolatedProcess="false"
-                android:process=":geckomediaplugin">
+            android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":geckomediaplugin"
+            android:isolatedProcess="false">
         </service>
+
         <service
-                android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab"
-                android:enabled="true"
-                android:exported="false"
-                android:isolatedProcess="false"
-                android:process=":tab">
+            android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":tab"
+            android:isolatedProcess="false">
         </service>
+
         <service
-                android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
-                android:enabled="true"
-                android:exported="false"
-                android:isolatedProcess="false">
+            android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
+            android:enabled="true"
+            android:exported="false"
+            android:isolatedProcess="false">
         </service>
-        <service
-                android:name="org.mozilla.gecko.CrashReporterService"
-                android:exported="false"
-                android:process=":crashreporter">
-        </service>
-    </application>
+   </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
--- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
+++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl
@@ -6,15 +6,15 @@ package org.mozilla.gecko.process;
 
 import org.mozilla.gecko.process.IProcessManager;
 
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 
 interface IChildProcess {
     int getPid();
-    boolean start(in IProcessManager procMan, in String[] args, in Bundle extras, int flags,
+    boolean start(in IProcessManager procMan, in String[] args, in Bundle extras,
                   in ParcelFileDescriptor prefsPfd, in ParcelFileDescriptor ipcPfd,
                   in ParcelFileDescriptor crashReporterPfd,
                   in ParcelFileDescriptor crashAnnotationPfd);
 
     void crash();
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java
@@ -292,25 +292,26 @@ public class CrashHandler implements Thr
      * @param extraFile Path for the crash extra file
      * @return Whether the crash reporter was successfully launched
      */
     protected boolean launchCrashReporter(final String dumpFile, final String extraFile) {
         try {
             final Context context = getAppContext();
             final String javaPkg = getJavaPackageName();
             final String pkg = getAppPackageName();
-            final String component = javaPkg + ".CrashReporterService";
+            final String component = javaPkg + ".CrashReporter";
             final String action = javaPkg + ".reportCrash";
             final ProcessBuilder pb;
 
             if (context != null) {
                 final Intent intent = new Intent(action);
                 intent.setComponent(new ComponentName(pkg, component));
                 intent.putExtra("minidumpPath", dumpFile);
-                context.startService(intent);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(intent);
                 return true;
             }
 
             if (Build.VERSION.SDK_INT < 17) {
                 pb = new ProcessBuilder(
                     "/system/bin/am", "start",
                     "-a", action,
                     "-n", pkg + '/' + component,
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java
+++ /dev/null
@@ -1,373 +0,0 @@
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.mozglue.MinidumpAnalyzer;
-import org.mozilla.gecko.util.INIParser;
-import org.mozilla.gecko.util.INISection;
-import org.mozilla.gecko.util.ProxySelector;
-
-import android.app.IntentService;
-import android.content.Intent;
-import android.os.Build;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.security.MessageDigest;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.zip.GZIPOutputStream;
-
-public class CrashReporterService extends IntentService {
-    private static final String LOGTAG = "CrashReporter";
-    private static final String ACTION_REPORT_CRASH = "org.mozilla.gecko.reportCrash";
-    private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
-    private static final String PASSED_MINI_DUMP_SUCCESS_KEY = "minidumpSuccess";
-    private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
-    private static final String PAGE_URL_KEY = "URL";
-    private static final String NOTES_KEY = "Notes";
-    private static final String SERVER_URL_KEY = "ServerURL";
-
-    private static final String CRASH_REPORT_SUFFIX = "/mozilla/Crash Reports/";
-    private static final String PENDING_SUFFIX = CRASH_REPORT_SUFFIX + "pending";
-    private static final String SUBMITTED_SUFFIX = CRASH_REPORT_SUFFIX + "submitted";
-
-    private File mPendingMinidumpFile;
-    private File mPendingExtrasFile;
-    private HashMap<String, String> mExtrasStringMap;
-    private boolean mMinidumpSucceeded;
-
-    public CrashReporterService() {
-        super("CrashReporterService");
-    }
-
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        if (intent == null || !intent.getAction().equals(ACTION_REPORT_CRASH)) {
-            Log.d(LOGTAG, "Invalid or unknown action");
-            return;
-        }
-
-        Class<?> reporterActivityCls = getFennecReporterActivity();
-        if (reporterActivityCls != null) {
-            intent.setClass(this, reporterActivityCls);
-            startActivity(intent);
-            return;
-        }
-
-        submitCrash(intent);
-    }
-
-    private Class<?> getFennecReporterActivity() {
-        try {
-            return Class.forName("org.mozilla.gecko.CrashReporterActivity");
-        } catch (ClassNotFoundException e) {
-            return null;
-        }
-    }
-
-    private boolean moveFile(File inFile, File outFile) {
-        Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
-        if (inFile.renameTo(outFile))
-            return true;
-        try {
-            outFile.createNewFile();
-            Log.i(LOGTAG, "couldn't rename minidump file");
-            // so copy it instead
-            FileChannel inChannel = new FileInputStream(inFile).getChannel();
-            FileChannel outChannel = new FileOutputStream(outFile).getChannel();
-            long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
-            inChannel.close();
-            outChannel.close();
-
-            if (transferred > 0)
-                inFile.delete();
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while copying minidump file: ", e);
-            return false;
-        }
-        return true;
-    }
-
-    private void submitCrash(Intent intent) {
-        mMinidumpSucceeded = intent.getBooleanExtra(PASSED_MINI_DUMP_SUCCESS_KEY, false);
-        if (!mMinidumpSucceeded) {
-            Log.i(LOGTAG, "Failed to get minidump.");
-        }
-        String passedMinidumpPath = intent.getStringExtra(PASSED_MINI_DUMP_KEY);
-        File passedMinidumpFile = new File(passedMinidumpPath);
-        File pendingDir = new File(getFilesDir(), PENDING_SUFFIX);
-        pendingDir.mkdirs();
-        mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
-        moveFile(passedMinidumpFile, mPendingMinidumpFile);
-
-        File extrasFile = new File(passedMinidumpPath.replaceAll("\\.dmp", ".extra"));
-        mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
-        moveFile(extrasFile, mPendingExtrasFile);
-
-        // Compute the minidump hash and generate the stack traces
-        computeMinidumpHash(mPendingExtrasFile, mPendingMinidumpFile);
-
-        try {
-            GeckoLoader.loadMozGlue(this);
-
-            if (!MinidumpAnalyzer.GenerateStacks(mPendingMinidumpFile.getPath(), /* fullStacks */ false)) {
-                Log.e(LOGTAG, "Could not generate stacks for this minidump: " + passedMinidumpPath);
-            }
-        } catch (UnsatisfiedLinkError e) {
-            Log.e(LOGTAG, "Could not load libmozglue.so, stacks for this crash won't be generated");
-        }
-
-        // Extract the annotations from the .extra file
-        mExtrasStringMap = new HashMap<String, String>();
-        readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
-
-        try {
-            // Find the profile name and path. Since we don't have any other way of getting it within
-            // this context we extract it from the crash dump path.
-            final File profileDir = passedMinidumpFile.getParentFile().getParentFile();
-            final String profileName = getProfileName(profileDir);
-
-            if (profileName != null) {
-                // Extract the crash dump ID and telemetry client ID, we need profile access for the latter.
-                final String passedMinidumpName = passedMinidumpFile.getName();
-                // Strip the .dmp suffix from the minidump name to obtain the crash ID.
-                final String crashId = passedMinidumpName.substring(0, passedMinidumpName.length() - 4);
-                final GeckoProfile profile = GeckoProfile.get(this, profileName, profileDir);
-                final String clientId = profile.getClientId();
-            }
-        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
-            Log.e(LOGTAG, "Cannot send the crash ping: ", e);
-        }
-
-        // Notify GeckoApp that we've crashed, so it can react appropriately during the next start.
-        try {
-            File crashFlag = new File(GeckoProfileDirectories.getMozillaDirectory(this), "CRASHED");
-            crashFlag.createNewFile();
-        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
-            Log.e(LOGTAG, "Cannot set crash flag: ", e);
-        }
-
-        sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
-    }
-
-
-    private String getProfileName(File profileDir) throws GeckoProfileDirectories.NoMozillaDirectoryException {
-        final File mozillaDir = GeckoProfileDirectories.getMozillaDirectory(this);
-        final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
-        String profileName = null;
-
-        if (parser.getSections() != null) {
-            for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) {
-                final INISection section = e.nextElement();
-                final String path = section.getStringProperty("Path");
-                final boolean isRelative = (section.getIntProperty("IsRelative") == 1);
-
-                if ((isRelative && path.equals(profileDir.getName())) ||
-                        path.equals(profileDir.getPath())) {
-                    profileName = section.getStringProperty("Name");
-                    break;
-                }
-            }
-        }
-
-        return profileName;
-    }
-
-
-    private void computeMinidumpHash(File extraFile, File minidump) {
-        try {
-            FileInputStream stream = new FileInputStream(minidump);
-            MessageDigest md = MessageDigest.getInstance("SHA-256");
-
-            try {
-                byte[] buffer = new byte[4096];
-                int readBytes;
-
-                while ((readBytes = stream.read(buffer)) != -1) {
-                    md.update(buffer, 0, readBytes);
-                }
-            } finally {
-                stream.close();
-            }
-
-            byte[] digest = md.digest();
-            StringBuilder hash = new StringBuilder(84);
-
-            hash.append("MinidumpSha256Hash=");
-
-            for (int i = 0; i < digest.length; i++) {
-                hash.append(Integer.toHexString((digest[i] & 0xf0) >> 4));
-                hash.append(Integer.toHexString(digest[i] & 0x0f));
-            }
-
-            hash.append('\n');
-
-            FileWriter writer = new FileWriter(extraFile, /* append */ true);
-
-            try {
-                writer.write(hash.toString());
-            } finally {
-                writer.close();
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while computing the minidump hash: ", e);
-        }
-    }
-
-    private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
-        try {
-            BufferedReader reader = new BufferedReader(new FileReader(filePath));
-            return readStringsFromReader(reader, stringMap);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "exception while reading strings: ", e);
-            return false;
-        }
-    }
-
-    private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
-        String line;
-        while ((line = reader.readLine()) != null) {
-            int equalsPos = -1;
-            if ((equalsPos = line.indexOf('=')) != -1) {
-                String key = line.substring(0, equalsPos);
-                String val = unescape(line.substring(equalsPos + 1));
-                stringMap.put(key, val);
-            }
-        }
-        reader.close();
-        return true;
-    }
-
-    private String generateBoundary() {
-        // Generate some random numbers to fill out the boundary
-        int r0 = (int)(Integer.MAX_VALUE * Math.random());
-        int r1 = (int)(Integer.MAX_VALUE * Math.random());
-        return String.format("---------------------------%08X%08X", r0, r1);
-    }
-
-    private void sendPart(OutputStream os, String boundary, String name, String data) {
-        try {
-            os.write(("--" + boundary + "\r\n" +
-                    "Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
-                    "\r\n" +
-                    data + "\r\n"
-            ).getBytes());
-        } catch (Exception ex) {
-            Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
-        }
-    }
-
-    private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
-        os.write(("--" + boundary + "\r\n" +
-                "Content-Disposition: form-data; name=\"" + name + "\"; " +
-                "filename=\"" + file.getName() + "\"\r\n" +
-                "Content-Type: application/octet-stream\r\n" +
-                "\r\n"
-        ).getBytes());
-        FileChannel fc = new FileInputStream(file).getChannel();
-        fc.transferTo(0, fc.size(), Channels.newChannel(os));
-        fc.close();
-    }
-
-    private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
-        Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
-
-        String spec = extras.get(SERVER_URL_KEY);
-        if (spec == null) {
-            return;
-        }
-
-        try {
-            final URL url = new URL(URLDecoder.decode(spec, "UTF-8"));
-            final URI uri = new URI(url.getProtocol(), url.getUserInfo(),
-                    url.getHost(), url.getPort(),
-                    url.getPath(), url.getQuery(), url.getRef());
-            HttpURLConnection conn = (HttpURLConnection) ProxySelector.openConnectionWithProxy(uri);
-            conn.setRequestMethod("POST");
-            String boundary = generateBoundary();
-            conn.setDoOutput(true);
-            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
-            conn.setRequestProperty("Content-Encoding", "gzip");
-
-            OutputStream os = new GZIPOutputStream(conn.getOutputStream());
-            for (String key : extras.keySet()) {
-                if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
-                    sendPart(os, boundary, key, extras.get(key));
-                }
-            }
-
-            StringBuilder sb = new StringBuilder();
-            sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
-            sb.append(Build.MANUFACTURER).append(' ')
-                    .append(Build.MODEL).append('\n')
-                    .append(Build.FINGERPRINT);
-            sendPart(os, boundary, NOTES_KEY, sb.toString());
-
-            sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
-            sendPart(os, boundary, "Android_Model", Build.MODEL);
-            sendPart(os, boundary, "Android_Board", Build.BOARD);
-            sendPart(os, boundary, "Android_Brand", Build.BRAND);
-            sendPart(os, boundary, "Android_Device", Build.DEVICE);
-            sendPart(os, boundary, "Android_Display", Build.DISPLAY);
-            sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
-            sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
-            try {
-                sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
-                sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
-            } catch (Exception ex) {
-                Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
-            }
-            sendPart(os, boundary, "Android_Version",  Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
-            sendPart(os, boundary, PASSED_MINI_DUMP_SUCCESS_KEY, mMinidumpSucceeded ? "True" : "False");
-            sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
-            os.write(("\r\n--" + boundary + "--\r\n").getBytes());
-            os.flush();
-            os.close();
-            BufferedReader br = new BufferedReader(
-                    new InputStreamReader(conn.getInputStream()));
-            HashMap<String, String>  responseMap = new HashMap<String, String>();
-            readStringsFromReader(br, responseMap);
-
-            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
-                File submittedDir = new File(getFilesDir(),
-                        SUBMITTED_SUFFIX);
-                submittedDir.mkdirs();
-                minidumpFile.delete();
-                extrasFile.delete();
-                String crashid = responseMap.get("CrashID");
-                File file = new File(submittedDir, crashid + ".txt");
-                FileOutputStream fos = new FileOutputStream(file);
-                fos.write("Crash ID: ".getBytes());
-                fos.write(crashid.getBytes());
-                fos.close();
-                Log.i(LOGTAG, "Successfully sent crash report: " + crashid);
-            } else {
-                Log.w(LOGTAG, "Received failure HTTP response code from server: " + conn.getResponseCode());
-            }
-        } catch (IOException e) {
-            Log.e(LOGTAG, "exception during send: ", e);
-        } catch (URISyntaxException e) {
-            Log.e(LOGTAG, "exception during new URI: ", e);
-        }
-    }
-
-    private String unescape(String string) {
-        return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
-    }
-}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -106,17 +106,17 @@ import android.widget.AbsoluteLayout;
 
 public class GeckoAppShell
 {
     private static final String LOGTAG = "GeckoAppShell";
 
     // We have static members only.
     private GeckoAppShell() { }
 
-    private static class GeckoCrashHandler extends CrashHandler {
+    private static final CrashHandler CRASH_HANDLER = new CrashHandler() {
         @Override
         protected String getAppPackageName() {
             final Context appContext = getAppContext();
             if (appContext == null) {
                 return "<unknown>";
             }
             return appContext.getPackageName();
         }
@@ -169,28 +169,20 @@ public class GeckoAppShell
                 // Only use Java crash reporter if enabled on official build.
                 return super.reportException(thread, exc);
             }
             return false;
         }
     };
 
     private static String sAppNotes;
-    private static CrashHandler sCrashHandler;
 
-    public static synchronized CrashHandler ensureCrashHandling() {
-        if (sCrashHandler == null) {
-            sCrashHandler = new GeckoCrashHandler();
-        }
-
-        return sCrashHandler;
-    }
-
-    public static synchronized boolean isCrashHandlingEnabled() {
-        return sCrashHandler != null;
+    public static CrashHandler ensureCrashHandling() {
+        // Crash handling is automatically enabled when GeckoAppShell is loaded.
+        return CRASH_HANDLER;
     }
 
     @WrapForJNI(exceptionMode = "ignore")
     /* package */ static synchronized String getAppNotes() {
         return sAppNotes;
     }
 
     public static synchronized void appendAppNotesToCrashReport(final String notes) {
@@ -283,20 +275,18 @@ public class GeckoAppShell
      */
 
     @WrapForJNI(exceptionMode = "ignore")
     private static String getExceptionStackTrace(Throwable e) {
         return CrashHandler.getExceptionStackTrace(CrashHandler.getRootException(e));
     }
 
     @WrapForJNI(exceptionMode = "ignore")
-    private static synchronized void handleUncaughtException(Throwable e) {
-        if (sCrashHandler != null) {
-            sCrashHandler.uncaughtException(null, e);
-        }
+    private static void handleUncaughtException(Throwable e) {
+        CRASH_HANDLER.uncaughtException(null, e);
     }
 
     private static float getLocationAccuracy(Location location) {
         float radius = location.getAccuracy();
         return (location.hasAccuracy() && radius > 0) ? radius : 1001;
     }
 
     // Permissions are explicitly checked when requesting content permission.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -7,36 +7,35 @@ package org.mozilla.gecko;
 
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.process.GeckoProcessManager;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.geckoview.BuildConfig;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.File;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Locale;
 import java.util.StringTokenizer;
 
 public class GeckoThread extends Thread {
     private static final String LOGTAG = "GeckoThread";
 
     public enum State implements NativeQueue.State {
         // After being loaded by class loader.
@@ -120,20 +119,18 @@ public class GeckoThread extends Thread 
     @WrapForJNI
     private static final ClassLoader clsLoader = GeckoThread.class.getClassLoader();
     @WrapForJNI
     private static MessageQueue msgQueue;
     @WrapForJNI
     private static int uiThreadId;
 
     // Main process parameters
-    public static final int FLAG_DEBUGGING = 1 << 0; // Debugging mode.
-    public static final int FLAG_PRELOAD_CHILD = 1 << 1; // Preload child during main thread start.
-    public static final int FLAG_ENABLE_NATIVE_CRASHREPORTER = 1 << 2; // Enable native crash reporting
-    public static final int FLAG_ENABLE_JAVA_CRASHREPORTER = 1 << 3; // Enable java crash reporting
+    public static final int FLAG_DEBUGGING = 1; // Debugging mode.
+    public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start.
 
     private static final String EXTRA_ARGS = "args";
     private static final String EXTRA_PREFS_FD = "prefsFd";
     private static final String EXTRA_IPC_FD = "ipcFd";
     private static final String EXTRA_CRASH_FD = "crashFd";
     private static final String EXTRA_CRASH_ANNOTATION_FD = "crashAnnotationFd";
 
     private boolean mInitialized;
@@ -179,24 +176,21 @@ public class GeckoThread extends Thread 
     }
 
     public static boolean initMainProcess(final GeckoProfile profile, final String[] args,
                                           final Bundle extras, final int flags) {
         return INSTANCE.init(profile, args, extras, flags, /* fd */ -1,
                              /* fd */ -1, /* fd */ -1, /* fd */ -1);
     }
 
-    public static boolean initChildProcess(final String[] args,
-                                           final Bundle extras,
-                                           final int flags,
-                                           final int prefsFd,
-                                           final int ipcFd,
+    public static boolean initChildProcess(final String[] args, final Bundle extras,
+                                           final int prefsFd, final int ipcFd,
                                            final int crashFd,
                                            final int crashAnnotationFd) {
-        return INSTANCE.init(/* profile */ null, args, extras, flags,
+        return INSTANCE.init(/* profile */ null, args, extras, /* flags */ 0,
                              prefsFd, ipcFd, crashFd, crashAnnotationFd);
     }
 
     private static boolean canUseProfile(final Context context, final GeckoProfile profile,
                                          final String profileName, final File profileDir) {
         if (profileDir != null && !profileDir.isDirectory()) {
             return false;
         }
@@ -378,50 +372,20 @@ public class GeckoThread extends Thread 
         return mProfile;
     }
 
     public static @Nullable Bundle getActiveExtras() {
         synchronized (INSTANCE) {
             if (!INSTANCE.mInitialized) {
                 return null;
             }
-            return new Bundle(INSTANCE.mExtras);
-        }
-    }
-
-    public static int getActiveFlags() {
-        synchronized (INSTANCE) {
-            if (!INSTANCE.mInitialized) {
-                return 0;
-            }
-
-            return INSTANCE.mFlags;
+            return INSTANCE.mExtras;
         }
     }
 
-    private static ArrayList<String> getEnvFromExtras(final Bundle extras) {
-        if (extras == null) {
-            return new ArrayList<>();
-        }
-
-        ArrayList<String> result = new ArrayList<>();
-        if (extras != null) {
-            String env = extras.getString("env0");
-            for (int c = 1; env != null; c++) {
-                if (BuildConfig.DEBUG) {
-                    Log.d(LOGTAG, "env var: " + env);
-                }
-                result.add(env);
-                env = extras.getString("env" + c);
-            }
-        }
-
-        return result;
-    }
-
     @Override
     public void run() {
         Log.i(LOGTAG, "preparing to run Gecko");
 
         Looper.prepare();
         GeckoThread.msgQueue = Looper.myQueue();
         ThreadUtils.sGeckoThread = this;
         ThreadUtils.sGeckoHandler = new Handler();
@@ -473,31 +437,17 @@ public class GeckoThread extends Thread 
 
         final Context context = GeckoAppShell.getApplicationContext();
         final String[] args = isChildProcess() ? mArgs : getMainProcessArgs();
 
         if ((mFlags & FLAG_DEBUGGING) != 0) {
             Log.i(LOGTAG, "RunGecko - args = " + TextUtils.join(" ", args));
         }
 
-        final List<String> env = getEnvFromExtras(mExtras);
-
-        // In Gecko, the native crash reporter is enabled by default in opt builds, and
-        // disabled by default in debug builds.
-        if ((mFlags & FLAG_ENABLE_NATIVE_CRASHREPORTER) == 0 && !BuildConfig.DEBUG_BUILD) {
-            env.add(0, "MOZ_CRASHREPORTER_DISABLE=1");
-        } else if ((mFlags & FLAG_ENABLE_NATIVE_CRASHREPORTER) != 0 && BuildConfig.DEBUG_BUILD) {
-            env.add(0, "MOZ_CRASHREPORTER=1");
-        }
-
-        if ((mFlags & FLAG_ENABLE_JAVA_CRASHREPORTER) != 0) {
-            GeckoAppShell.ensureCrashHandling();
-        }
-
-        GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath(), env);
+        GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath(), mExtras);
 
         // And go.
         GeckoLoader.nativeRun(args,
                               mExtras.getInt(EXTRA_PREFS_FD, -1),
                               mExtras.getInt(EXTRA_IPC_FD, -1),
                               mExtras.getInt(EXTRA_CRASH_FD, -1),
                               mExtras.getInt(EXTRA_CRASH_ANNOTATION_FD, -1));
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.mozglue;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
-import java.util.Collection;
 import java.util.Locale;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
@@ -88,19 +87,27 @@ public final class GeckoLoader {
         if (oldDir.exists()) {
             delTree(oldDir);
         }
         return tmpDir;
     }
 
     public synchronized static void setupGeckoEnvironment(final Context context,
                                                           final String profilePath,
-                                                          final Collection<String> env) {
-        for (final String e : env) {
-            putenv(e);
+                                                          final Bundle extras) {
+        // if we have an intent (we're being launched by an activity)
+        // read in any environmental variables from it here
+        if (extras != null) {
+            String env = extras.getString("env0");
+            Log.d(LOGTAG, "Gecko environment env0: " + env);
+            for (int c = 1; env != null; c++) {
+                putenv(env);
+                env = extras.getString("env" + c);
+                Log.d(LOGTAG, "env" + c + ": " + env);
+            }
         }
 
         try {
             final File dataDir = new File(context.getApplicationInfo().dataDir);
             putenv("MOZ_ANDROID_DATA_DIR=" + dataDir.getCanonicalPath());
         } catch (final java.io.IOException e) {
             Log.e(LOGTAG, "Failed to resolve app data directory");
         }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
@@ -176,21 +176,16 @@ public final class GeckoProcessManager e
 
     @WrapForJNI
     private static int start(final String type, final String[] args,
                              final int prefsFd, final int ipcFd,
                              final int crashFd, final int crashAnnotationFd) {
         return INSTANCE.start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false);
     }
 
-    private int filterFlagsForChild(int flags) {
-        return flags & (GeckoThread.FLAG_ENABLE_JAVA_CRASHREPORTER |
-                GeckoThread.FLAG_ENABLE_NATIVE_CRASHREPORTER);
-    }
-
     private int start(final String type, final String[] args, final int prefsFd,
                       final int ipcFd, final int crashFd,
                       final int crashAnnotationFd, final boolean retry) {
         final ChildConnection connection = getConnection(type);
         final IChildProcess child = connection.bind();
         if (child == null) {
             return 0;
         }
@@ -205,21 +200,19 @@ public final class GeckoProcessManager e
             ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
             crashPfd = (crashFd >= 0) ? ParcelFileDescriptor.fromFd(crashFd) : null;
             crashAnnotationPfd = (crashAnnotationFd >= 0) ? ParcelFileDescriptor.fromFd(crashAnnotationFd) : null;
         } catch (final IOException e) {
             Log.e(LOGTAG, "Cannot create fd for " + type, e);
             return 0;
         }
 
-        final int flags = filterFlagsForChild(GeckoThread.getActiveFlags());
-
         boolean started = false;
         try {
-            started = child.start(this, args, extras, flags, prefsPfd, ipcPfd, crashPfd,
+            started = child.start(this, args, extras, prefsPfd, ipcPfd, crashPfd,
                                   crashAnnotationPfd);
         } catch (final RemoteException e) {
         }
 
         if (!started) {
             if (retry) {
                 Log.e(LOGTAG, "Cannot restart child " + type);
                 return 0;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
@@ -19,17 +19,19 @@ import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
 public class GeckoServiceChildProcess extends Service {
+
     private static final String LOGTAG = "GeckoServiceChildProcess";
+
     private static IProcessManager sProcessManager;
 
     @WrapForJNI(calledFrom = "gecko")
     private static IGeckoEditableParent getEditableParent(final long contentId,
                                                           final long tabId) {
         try {
             return sProcessManager.getEditableParent(contentId, tabId);
         } catch (final RemoteException e) {
@@ -37,16 +39,17 @@ public class GeckoServiceChildProcess ex
             return null;
         }
     }
 
     @Override
     public void onCreate() {
         super.onCreate();
 
+        GeckoAppShell.ensureCrashHandling();
         GeckoAppShell.setApplicationContext(getApplicationContext());
     }
 
     @Override
     public int onStartCommand(final Intent intent, final int flags, final int startId) {
         return Service.START_NOT_STICKY;
     }
 
@@ -55,17 +58,16 @@ public class GeckoServiceChildProcess ex
         public int getPid() {
             return Process.myPid();
         }
 
         @Override
         public boolean start(final IProcessManager procMan,
                              final String[] args,
                              final Bundle extras,
-                             final int flags,
                              final ParcelFileDescriptor prefsPfd,
                              final ParcelFileDescriptor ipcPfd,
                              final ParcelFileDescriptor crashReporterPfd,
                              final ParcelFileDescriptor crashAnnotationPfd) {
             synchronized (GeckoServiceChildProcess.class) {
                 if (sProcessManager != null) {
                     Log.e(LOGTAG, "Child process already started");
                     return false;
@@ -78,17 +80,17 @@ public class GeckoServiceChildProcess ex
             final int crashReporterFd = crashReporterPfd != null ?
                                         crashReporterPfd.detachFd() : -1;
             final int crashAnnotationFd = crashAnnotationPfd != null ?
                                           crashAnnotationPfd.detachFd() : -1;
 
             ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
-                    if (GeckoThread.initChildProcess(args, extras, flags, prefsFd, ipcFd, crashReporterFd,
+                    if (GeckoThread.initChildProcess(args, extras, prefsFd, ipcFd, crashReporterFd,
                                                      crashAnnotationFd)) {
                         GeckoThread.launch();
                     }
                 }
             });
             return true;
         }
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
@@ -79,29 +79,19 @@ public final class GeckoRuntime implemen
             }
         }
     };
 
     /* package */ boolean init(final @NonNull GeckoRuntimeSettings settings) {
         if (DEBUG) {
             Log.d(LOGTAG, "init");
         }
-        int flags = 0;
-        if (settings.getUseContentProcessHint()) {
-            flags |= GeckoThread.FLAG_PRELOAD_CHILD;
-        }
-
-        if (settings.getNativeCrashReportingEnabled()) {
-            flags |= GeckoThread.FLAG_ENABLE_NATIVE_CRASHREPORTER;
-        }
-
-        if (settings.getJavaCrashReportingEnabled()) {
-            flags |= GeckoThread.FLAG_ENABLE_JAVA_CRASHREPORTER;
-        }
-
+        final int flags = settings.getUseContentProcessHint()
+                          ? GeckoThread.FLAG_PRELOAD_CHILD
+                          : 0;
         if (GeckoThread.initMainProcess(/* profile */ null,
                                         settings.getArguments(),
                                         settings.getExtras(),
                                         flags)) {
             if (!GeckoThread.launch()) {
                 Log.d(LOGTAG, "init failed (GeckoThread already launched)");
                 return false;
             }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -35,19 +35,17 @@ public final class GeckoRuntimeSettings 
         public @NonNull GeckoRuntimeSettings build() {
             return new GeckoRuntimeSettings(mSettings);
         }
 
         /**
          * Set the content process hint flag.
          *
          * @param use If true, this will reload the content process for future use.
-         *            Default is false.
          * @return This Builder instance.
-
          */
         public @NonNull Builder useContentProcessHint(final boolean use) {
             mSettings.mUseContentProcess = use;
             return this;
         }
 
         /**
          * Set the custom Gecko process arguments.
@@ -76,17 +74,16 @@ public final class GeckoRuntimeSettings 
             mSettings.mExtras = extras;
             return this;
         }
 
         /**
          * Set whether JavaScript support should be enabled.
          *
          * @param flag A flag determining whether JavaScript should be enabled.
-         *             Default is true.
          * @return This Builder instance.
          */
         public @NonNull Builder javaScriptEnabled(final boolean flag) {
             mSettings.mJavaScript.set(flag);
             return this;
         }
 
         /**
@@ -99,51 +96,22 @@ public final class GeckoRuntimeSettings 
             mSettings.mRemoteDebugging.set(enabled);
             return this;
         }
 
         /**
          * Set whether support for web fonts should be enabled.
          *
          * @param flag A flag determining whether web fonts should be enabled.
-         *             Default is true.
          * @return This Builder instance.
          */
         public @NonNull Builder webFontsEnabled(final boolean flag) {
             mSettings.mWebFonts.set(flag);
             return this;
         }
-
-        /**
-         * Set whether crash reporting for native code should be enabled. This will cause
-         * a SIGSEGV handler to be installed, and any crash encountered there will be
-         * reported to Mozilla.
-         *
-         * @param enabled A flag determining whether native crash reporting should be enabled.
-         *                Defaults to false.
-         * @return This Builder.
-         */
-        public @NonNull Builder nativeCrashReportingEnabled(final boolean enabled) {
-            mSettings.mNativeCrashReporting = enabled;
-            return this;
-        }
-
-        /**
-         * Set whether crash reporting for Java code should be enabled. This will cause
-         * a default unhandled exception handler to be installed, and any exceptions encountered
-         * will automatically reported to Mozilla.
-         *
-         * @param enabled A flag determining whether Java crash reporting should be enabled.
-         *                Defaults to false.
-         * @return This Builder.
-         */
-        public @NonNull Builder javaCrashReportingEnabled(final boolean enabled) {
-            mSettings.mJavaCrashReporting = enabled;
-            return this;
-        }
     }
 
     /* package */ GeckoRuntime runtime;
     /* package */ boolean mUseContentProcess;
     /* package */ String[] mArgs;
     /* package */ Bundle mExtras;
     /* package */ int prefCount;
 
@@ -177,18 +145,16 @@ public final class GeckoRuntimeSettings 
     }
 
     /* package */ Pref<Boolean> mJavaScript = new Pref<Boolean>(
         "javascript.enabled", true);
     /* package */ Pref<Boolean> mRemoteDebugging = new Pref<Boolean>(
         "devtools.debugger.remote-enabled", false);
     /* package */ Pref<Boolean> mWebFonts = new Pref<Boolean>(
         "browser.display.use_document_fonts", true);
-    /* package */ boolean mNativeCrashReporting;
-    /* package */ boolean mJavaCrashReporting;
 
     private final Pref<?>[] mPrefs = new Pref<?>[] {
         mJavaScript, mRemoteDebugging, mWebFonts
     };
 
     /* package */ GeckoRuntimeSettings() {
         this(null);
     }
@@ -209,19 +175,16 @@ public final class GeckoRuntimeSettings 
         mExtras = new Bundle(settings.getExtras());
 
         for (int i = 0; i < mPrefs.length; i++) {
             // We know this is safe.
             @SuppressWarnings("unchecked")
             final Pref<Object> uncheckedPref = (Pref<Object>) mPrefs[i];
             uncheckedPref.set(settings.mPrefs[i].get());
         }
-
-        mNativeCrashReporting = settings.mNativeCrashReporting;
-        mJavaCrashReporting = settings.mJavaCrashReporting;
     }
 
     /* package */ void flush() {
         for (final Pref<?> pref: mPrefs) {
             pref.flush();
         }
     }
 
@@ -307,68 +270,44 @@ public final class GeckoRuntimeSettings 
      * @param flag A flag determining whether web fonts should be enabled.
      * @return This GeckoRuntimeSettings instance.
      */
     public @NonNull GeckoRuntimeSettings setWebFontsEnabled(final boolean flag) {
         mWebFonts.set(flag);
         return this;
     }
 
-    /**
-     * Get whether native crash reporting is enabled or not.
-     *
-     * @return True if native crash reporting is enabled.
-     */
-    public boolean getNativeCrashReportingEnabled() {
-        return mNativeCrashReporting;
-    }
-
-    /**
-     * Get whether Java crash reporting is enabled or not.
-     *
-     * @return True if Java crash reporting is enabled.
-     */
-    public boolean getJavaCrashReportingEnabled() {
-        return mJavaCrashReporting;
-    }
-
     @Override // Parcelable
     public int describeContents() {
         return 0;
     }
 
     @Override // Parcelable
     public void writeToParcel(Parcel out, int flags) {
-        ParcelableUtils.writeBoolean(out, mUseContentProcess);
+        out.writeByte((byte) (mUseContentProcess ? 1 : 0));
         out.writeStringArray(mArgs);
         mExtras.writeToParcel(out, flags);
 
         for (final Pref<?> pref : mPrefs) {
             out.writeValue(pref.get());
         }
-
-        ParcelableUtils.writeBoolean(out, mNativeCrashReporting);
-        ParcelableUtils.writeBoolean(out, mJavaCrashReporting);
     }
 
     // AIDL code may call readFromParcel even though it's not part of Parcelable.
     public void readFromParcel(final Parcel source) {
-        mUseContentProcess = ParcelableUtils.readBoolean(source);
+        mUseContentProcess = source.readByte() == 1;
         mArgs = source.createStringArray();
         mExtras.readFromParcel(source);
 
         for (final Pref<?> pref : mPrefs) {
             // We know this is safe.
             @SuppressWarnings("unchecked")
             final Pref<Object> uncheckedPref = (Pref<Object>) pref;
             uncheckedPref.set(source.readValue(getClass().getClassLoader()));
         }
-
-        mNativeCrashReporting = ParcelableUtils.readBoolean(source);
-        mJavaCrashReporting = ParcelableUtils.readBoolean(source);
     }
 
     public static final Parcelable.Creator<GeckoRuntimeSettings> CREATOR
         = new Parcelable.Creator<GeckoRuntimeSettings>() {
         @Override
         public GeckoRuntimeSettings createFromParcel(final Parcel in) {
             final GeckoRuntimeSettings settings = new GeckoRuntimeSettings();
             settings.readFromParcel(in);
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ParcelableUtils.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * vim: ts=4 sw=4 expandtab:
- * 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/. */
-
-package org.mozilla.geckoview;
-
-import android.os.Parcel;
-
-class ParcelableUtils {
-    public static void writeBoolean(Parcel out, boolean val) {
-        out.writeByte((byte) (val ? 1 : 0));
-    }
-
-    public static boolean readBoolean(Parcel source) {
-        return source.readByte() == 1;
-    }
-}
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -62,22 +62,17 @@ public class GeckoViewActivity extends A
                 // each build.
                 runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" });
             }
 
             final Bundle extras = getIntent().getExtras();
             if (extras != null) {
                 runtimeSettingsBuilder.extras(extras);
             }
-
-            runtimeSettingsBuilder
-                    .useContentProcessHint(useMultiprocess)
-                    .nativeCrashReportingEnabled(true)
-                    .javaCrashReportingEnabled(true);
-
+            runtimeSettingsBuilder.useContentProcessHint(useMultiprocess);
             sGeckoRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
         }
 
         final GeckoSessionSettings sessionSettings = new GeckoSessionSettings();
         sessionSettings.setBoolean(GeckoSessionSettings.USE_MULTIPROCESS,
                                    useMultiprocess);
         mGeckoSession = new GeckoSession(sessionSettings);
 
--- a/netwerk/base/nsInputStreamPump.cpp
+++ b/netwerk/base/nsInputStreamPump.cpp
@@ -456,29 +456,27 @@ nsInputStreamPump::OnInputStreamReady(ns
         if (nextState == STATE_STOP && !NS_IsMainThread()) {
             mRetargeting = true;
         }
 
         // Unset mProcessingCallbacks here (while we have lock) so our own call to
         // EnsureWaiting isn't blocked by it.
         mProcessingCallbacks = false;
 
-        // We must break the loop when we're switching event delivery to another
-        // thread and the input stream pump is suspended, otherwise
-        // OnStateStop() might be called off the main thread. See bug 1026951
-        // comment #107 for the exact scenario.
-        if (mSuspendCount && mRetargeting) {
+        // We must break the loop if suspended during one of the previous
+        // operation.
+        if (mSuspendCount) {
             mState = nextState;
             mWaitingForInputStreamReady = false;
             break;
         }
 
         // Wait asynchronously if there is still data to transfer, or we're
         // switching event delivery to another thread.
-        if (!mSuspendCount && (stillTransferring || mRetargeting)) {
+        if (stillTransferring || mRetargeting) {
             mState = nextState;
             mWaitingForInputStreamReady = false;
             nsresult rv = EnsureWaiting();
             if (NS_SUCCEEDED(rv))
                 break;
 
             // Failure to start asynchronous wait: stop transfer.
             // Do not set mStatus if it was previously set to report a failure.
@@ -621,17 +619,17 @@ nsInputStreamPump::OnStateTransfer()
                 }
             }
             else
                 mStreamOffset += odaAvail; // assume ODA behaved well
         }
     }
 
     // an error returned from Available or OnDataAvailable should cause us to
-    // abort; however, we must not stomp on mStatus if already canceled.
+    // abort; however, we must not stop on mStatus if already canceled.
 
     if (NS_SUCCEEDED(mStatus)) {
         if (NS_FAILED(rv))
             mStatus = rv;
         else if (avail) {
             // if stream is now closed, advance to STATE_STOP right away.
             // Available may return 0 bytes available at the moment; that
             // would not mean that we are done.
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -1,15 +1,15 @@
 # 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/.
 
 import re
 
-PHYSICAL_SIDES = ["top", "left", "bottom", "right"]
+PHYSICAL_SIDES = ["top", "right", "bottom", "left"]
 LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"]
 PHYSICAL_SIZES = ["width", "height"]
 LOGICAL_SIZES = ["block-size", "inline-size"]
 
 # bool is True when logical
 ALL_SIDES = [(side, False) for side in PHYSICAL_SIDES] + [(side, True) for side in LOGICAL_SIDES]
 ALL_SIZES = [(size, False) for size in PHYSICAL_SIZES] + [(size, True) for size in LOGICAL_SIZES]
 
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -754,17 +754,17 @@
 
         ${caller.body()}
     }
     % endif
 </%def>
 
 <%def name="four_sides_shorthand(name, sub_property_pattern, parser_function,
                                  needs_context=True, allow_quirks=False, **kwargs)">
-    <% sub_properties=' '.join(sub_property_pattern % side for side in ['top', 'right', 'bottom', 'left']) %>
+    <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %>
     <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)">
         #[allow(unused_imports)]
         use parser::Parse;
         use values::generics::rect::Rect;
         use values::specified;
 
         pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                    -> Result<Longhands, ParseError<'i>> {
--- a/taskcluster/ci/post-beetmover-checksums-dummy/kind.yml
+++ b/taskcluster/ci/post-beetmover-checksums-dummy/kind.yml
@@ -5,17 +5,17 @@
 loader: taskgraph.loader.transform:loader
 
 transforms:
    - taskgraph.transforms.reverse_chunk_deps:transforms
    - taskgraph.transforms.task:transforms
 
 kind-dependencies:
    - beetmover-checksums
-   - beetmover-release-source-checksums
+   - release-beetmover-source-checksums
 
 jobs:
    firefox-promote:
       name: post-beetmover-checksums-dummy
       description: Dummy task to deal with max_dependencies
       run-on-projects: []
       shipping-phase: promote
       shipping-product: firefox
rename from taskcluster/ci/beetmover-release-source-checksums/kind.yml
rename to taskcluster/ci/release-beetmover-source-checksums/kind.yml
--- a/taskcluster/docs/kinds.rst
+++ b/taskcluster/docs/kinds.rst
@@ -212,17 +212,17 @@ source-related beetmover task and sign i
 Returns the same file signed and additional detached signature.
 
 beetmover-checksums
 -------------------
 Beetmover, takes specific artifact checksums and pushes it to a location outside
 of Taskcluster's task artifacts (archive.mozilla.org as one place) and in the
 process determines the final location and "pretty" names it (version product name)
 
-beetmover-release-source-checksums
+release-beetmover-source-checksums
 ---------------------------------
 Beetmover, takes source specific artifact checksums and pushes it to a location outside
 of Taskcluster's task artifacts (archive.mozilla.org as one place) and in the
 process determines the final location and "pretty" names it (version product name)
 
 google-play-strings
 -------------------
 Download strings to display on Google Play from https://l10n.mozilla-community.org/stores_l10n/.
--- a/taskcluster/taskgraph/transforms/beetmover_source_checksums.py
+++ b/taskcluster/taskgraph/transforms/beetmover_source_checksums.py
@@ -1,13 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 """
-Transform beetmover-release-source-checksums task into an actual task description.
+Transform release-beetmover-source-checksums into an actual task description.
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 from taskgraph.transforms.base import TransformSequence
 from taskgraph.transforms.beetmover import craft_release_properties
 from taskgraph.util.attributes import copy_attributes_from_dependent_job
 from taskgraph.util.schema import validate_schema, Schema
--- a/testing/web-platform/meta/mediacapture-streams/historical.html.ini
+++ b/testing/web-platform/meta/mediacapture-streams/historical.html.ini
@@ -1,4 +1,6 @@
 [historical.html]
   [navigator.mozGetUserMedia should not exist]
     expected: FAIL
 
+  [Passing MediaStream to URL.createObjectURL() should throw]
+    expected: FAIL
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -835,27 +835,27 @@ LaunchCrashReporterActivity(XP_CHAR* aPr
 
   if (pid == -1)
     return false;
   else if (pid == 0) {
     // Invoke the reportCrash activity using am
     if (androidUserSerial) {
       Unused << execlp("/system/bin/am",
                        "/system/bin/am",
-                       "startservice",
+                       "start",
                        "--user", androidUserSerial,
                        "-a", "org.mozilla.gecko.reportCrash",
                        "-n", aProgramPath,
                        "--es", "minidumpPath", aMinidumpPath,
                        "--ez", "minidumpSuccess", aSucceeded ? "true" : "false",
                        (char*)0);
     } else {
       Unused << execlp("/system/bin/am",
                        "/system/bin/am",
-                       "startservice",
+                       "start",
                        "-a", "org.mozilla.gecko.reportCrash",
                        "-n", aProgramPath,
                        "--es", "minidumpPath", aMinidumpPath,
                        "--ez", "minidumpSuccess", aSucceeded ? "true" : "false",
                        (char*)0);
     }
     _exit(1);
 
@@ -1539,20 +1539,20 @@ nsresult SetExceptionHandler(nsIFile* aX
 #endif // XP_WIN32
 #else
   // On Android, we launch using the application package name instead of a
   // filename, so use the dynamically set MOZ_ANDROID_PACKAGE_NAME, or fall
   // back to the static ANDROID_PACKAGE_NAME.
   const char* androidPackageName = PR_GetEnv("MOZ_ANDROID_PACKAGE_NAME");
   if (androidPackageName != nullptr) {
     nsCString package(androidPackageName);
-    package.AppendLiteral("/org.mozilla.gecko.CrashReporterService");
+    package.AppendLiteral("/org.mozilla.gecko.CrashReporter");
     crashReporterPath = ToNewCString(package);
   } else {
-    nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporterService");
+    nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporter");
     crashReporterPath = ToNewCString(package);
   }
 #endif // !defined(MOZ_WIDGET_ANDROID)
 
   // get temp path to use for minidump path
 #if defined(XP_WIN32)
   nsString tempPath;
 #else
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -401,17 +401,16 @@ nsAppShell::nsAppShell()
 {
     {
         MutexAutoLock lock(*sAppShellLock);
         sAppShell = this;
     }
 
     if (!XRE_IsParentProcess()) {
         if (jni::IsAvailable()) {
-            GeckoAppShellSupport::Init();
             GeckoThreadSupport::Init();
 
             // Set the corresponding state in GeckoThread.
             java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
         }
         return;
     }