Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 31 Aug 2016 22:33:17 -0400
changeset 312143 b7f7ae14590aced450bb0b0469dfb38edd2c0ace
parent 312071 9e00b305da24074ae5aba1227beb5e096b026100 (current diff)
parent 312142 cbe18f18111247e3b541cf0e5d3c97b0c1478e46 (diff)
child 312144 561fa3ce8c0906c35af942bb44e84254afc25541
child 312153 a7ef41c19c53686fade038ef68ffc91a36e3fcab
child 312185 9f33ab9fd502d2a4c38aef7744ab68c0aaa78234
child 312223 981dabd02177ddd384d4709bfb827a11ef6f417a
push id30632
push userryanvm@gmail.com
push dateThu, 01 Sep 2016 02:33:28 +0000
treeherdermozilla-central@b7f7ae14590a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
first release with
nightly linux32
b7f7ae14590a / 51.0a1 / 20160901030202 / files
nightly linux64
b7f7ae14590a / 51.0a1 / 20160901030202 / files
nightly mac
b7f7ae14590a / 51.0a1 / 20160901030202 / files
nightly win32
b7f7ae14590a / 51.0a1 / 20160901030202 / files
nightly win64
b7f7ae14590a / 51.0a1 / 20160901030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
browser/base/content/test/newtab/head.js
dom/base/test/test_getFeature_with_perm.html
dom/base/test/test_hasFeature.html
dom/html/HTMLMediaElement.cpp
js/src/jit-test/tests/jaeger/bug601400.js
layout/svg/SVGTextFrame.cpp
mobile/android/chrome/content/browser.js
testing/marionette/listener.js
testing/web-platform/meta/html/semantics/selectors/pseudo-classes/indeterminate.html.ini
--- a/addon-sdk/source/lib/sdk/content/l10n-html.js
+++ b/addon-sdk/source/lib/sdk/content/l10n-html.js
@@ -2,21 +2,25 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
-const { Ci } = require("chrome");
+const { Ci, Cc, Cu } = require("chrome");
 const core = require("../l10n/core");
 const { loadSheet, removeSheet } = require("../stylesheet/utils");
 const { process, frames } = require("../remote/child");
-const { Services } = require("resource://gre/modules/Services.jsm");
+var observerService = Cc["@mozilla.org/observer-service;1"]
+                      .getService(Ci.nsIObserverService);
+const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
+const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
+const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
 
 const assetsURI = require('../self').data.url();
 
 const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}";
 
 function translateElementAttributes(element) {
   // Translateable attributes
   const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder'];
@@ -110,20 +114,20 @@ function onContentWindow(document) {
 
 // Listen to creation of content documents in order to translate them as soon
 // as possible in their loading process
 const ON_CONTENT = "document-element-inserted";
 let enabled = false;
 function enable() {
   if (enabled)
     return;
-  Services.obs.addObserver(onContentWindow, ON_CONTENT, false);
+  addObserver(onContentWindow, ON_CONTENT, false);
   enabled = true;
 }
 process.port.on("sdk/l10n/html/enable", enable);
 
 function disable() {
   if (!enabled)
     return;
-  Services.obs.removeObserver(onContentWindow, ON_CONTENT);
+  removeObserver(onContentWindow, ON_CONTENT);
   enabled = false;
 }
 process.port.on("sdk/l10n/html/disable", disable);
--- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js
+++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js
@@ -57,17 +57,16 @@ function browserWindowIterator() {
 exports.browserWindowIterator = browserWindowIterator;
 
 function WindowTracker(delegate) {
    if (!(this instanceof WindowTracker)) {
      return new WindowTracker(delegate);
    }
 
   this._delegate = delegate;
-  this._loadingWindows = [];
 
   for (let window of getWindows())
     this._regWindow(window);
   windowWatcher.registerNotification(this);
   this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this);
   events.on('toplevel-window-ready', this._onToplevelWindowReady);
 
   require('../system/unload').ensure(this);
@@ -76,27 +75,22 @@ function WindowTracker(delegate) {
 };
 
 WindowTracker.prototype = {
   _regLoadingWindow: function _regLoadingWindow(window) {
     // Bug 834961: ignore private windows when they are not supported
     if (ignoreWindow(window))
       return;
 
-    this._loadingWindows.push(window);
     window.addEventListener('load', this, true);
   },
 
   _unregLoadingWindow: function _unregLoadingWindow(window) {
-    var index = this._loadingWindows.indexOf(window);
-
-    if (index != -1) {
-      this._loadingWindows.splice(index, 1);
-      window.removeEventListener('load', this, true);
-    }
+    // This may have no effect if we ignored the window in _regLoadingWindow().
+    window.removeEventListener('load', this, true);
   },
 
   _regWindow: function _regWindow(window) {
     // Bug 834961: ignore private windows when they are not supported
     if (ignoreWindow(window))
       return;
 
     if (window.document.readyState == 'complete') {
--- a/browser/base/content/newtab/dropTargetShim.js
+++ b/browser/base/content/newtab/dropTargetShim.js
@@ -216,17 +216,17 @@ var gDropTargetShim = {
   /**
    * Dispatches a custom DragEvent on the given target node.
    * @param aEvent The source event.
    * @param aType The event type.
    * @param aTarget The target node that receives the event.
    */
   _dispatchEvent: function (aEvent, aType, aTarget) {
     let node = aTarget.node;
-    let event = document.createEvent("DragEvents");
+    let event = document.createEvent("DragEvent");
 
     // The event should not bubble to prevent recursion.
     event.initDragEvent(aType, false, true, window, 0, 0, 0, 0, 0, false, false,
                         false, false, 0, node, aEvent.dataTransfer);
 
     node.dispatchEvent(event);
   }
 };
--- a/browser/base/content/test/newtab/browser_newtab_bug723121.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js
@@ -14,17 +14,17 @@ add_task(function* () {
     let link = site.querySelector(".newtab-link");
 
     function checkGridLocked(aLocked, aMessage) {
       Assert.equal(grid.node.hasAttribute("locked"), aLocked, aMessage);
     }
 
     function sendDragEvent(aEventType, aTarget) {
       let dataTransfer = new content.DataTransfer(aEventType, false);
-      let event = content.document.createEvent("DragEvents");
+      let event = content.document.createEvent("DragEvent");
       event.initDragEvent(aEventType, true, true, content, 0, 0, 0, 0, 0,
                           false, false, false, false, 0, null, dataTransfer);
       aTarget.dispatchEvent(event);
     }
 
     checkGridLocked(false, "grid is unlocked");
 
     sendDragEvent("dragstart", link);
--- a/browser/base/content/test/newtab/browser_newtab_bug725996.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js
@@ -7,17 +7,17 @@ add_task(function* () {
 
   yield* addNewTabPageTab();
   yield* checkGrid("0,1,2,3,4,5,6,7,8");
 
   function doDrop(data) {
     return ContentTask.spawn(gBrowser.selectedBrowser, { data: data }, function*(args) {
       let dataTransfer = new content.DataTransfer("dragstart", false);
       dataTransfer.mozSetDataAt("text/x-moz-url", args.data, 0);
-      let event = content.document.createEvent("DragEvents");
+      let event = content.document.createEvent("DragEvent");
       event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                           false, false, false, false, 0, null, dataTransfer);
 
       let target = content.gGrid.cells[0].node;
       target.dispatchEvent(event);
     });
   }
 
--- a/browser/base/content/test/newtab/browser_newtab_bug765628.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug765628.js
@@ -10,17 +10,17 @@ add_task(function* () {
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     const BAD_DRAG_DATA = "javascript:alert('h4ck0rz');\nbad stuff";
     const GOOD_DRAG_DATA = "http://example99.com/\nsite 99";
 
     function sendDropEvent(aCellIndex, aDragData) {
       let dataTransfer = new content.DataTransfer("dragstart", false);
       dataTransfer.mozSetDataAt("text/x-moz-url", aDragData, 0);
-      let event = content.document.createEvent("DragEvents");
+      let event = content.document.createEvent("DragEvent");
       event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                           false, false, false, false, 0, null, dataTransfer);
 
       let target = content.gGrid.cells[aCellIndex].node;
       target.dispatchEvent(event);
     }
 
     sendDropEvent(0, BAD_DRAG_DATA);
--- a/browser/base/content/test/newtab/browser_newtab_drag_drop.js
+++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js
@@ -73,23 +73,23 @@ add_task(function* () {
   yield doDragEvent(0, 4);
   yield* checkGrid("3,1p,2p,4,0p,5p,6,7,8");
 });
 
 function doDragEvent(sourceIndex, dropIndex) {
   return ContentTask.spawn(gBrowser.selectedBrowser,
                            { sourceIndex: sourceIndex, dropIndex: dropIndex }, function*(args) {
     let dataTransfer = new content.DataTransfer("dragstart", false);
-    let event = content.document.createEvent("DragEvents");
+    let event = content.document.createEvent("DragEvent");
     event.initDragEvent("dragstart", true, true, content, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
 
     let target = content.gGrid.cells[args.sourceIndex].site.node;
     target.dispatchEvent(event);
 
-    event = content.document.createEvent("DragEvents");
+    event = content.document.createEvent("DragEvent");
     event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
 
     target = content.gGrid.cells[args.dropIndex].node;
     target.dispatchEvent(event);
   });
 }
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -414,17 +414,17 @@ function* simulateExternalDrop(aDestInde
       let iframe = doc.createElement("iframe");
 
       function iframeLoaded() {
         let link = iframe.contentDocument.getElementById("link");
 
         let dataTransfer = new iframe.contentWindow.DataTransfer("dragstart", false);
         dataTransfer.mozSetDataAt("text/x-moz-url", "http://example99.com/", 0);
 
-        let event = content.document.createEvent("DragEvents");
+        let event = content.document.createEvent("DragEvent");
         event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                             false, false, false, false, 0, null, dataTransfer);
 
         let target = content.gGrid.cells[dropIndex].node;
         target.dispatchEvent(event);
 
         iframe.remove();
 
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -829,17 +829,17 @@
             "name": "callback",
             "optional": true,
             "description": "Called after all the JavaScript has been executed.",
             "parameters": [
               {
                 "name": "result",
                 "optional": true,
                 "type": "array",
-                "items": {"type": "any", "minimum": 0},
+                "items": {"type": "any"},
                 "description": "The result of the script in every injected frame."
               }
             ]
           }
         ]
       },
       {
         "name": "insertCSS",
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2609,16 +2609,55 @@ ContentPermissionPrompt.prototype = {
     }
 
     secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
 
     this._showPrompt(aRequest, message, "geo", actions, "geolocation",
                      "geo-notification-icon", options);
   },
 
+  _promptFlyWebPublishServer : function(aRequest) {
+    var message = "Would you like to let this site start a server accessible to nearby devices and people?";
+    var actions = [
+      {
+        stringId: "flyWebPublishServer.allowPublishServer",
+        action: Ci.nsIPermissionManager.ALLOW_ACTION,
+        expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
+      },
+      {
+        stringId: "flyWebPublishServer.denyPublishServer",
+        action: Ci.nsIPermissionManager.DENY_ACTION,
+        expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
+      }
+    ];
+
+    let options = {
+      learnMoreURL: "https://flyweb.github.io",
+      popupIconURL: "chrome://flyweb/skin/icon-64.png"
+    };
+
+    let browser = this._getBrowserForRequest(aRequest);
+    let chromeDoc = browser.ownerDocument;
+    let iconElem = chromeDoc.getElementById("flyweb-publish-server-notification-icon");
+    if (!iconElem) {
+      let notificationPopupBox = chromeDoc.getElementById("notification-popup-box");
+      let notificationIcon = chromeDoc.createElement("image");
+      notificationIcon.setAttribute("id", "flyweb-publish-server-notification-icon");
+      notificationIcon.setAttribute("src", "chrome://flyweb/skin/icon-64.png");
+      notificationIcon.setAttribute("class", "notification-anchor-icon flyweb-publish-server-icon");
+      notificationIcon.setAttribute("style", "filter: url(chrome://browser/skin/filters.svg#fill); fill: currentColor; opacity: .4;");
+      notificationIcon.setAttribute("role", "button");
+      notificationIcon.setAttribute("aria-label", "View the publish-server request");
+      notificationPopupBox.appendChild(notificationIcon);
+    }
+
+    this._showPrompt(aRequest, message, "flyweb-publish-server", actions, "flyweb-publish-server",
+                     "flyweb-publish-server-notification-icon", options);
+  },
+
   _promptWebNotifications : function(aRequest) {
     var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
 
     var actions;
 
     var browser = this._getBrowserForRequest(aRequest);
     // Only show "allow for session" in PB mode, we don't
     // support "allow for session" in non-PB mode.
@@ -2673,17 +2712,18 @@ ContentPermissionPrompt.prototype = {
     let types = request.types.QueryInterface(Ci.nsIArray);
     if (types.length != 1) {
       request.cancel();
       return;
     }
     let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
 
     const kFeatureKeys = { "geolocation" : "geo",
-                           "desktop-notification" : "desktop-notification"
+                           "desktop-notification" : "desktop-notification",
+                           "flyweb-publish-server": "flyweb-publish-server"
                          };
 
     // Make sure that we support the request.
     if (!(perm.type in kFeatureKeys)) {
       return;
     }
 
     var requestingPrincipal = request.principal;
@@ -2716,16 +2756,21 @@ ContentPermissionPrompt.prototype = {
     // Show the prompt.
     switch (perm.type) {
     case "geolocation":
       this._promptGeo(request);
       break;
     case "desktop-notification":
       this._promptWebNotifications(request);
       break;
+    case "flyweb-publish-server":
+      if (AppConstants.NIGHTLY_BUILD) {
+        this._promptFlyWebPublishServer(request);
+      }
+      break;
     }
   },
 
 };
 
 var DefaultBrowserCheck = {
   get OPTIONPOPUP() { return "defaultBrowserNotificationPopup" },
   _setAsDefaultTimer: null,
--- a/browser/extensions/e10srollout/bootstrap.js
+++ b/browser/extensions/e10srollout/bootstrap.js
@@ -8,16 +8,17 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/UpdateUtils.jsm");
 
  // The amount of people to be part of e10s
 const TEST_THRESHOLD = {
   "beta"    : 0.5,  // 50%
+  "release" : 1.0,  // 100%
 };
 
 const ADDON_ROLLOUT_POLICY = {
   "beta"    : "2a", // Set 2 + any WebExtension
 };
 
 const PREF_COHORT_SAMPLE       = "e10s.rollout.cohortSample";
 const PREF_COHORT_NAME         = "e10s.rollout.cohort";
--- a/browser/extensions/e10srollout/install.rdf.in
+++ b/browser/extensions/e10srollout/install.rdf.in
@@ -5,17 +5,17 @@
 
 #filter substitution
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
 
   <Description about="urn:mozilla:install-manifest">
     <em:id>e10srollout@mozilla.org</em:id>
-    <em:version>1.0</em:version>
+    <em:version>1.2</em:version>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <!-- Target Application this theme can install into,
         with minimum and maximum supported versions. -->
     <em:targetApplication>
       <Description>
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -373,16 +373,26 @@ geolocation.shareLocation=Share Location
 geolocation.shareLocation.accesskey=a
 geolocation.alwaysShareLocation=Always Share Location
 geolocation.alwaysShareLocation.accesskey=A
 geolocation.neverShareLocation=Never Share Location
 geolocation.neverShareLocation.accesskey=N
 geolocation.shareWithSite2=Would you like to share your location with this site?
 geolocation.shareWithFile2=Would you like to share your location with this file?
 
+# FlyWeb UI
+# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.allowPublishServer=Allow Server
+# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.allowPublishServer.accesskey=A
+# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.denyPublishServer=Block Server
+# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.denyPublishServer.accesskey=B
+
 webNotifications.receiveForSession=Receive for this session
 webNotifications.receiveForSession.accesskey=s
 webNotifications.alwaysReceive=Always Receive Notifications
 webNotifications.alwaysReceive.accesskey=A
 webNotifications.neverShow=Always Block Notifications
 webNotifications.neverShow.accesskey=N
 webNotifications.receiveFromSite=Would you like to receive notifications from this site?
 # LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters.
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -53,20 +53,16 @@
   --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px);
   --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
 }
 
-:root[devtoolstheme="dark"] #identity-box {
-  --identity-box-chrome-color: #46afe3;
-}
-
 :root[devtoolstheme="light"] {
   --url-and-searchbar-background-color: #fff;
 
   --chrome-background-color: #E3E4E6;
   --chrome-color: #18191a;
   --chrome-secondary-background-color: #f5f6f7;
   --chrome-navigator-toolbox-separator-color: #cccccc;
   --chrome-nav-bar-separator-color: #B6B6B8;
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -1,42 +1,33 @@
 %if 0
 /* 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/. */
 %endif
 
 #identity-box {
-  --identity-box-verified-color: hsl(92,100%,30%);
-%ifdef MOZ_OFFICIAL_BRANDING
-  --identity-box-chrome-color: rgb(229,115,0);
-%else
-%if MOZ_UPDATE_CHANNEL == aurora
-  --identity-box-chrome-color: rgb(51,30,84);
-%else
-  --identity-box-chrome-color: rgb(0,33,71);
-%endif
-%endif
-
   font-size: .9em;
   padding: 3px 5px;
   overflow: hidden;
   /* The padding-left and padding-right transitions handle the delayed hiding of
      the forward button when hovered. */
   transition: padding-left, padding-right;
 }
 
-#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon,
 #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #identity-icon-labels {
-  color: var(--identity-box-verified-color);
+  color: hsl(92,100%,30%);
 }
 
-#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #connection-icon,
 #urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon-labels {
-  color: var(--identity-box-chrome-color);
+%ifdef MOZ_OFFICIAL_BRANDING
+  color: rgb(229,115,0);
+%else
+  color: inherit;
+%endif
 }
 
 #identity-icon-labels:-moz-locale-dir(ltr) {
   padding-left: 2px;
 }
 
 #identity-icon-labels:-moz-locale-dir(rtl) {
   padding-right: 2px;
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -1,12 +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/. */
 
+/* This file respects the LLVM coding standard described at
+ * http://llvm.org/docs/CodingStandards.html */
+
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/Version.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
@@ -37,47 +40,47 @@ typedef ASTConsumer *ASTConsumerPtr;
 #define cxxMethodDecl methodDecl
 #define cxxNewExpr newExpr
 #define cxxRecordDecl recordDecl
 #endif
 
 // Check if the given expression contains an assignment expression.
 // This can either take the form of a Binary Operator or a
 // Overloaded Operator Call.
-bool HasSideEffectAssignment(const Expr *expr) {
-  if (auto opCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(expr)) {
-    auto binOp = opCallExpr->getOperator();
-    if (binOp == OO_Equal || (binOp >= OO_PlusEqual && binOp <= OO_PipeEqual)) {
+bool hasSideEffectAssignment(const Expr *Expression) {
+  if (auto OpCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(Expression)) {
+    auto BinOp = OpCallExpr->getOperator();
+    if (BinOp == OO_Equal || (BinOp >= OO_PlusEqual && BinOp <= OO_PipeEqual)) {
       return true;
     }
-  } else if (auto binOpExpr = dyn_cast_or_null<BinaryOperator>(expr)) {
-    if (binOpExpr->isAssignmentOp()) {
+  } else if (auto BinOpExpr = dyn_cast_or_null<BinaryOperator>(Expression)) {
+    if (BinOpExpr->isAssignmentOp()) {
       return true;
     }
   }
 
   // Recurse to children.
-  for (const Stmt *SubStmt : expr->children()) {
-    auto childExpr = dyn_cast_or_null<Expr>(SubStmt);
-    if (childExpr && HasSideEffectAssignment(childExpr)) {
+  for (const Stmt *SubStmt : Expression->children()) {
+    auto ChildExpr = dyn_cast_or_null<Expr>(SubStmt);
+    if (ChildExpr && hasSideEffectAssignment(ChildExpr)) {
       return true;
     }
   }
 
   return false;
 }
 
 namespace {
 
 using namespace clang::ast_matchers;
 class DiagnosticsMatcher {
 public:
   DiagnosticsMatcher();
 
-  ASTConsumerPtr makeASTConsumer() { return astMatcher.newASTConsumer(); }
+  ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); }
 
 private:
   class ScopeChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class ArithmeticArgChecker : public MatchFinder::MatchCallback {
@@ -150,134 +153,134 @@ private:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class AssertAssignmentChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
-  ScopeChecker scopeChecker;
-  ArithmeticArgChecker arithmeticArgChecker;
-  TrivialCtorDtorChecker trivialCtorDtorChecker;
-  NaNExprChecker nanExprChecker;
-  NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
-  RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
-  ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
-  NoDuplicateRefCntMemberChecker noDuplicateRefCntMemberChecker;
-  NeedsNoVTableTypeChecker needsNoVTableTypeChecker;
-  NonMemMovableTemplateArgChecker nonMemMovableTemplateArgChecker;
-  NonMemMovableMemberChecker nonMemMovableMemberChecker;
-  ExplicitImplicitChecker explicitImplicitChecker;
-  NoAutoTypeChecker noAutoTypeChecker;
-  NoExplicitMoveConstructorChecker noExplicitMoveConstructorChecker;
-  RefCountedCopyConstructorChecker refCountedCopyConstructorChecker;
-  AssertAssignmentChecker assertAttributionChecker;
-  MatchFinder astMatcher;
+  ScopeChecker Scope;
+  ArithmeticArgChecker ArithmeticArg;
+  TrivialCtorDtorChecker TrivialCtorDtor;
+  NaNExprChecker NaNExpr;
+  NoAddRefReleaseOnReturnChecker NoAddRefReleaseOnReturn;
+  RefCountedInsideLambdaChecker RefCountedInsideLambda;
+  ExplicitOperatorBoolChecker ExplicitOperatorBool;
+  NoDuplicateRefCntMemberChecker NoDuplicateRefCntMember;
+  NeedsNoVTableTypeChecker NeedsNoVTableType;
+  NonMemMovableTemplateArgChecker NonMemMovableTemplateArg;
+  NonMemMovableMemberChecker NonMemMovableMember;
+  ExplicitImplicitChecker ExplicitImplicit;
+  NoAutoTypeChecker NoAutoType;
+  NoExplicitMoveConstructorChecker NoExplicitMoveConstructor;
+  RefCountedCopyConstructorChecker RefCountedCopyConstructor;
+  AssertAssignmentChecker AssertAttribution;
+  MatchFinder AstMatcher;
 };
 
 namespace {
 
-std::string getDeclarationNamespace(const Decl *decl) {
+std::string getDeclarationNamespace(const Decl *Declaration) {
   const DeclContext *DC =
-      decl->getDeclContext()->getEnclosingNamespaceContext();
+      Declaration->getDeclContext()->getEnclosingNamespaceContext();
   const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
   if (!ND) {
     return "";
   }
 
   while (const DeclContext *ParentDC = ND->getParent()) {
     if (!isa<NamespaceDecl>(ParentDC)) {
       break;
     }
     ND = cast<NamespaceDecl>(ParentDC);
   }
 
-  const auto &name = ND->getName();
-  return name;
+  const auto &Name = ND->getName();
+  return Name;
 }
 
-bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) {
-  std::string name = getDeclarationNamespace(decl);
-  if (name == "") {
+bool isInIgnoredNamespaceForImplicitCtor(const Decl *Declaration) {
+  std::string Name = getDeclarationNamespace(Declaration);
+  if (Name == "") {
     return false;
   }
 
-  return name == "std" ||               // standard C++ lib
-         name == "__gnu_cxx" ||         // gnu C++ lib
-         name == "boost" ||             // boost
-         name == "webrtc" ||            // upstream webrtc
-         name == "rtc" ||               // upstream webrtc 'base' package
-         name.substr(0, 4) == "icu_" || // icu
-         name == "google" ||            // protobuf
-         name == "google_breakpad" ||   // breakpad
-         name == "soundtouch" ||        // libsoundtouch
-         name == "stagefright" ||       // libstagefright
-         name == "MacFileUtilities" ||  // MacFileUtilities
-         name == "dwarf2reader" ||      // dwarf2reader
-         name == "arm_ex_to_module" ||  // arm_ex_to_module
-         name == "testing";             // gtest
+  return Name == "std" ||               // standard C++ lib
+         Name == "__gnu_cxx" ||         // gnu C++ lib
+         Name == "boost" ||             // boost
+         Name == "webrtc" ||            // upstream webrtc
+         Name == "rtc" ||               // upstream webrtc 'base' package
+         Name.substr(0, 4) == "icu_" || // icu
+         Name == "google" ||            // protobuf
+         Name == "google_breakpad" ||   // breakpad
+         Name == "soundtouch" ||        // libsoundtouch
+         Name == "stagefright" ||       // libstagefright
+         Name == "MacFileUtilities" ||  // MacFileUtilities
+         Name == "dwarf2reader" ||      // dwarf2reader
+         Name == "arm_ex_to_module" ||  // arm_ex_to_module
+         Name == "testing";             // gtest
 }
 
-bool isInIgnoredNamespaceForImplicitConversion(const Decl *decl) {
-  std::string name = getDeclarationNamespace(decl);
-  if (name == "") {
+bool isInIgnoredNamespaceForImplicitConversion(const Decl *Declaration) {
+  std::string Name = getDeclarationNamespace(Declaration);
+  if (Name == "") {
     return false;
   }
 
-  return name == "std" ||             // standard C++ lib
-         name == "__gnu_cxx" ||       // gnu C++ lib
-         name == "google_breakpad" || // breakpad
-         name == "testing";           // gtest
+  return Name == "std" ||             // standard C++ lib
+         Name == "__gnu_cxx" ||       // gnu C++ lib
+         Name == "google_breakpad" || // breakpad
+         Name == "testing";           // gtest
 }
 
-bool isIgnoredPathForImplicitCtor(const Decl *decl) {
-  SourceLocation Loc = decl->getLocation();
-  const SourceManager &SM = decl->getASTContext().getSourceManager();
+bool isIgnoredPathForImplicitCtor(const Decl *Declaration) {
+  SourceLocation Loc = Declaration->getLocation();
+  const SourceManager &SM = Declaration->getASTContext().getSourceManager();
   SmallString<1024> FileName = SM.getFilename(Loc);
   llvm::sys::fs::make_absolute(FileName);
-  llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName),
-                                    end = llvm::sys::path::rend(FileName);
-  for (; begin != end; ++begin) {
-    if (begin->compare_lower(StringRef("skia")) == 0 ||
-        begin->compare_lower(StringRef("angle")) == 0 ||
-        begin->compare_lower(StringRef("harfbuzz")) == 0 ||
-        begin->compare_lower(StringRef("hunspell")) == 0 ||
-        begin->compare_lower(StringRef("scoped_ptr.h")) == 0 ||
-        begin->compare_lower(StringRef("graphite2")) == 0) {
+  llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
+                                    End = llvm::sys::path::rend(FileName);
+  for (; Begin != End; ++Begin) {
+    if (Begin->compare_lower(StringRef("skia")) == 0 ||
+        Begin->compare_lower(StringRef("angle")) == 0 ||
+        Begin->compare_lower(StringRef("harfbuzz")) == 0 ||
+        Begin->compare_lower(StringRef("hunspell")) == 0 ||
+        Begin->compare_lower(StringRef("scoped_ptr.h")) == 0 ||
+        Begin->compare_lower(StringRef("graphite2")) == 0) {
       return true;
     }
-    if (begin->compare_lower(StringRef("chromium")) == 0) {
+    if (Begin->compare_lower(StringRef("chromium")) == 0) {
       // Ignore security/sandbox/chromium but not ipc/chromium.
-      ++begin;
-      return begin != end && begin->compare_lower(StringRef("sandbox")) == 0;
+      ++Begin;
+      return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0;
     }
   }
   return false;
 }
 
-bool isIgnoredPathForImplicitConversion(const Decl *decl) {
-  decl = decl->getCanonicalDecl();
-  SourceLocation Loc = decl->getLocation();
-  const SourceManager &SM = decl->getASTContext().getSourceManager();
+bool isIgnoredPathForImplicitConversion(const Decl *Declaration) {
+  Declaration = Declaration->getCanonicalDecl();
+  SourceLocation Loc = Declaration->getLocation();
+  const SourceManager &SM = Declaration->getASTContext().getSourceManager();
   SmallString<1024> FileName = SM.getFilename(Loc);
   llvm::sys::fs::make_absolute(FileName);
-  llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName),
-                                    end = llvm::sys::path::rend(FileName);
-  for (; begin != end; ++begin) {
-    if (begin->compare_lower(StringRef("graphite2")) == 0) {
+  llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
+                                    End = llvm::sys::path::rend(FileName);
+  for (; Begin != End; ++Begin) {
+    if (Begin->compare_lower(StringRef("graphite2")) == 0) {
       return true;
     }
   }
   return false;
 }
 
-bool isInterestingDeclForImplicitConversion(const Decl *decl) {
-  return !isInIgnoredNamespaceForImplicitConversion(decl) &&
-         !isIgnoredPathForImplicitConversion(decl);
+bool isInterestingDeclForImplicitConversion(const Decl *Declaration) {
+  return !isInIgnoredNamespaceForImplicitConversion(Declaration) &&
+         !isIgnoredPathForImplicitConversion(Declaration);
 }
 
 bool isIgnoredExprForMustUse(const Expr *E) {
   if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
     switch (OpCall->getOperator()) {
     case OO_Equal:
     case OO_PlusEqual:
     case OO_MinusEqual:
@@ -400,257 +403,257 @@ protected:
   }
 };
 
 static MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
 
 class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
   DiagnosticsEngine &Diag;
   const CompilerInstance &CI;
-  DiagnosticsMatcher matcher;
+  DiagnosticsMatcher Matcher;
 
 public:
   MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {}
 
-  ASTConsumerPtr getOtherConsumer() { return matcher.makeASTConsumer(); }
+  ASTConsumerPtr getOtherConsumer() { return Matcher.makeASTConsumer(); }
 
-  virtual void HandleTranslationUnit(ASTContext &ctx) {
-    TraverseDecl(ctx.getTranslationUnitDecl());
+  virtual void HandleTranslationUnit(ASTContext &Ctx) override {
+    TraverseDecl(Ctx.getTranslationUnitDecl());
   }
 
   static bool hasCustomAnnotation(const Decl *D, const char *Spelling) {
     iterator_range<specific_attr_iterator<AnnotateAttr>> Attrs =
         D->specific_attrs<AnnotateAttr>();
 
     for (AnnotateAttr *Attr : Attrs) {
       if (Attr->getAnnotation() == Spelling) {
         return true;
       }
     }
 
     return false;
   }
 
-  void HandleUnusedExprResult(const Stmt *stmt) {
-    const Expr *E = dyn_cast_or_null<Expr>(stmt);
+  void handleUnusedExprResult(const Stmt *Statement) {
+    const Expr *E = dyn_cast_or_null<Expr>(Statement);
     if (E) {
       E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers
       QualType T = E->getType();
       if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
-        unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error, "Unused value of must-use type %0");
 
-        Diag.Report(E->getLocStart(), errorID) << T;
+        Diag.Report(E->getLocStart(), ErrorID) << T;
         MustUse.dumpAnnotationReason(Diag, T, E->getLocStart());
       }
     }
   }
 
-  bool VisitCXXRecordDecl(CXXRecordDecl *d) {
+  bool VisitCXXRecordDecl(CXXRecordDecl *D) {
     // We need definitions, not declarations
-    if (!d->isThisDeclarationADefinition())
+    if (!D->isThisDeclarationADefinition())
       return true;
 
     // Look through all of our immediate bases to find methods that need to be
     // overridden
     typedef std::vector<CXXMethodDecl *> OverridesVector;
-    OverridesVector must_overrides;
-    for (CXXRecordDecl::base_class_iterator base = d->bases_begin(),
-                                            e = d->bases_end();
-         base != e; ++base) {
+    OverridesVector MustOverrides;
+    for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
+                                            E = D->bases_end();
+         Base != E; ++Base) {
       // The base is either a class (CXXRecordDecl) or it's a templated class...
-      CXXRecordDecl *parent = base->getType()
-                                  .getDesugaredType(d->getASTContext())
+      CXXRecordDecl *Parent = Base->getType()
+                                  .getDesugaredType(D->getASTContext())
                                   ->getAsCXXRecordDecl();
       // The parent might not be resolved to a type yet. In this case, we can't
       // do any checking here. For complete correctness, we should visit
       // template instantiations, but this case is likely to be rare, so we will
       // ignore it until it becomes important.
-      if (!parent) {
+      if (!Parent) {
         continue;
       }
-      parent = parent->getDefinition();
-      for (CXXRecordDecl::method_iterator M = parent->method_begin();
-           M != parent->method_end(); ++M) {
+      Parent = Parent->getDefinition();
+      for (CXXRecordDecl::method_iterator M = Parent->method_begin();
+           M != Parent->method_end(); ++M) {
         if (hasCustomAnnotation(*M, "moz_must_override"))
-          must_overrides.push_back(*M);
+          MustOverrides.push_back(*M);
       }
     }
 
-    for (OverridesVector::iterator it = must_overrides.begin();
-         it != must_overrides.end(); ++it) {
-      bool overridden = false;
-      for (CXXRecordDecl::method_iterator M = d->method_begin();
-           !overridden && M != d->method_end(); ++M) {
+    for (OverridesVector::iterator It = MustOverrides.begin();
+         It != MustOverrides.end(); ++It) {
+      bool Overridden = false;
+      for (CXXRecordDecl::method_iterator M = D->method_begin();
+           !Overridden && M != D->method_end(); ++M) {
         // The way that Clang checks if a method M overrides its parent method
         // is if the method has the same name but would not overload.
-        if (getNameChecked(M) == getNameChecked(*it) &&
-            !CI.getSema().IsOverload(*M, (*it), false)) {
-          overridden = true;
+        if (getNameChecked(M) == getNameChecked(*It) &&
+            !CI.getSema().IsOverload(*M, (*It), false)) {
+          Overridden = true;
           break;
         }
       }
-      if (!overridden) {
-        unsigned overrideID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      if (!Overridden) {
+        unsigned OverrideID = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error, "%0 must override %1");
-        unsigned overrideNote = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned OverrideNote = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Note, "function to override is here");
-        Diag.Report(d->getLocation(), overrideID) << d->getDeclName()
-                                                  << (*it)->getDeclName();
-        Diag.Report((*it)->getLocation(), overrideNote);
+        Diag.Report(D->getLocation(), OverrideID) << D->getDeclName()
+                                                  << (*It)->getDeclName();
+        Diag.Report((*It)->getLocation(), OverrideNote);
       }
     }
 
     return true;
   }
 
-  bool VisitSwitchCase(SwitchCase *stmt) {
-    HandleUnusedExprResult(stmt->getSubStmt());
+  bool VisitSwitchCase(SwitchCase *Statement) {
+    handleUnusedExprResult(Statement->getSubStmt());
     return true;
   }
-  bool VisitCompoundStmt(CompoundStmt *stmt) {
-    for (CompoundStmt::body_iterator it = stmt->body_begin(),
-                                     e = stmt->body_end();
-         it != e; ++it) {
-      HandleUnusedExprResult(*it);
+  bool VisitCompoundStmt(CompoundStmt *Statement) {
+    for (CompoundStmt::body_iterator It = Statement->body_begin(),
+                                     E = Statement->body_end();
+         It != E; ++It) {
+      handleUnusedExprResult(*It);
     }
     return true;
   }
-  bool VisitIfStmt(IfStmt *Stmt) {
-    HandleUnusedExprResult(Stmt->getThen());
-    HandleUnusedExprResult(Stmt->getElse());
+  bool VisitIfStmt(IfStmt *Statement) {
+    handleUnusedExprResult(Statement->getThen());
+    handleUnusedExprResult(Statement->getElse());
     return true;
   }
-  bool VisitWhileStmt(WhileStmt *Stmt) {
-    HandleUnusedExprResult(Stmt->getBody());
+  bool VisitWhileStmt(WhileStmt *Statement) {
+    handleUnusedExprResult(Statement->getBody());
     return true;
   }
-  bool VisitDoStmt(DoStmt *Stmt) {
-    HandleUnusedExprResult(Stmt->getBody());
+  bool VisitDoStmt(DoStmt *Statement) {
+    handleUnusedExprResult(Statement->getBody());
     return true;
   }
-  bool VisitForStmt(ForStmt *Stmt) {
-    HandleUnusedExprResult(Stmt->getBody());
-    HandleUnusedExprResult(Stmt->getInit());
-    HandleUnusedExprResult(Stmt->getInc());
+  bool VisitForStmt(ForStmt *Statement) {
+    handleUnusedExprResult(Statement->getBody());
+    handleUnusedExprResult(Statement->getInit());
+    handleUnusedExprResult(Statement->getInc());
     return true;
   }
   bool VisitBinComma(BinaryOperator *Op) {
-    HandleUnusedExprResult(Op->getLHS());
+    handleUnusedExprResult(Op->getLHS());
     return true;
   }
 };
 
 /// A cached data of whether classes are refcounted or not.
 typedef DenseMap<const CXXRecordDecl *, std::pair<const Decl *, bool>>
     RefCountedMap;
-RefCountedMap refCountedClasses;
+RefCountedMap RefCountedClasses;
 
 bool classHasAddRefRelease(const CXXRecordDecl *D) {
-  const RefCountedMap::iterator &it = refCountedClasses.find(D);
-  if (it != refCountedClasses.end()) {
-    return it->second.second;
+  const RefCountedMap::iterator &It = RefCountedClasses.find(D);
+  if (It != RefCountedClasses.end()) {
+    return It->second.second;
   }
 
-  bool seenAddRef = false;
-  bool seenRelease = false;
-  for (CXXRecordDecl::method_iterator method = D->method_begin();
-       method != D->method_end(); ++method) {
-    const auto &name = getNameChecked(method);
-    if (name == "AddRef") {
-      seenAddRef = true;
-    } else if (name == "Release") {
-      seenRelease = true;
+  bool SeenAddRef = false;
+  bool SeenRelease = false;
+  for (CXXRecordDecl::method_iterator Method = D->method_begin();
+       Method != D->method_end(); ++Method) {
+    const auto &Name = getNameChecked(Method);
+    if (Name == "AddRef") {
+      SeenAddRef = true;
+    } else if (Name == "Release") {
+      SeenRelease = true;
     }
   }
-  refCountedClasses[D] = std::make_pair(D, seenAddRef && seenRelease);
-  return seenAddRef && seenRelease;
+  RefCountedClasses[D] = std::make_pair(D, SeenAddRef && SeenRelease);
+  return SeenAddRef && SeenRelease;
 }
 
 bool isClassRefCounted(QualType T);
 
 bool isClassRefCounted(const CXXRecordDecl *D) {
   // Normalize so that D points to the definition if it exists.
   if (!D->hasDefinition())
     return false;
   D = D->getDefinition();
   // Base class: anyone with AddRef/Release is obviously a refcounted class.
   if (classHasAddRefRelease(D))
     return true;
 
   // Look through all base cases to figure out if the parent is a refcounted
   // class.
-  for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin();
-       base != D->bases_end(); ++base) {
-    bool super = isClassRefCounted(base->getType());
-    if (super) {
+  for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin();
+       Base != D->bases_end(); ++Base) {
+    bool Super = isClassRefCounted(Base->getType());
+    if (Super) {
       return true;
     }
   }
 
   return false;
 }
 
 bool isClassRefCounted(QualType T) {
-  while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
-  return clazz ? isClassRefCounted(clazz) : false;
+  while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
+    T = ArrTy->getElementType();
+  CXXRecordDecl *Clazz = T->getAsCXXRecordDecl();
+  return Clazz ? isClassRefCounted(Clazz) : false;
 }
 
-template <class T> bool IsInSystemHeader(const ASTContext &AC, const T &D) {
+template <class T> bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) {
   auto &SourceManager = AC.getSourceManager();
   auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart());
   if (ExpansionLoc.isInvalid()) {
     return false;
   }
   return SourceManager.isInSystemHeader(ExpansionLoc);
 }
 
 const FieldDecl *getClassRefCntMember(const CXXRecordDecl *D) {
-  for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end();
-       field != e; ++field) {
-    if (getNameChecked(field) == "mRefCnt") {
-      return *field;
+  for (RecordDecl::field_iterator Field = D->field_begin(), E = D->field_end();
+       Field != E; ++Field) {
+    if (getNameChecked(Field) == "mRefCnt") {
+      return *Field;
     }
   }
   return 0;
 }
 
 const FieldDecl *getBaseRefCntMember(QualType T);
 
 const FieldDecl *getBaseRefCntMember(const CXXRecordDecl *D) {
-  const FieldDecl *refCntMember = getClassRefCntMember(D);
-  if (refCntMember && isClassRefCounted(D)) {
-    return refCntMember;
+  const FieldDecl *RefCntMember = getClassRefCntMember(D);
+  if (RefCntMember && isClassRefCounted(D)) {
+    return RefCntMember;
   }
 
-  for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin(),
-                                                e = D->bases_end();
-       base != e; ++base) {
-    refCntMember = getBaseRefCntMember(base->getType());
-    if (refCntMember) {
-      return refCntMember;
+  for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(),
+                                                E = D->bases_end();
+       Base != E; ++Base) {
+    RefCntMember = getBaseRefCntMember(Base->getType());
+    if (RefCntMember) {
+      return RefCntMember;
     }
   }
   return 0;
 }
 
 const FieldDecl *getBaseRefCntMember(QualType T) {
-  while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
-  return clazz ? getBaseRefCntMember(clazz) : 0;
+  while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
+    T = ArrTy->getElementType();
+  CXXRecordDecl *Clazz = T->getAsCXXRecordDecl();
+  return Clazz ? getBaseRefCntMember(Clazz) : 0;
 }
 
 bool typeHasVTable(QualType T) {
-  while (const clang::ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  CXXRecordDecl *offender = T->getAsCXXRecordDecl();
-  return offender && offender->hasDefinition() && offender->isDynamicClass();
+  while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
+    T = ArrTy->getElementType();
+  CXXRecordDecl *Offender = T->getAsCXXRecordDecl();
+  return Offender && Offender->hasDefinition() && Offender->isDynamicClass();
 }
 }
 
 namespace clang {
 namespace ast_matchers {
 
 /// This matcher will match any function declaration that is declared as a heap
 /// allocator.
@@ -674,49 +677,49 @@ AST_MATCHER(CXXRecordDecl, hasTrivialCto
 /// calling AddRef or Release on its return value.
 AST_MATCHER(FunctionDecl, hasNoAddRefReleaseOnReturnAttr) {
   return MozChecker::hasCustomAnnotation(&Node,
                                          "moz_no_addref_release_on_return");
 }
 
 /// This matcher will match all arithmetic binary operators.
 AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
-  BinaryOperatorKind opcode = Node.getOpcode();
-  return opcode == BO_Mul || opcode == BO_Div || opcode == BO_Rem ||
-         opcode == BO_Add || opcode == BO_Sub || opcode == BO_Shl ||
-         opcode == BO_Shr || opcode == BO_And || opcode == BO_Xor ||
-         opcode == BO_Or || opcode == BO_MulAssign || opcode == BO_DivAssign ||
-         opcode == BO_RemAssign || opcode == BO_AddAssign ||
-         opcode == BO_SubAssign || opcode == BO_ShlAssign ||
-         opcode == BO_ShrAssign || opcode == BO_AndAssign ||
-         opcode == BO_XorAssign || opcode == BO_OrAssign;
+  BinaryOperatorKind OpCode = Node.getOpcode();
+  return OpCode == BO_Mul || OpCode == BO_Div || OpCode == BO_Rem ||
+         OpCode == BO_Add || OpCode == BO_Sub || OpCode == BO_Shl ||
+         OpCode == BO_Shr || OpCode == BO_And || OpCode == BO_Xor ||
+         OpCode == BO_Or || OpCode == BO_MulAssign || OpCode == BO_DivAssign ||
+         OpCode == BO_RemAssign || OpCode == BO_AddAssign ||
+         OpCode == BO_SubAssign || OpCode == BO_ShlAssign ||
+         OpCode == BO_ShrAssign || OpCode == BO_AndAssign ||
+         OpCode == BO_XorAssign || OpCode == BO_OrAssign;
 }
 
 /// This matcher will match all arithmetic unary operators.
 AST_MATCHER(UnaryOperator, unaryArithmeticOperator) {
-  UnaryOperatorKind opcode = Node.getOpcode();
-  return opcode == UO_PostInc || opcode == UO_PostDec || opcode == UO_PreInc ||
-         opcode == UO_PreDec || opcode == UO_Plus || opcode == UO_Minus ||
-         opcode == UO_Not;
+  UnaryOperatorKind OpCode = Node.getOpcode();
+  return OpCode == UO_PostInc || OpCode == UO_PostDec || OpCode == UO_PreInc ||
+         OpCode == UO_PreDec || OpCode == UO_Plus || OpCode == UO_Minus ||
+         OpCode == UO_Not;
 }
 
 /// This matcher will match == and != binary operators.
 AST_MATCHER(BinaryOperator, binaryEqualityOperator) {
-  BinaryOperatorKind opcode = Node.getOpcode();
-  return opcode == BO_EQ || opcode == BO_NE;
+  BinaryOperatorKind OpCode = Node.getOpcode();
+  return OpCode == BO_EQ || OpCode == BO_NE;
 }
 
 /// This matcher will match floating point types.
 AST_MATCHER(QualType, isFloat) { return Node->isRealFloatingType(); }
 
 /// This matcher will match locations in system headers.  This is adopted from
 /// isExpansionInSystemHeader in newer clangs, but modified in order to work
 /// with old clangs that we use on infra.
 AST_MATCHER(BinaryOperator, isInSystemHeader) {
-  return IsInSystemHeader(Finder->getASTContext(), Node);
+  return ASTIsInSystemHeader(Finder->getASTContext(), Node);
 }
 
 /// This matcher will match locations in SkScalar.h.  This header contains a
 /// known NaN-testing expression which we would like to whitelist.
 AST_MATCHER(BinaryOperator, isInSkScalarDotH) {
   SourceLocation Loc = Node.getOperatorLoc();
   auto &SourceManager = Finder->getASTContext().getSourceManager();
   SmallString<1024> FileName = SourceManager.getFilename(Loc);
@@ -756,28 +759,28 @@ AST_MATCHER(CXXRecordDecl, needsMemMovab
 }
 
 /// This matcher will select classes which require all members to be memmovable
 AST_MATCHER(CXXRecordDecl, needsMemMovableMembers) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_members");
 }
 
 AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) {
-  const CXXConstructorDecl *decl = Node.getCanonicalDecl();
+  const CXXConstructorDecl *Declaration = Node.getCanonicalDecl();
   return
       // Skip ignored namespaces and paths
-      !isInIgnoredNamespaceForImplicitCtor(decl) &&
-      !isIgnoredPathForImplicitCtor(decl) &&
+      !isInIgnoredNamespaceForImplicitCtor(Declaration) &&
+      !isIgnoredPathForImplicitCtor(Declaration) &&
       // We only want Converting constructors
-      decl->isConvertingConstructor(false) &&
+      Declaration->isConvertingConstructor(false) &&
       // We don't want copy of move constructors, as those are allowed to be
       // implicit
-      !decl->isCopyOrMoveConstructor() &&
+      !Declaration->isCopyOrMoveConstructor() &&
       // We don't want deleted constructors.
-      !decl->isDeleted();
+      !Declaration->isDeleted();
 }
 
 // We can't call this "isImplicit" since it clashes with an existing matcher in
 // clang.
 AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_implicit");
 }
 
@@ -796,22 +799,22 @@ AST_MATCHER(CXXConstructorDecl, isExplic
   return Node.isExplicit() && Node.isMoveConstructor();
 }
 
 AST_MATCHER(CXXConstructorDecl, isCompilerProvidedCopyConstructor) {
   return !Node.isUserProvided() && Node.isCopyConstructor();
 }
 
 AST_MATCHER(CallExpr, isAssertAssignmentTestFunc) {
-  static const std::string assertName = "MOZ_AssertAssignmentTest";
-  const FunctionDecl *method = Node.getDirectCallee();
+  static const std::string AssertName = "MOZ_AssertAssignmentTest";
+  const FunctionDecl *Method = Node.getDirectCallee();
 
-  return method
-      && method->getDeclName().isIdentifier()
-      && method->getName() == assertName;
+  return Method
+      && Method->getDeclName().isIdentifier()
+      && Method->getName() == AssertName;
 }
 
 AST_MATCHER(CXXRecordDecl, isLambdaDecl) {
   return Node.isLambda();
 }
 
 }
 }
@@ -835,32 +838,33 @@ void CustomTypeAnnotation::dumpAnnotatio
 
   AnnotationReason Reason = directAnnotationReason(T);
   for (;;) {
     switch (Reason.Kind) {
     case RK_ArrayElement:
       Diag.Report(Loc, ArrayID) << Pretty << T << Reason.Type;
       break;
     case RK_BaseClass: {
-      const CXXRecordDecl *Decl = T->getAsCXXRecordDecl();
-      assert(Decl && "This type should be a C++ class");
+      const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
+      assert(Declaration && "This type should be a C++ class");
 
-      Diag.Report(Decl->getLocation(), InheritsID) << Pretty << T
+      Diag.Report(Declaration->getLocation(), InheritsID) << Pretty << T
                                                    << Reason.Type;
       break;
     }
     case RK_Field:
       Diag.Report(Reason.Field->getLocation(), MemberID)
           << Pretty << T << Reason.Field << Reason.Type;
       break;
     case RK_TemplateInherited: {
-      const CXXRecordDecl *Decl = T->getAsCXXRecordDecl();
-      assert(Decl && "This type should be a C++ class");
+      const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
+      assert(Declaration && "This type should be a C++ class");
 
-      Diag.Report(Decl->getLocation(), TemplID) << Pretty << T << Reason.Type;
+      Diag.Report(Declaration->getLocation(), TemplID) << Pretty << T
+                                                   << Reason.Type;
       break;
     }
     default:
       // FIXME (bug 1203263): note the original annotation.
       return;
     }
 
     T = Reason.Type;
@@ -898,44 +902,44 @@ CustomTypeAnnotation::directAnnotationRe
     if (hasEffectiveAnnotation(Array->getElementType())) {
       AnnotationReason Reason = {Array->getElementType(), RK_ArrayElement,
                                  nullptr};
       Cache[Key] = Reason;
       return Reason;
     }
   }
 
-  // Recurse into base classes
-  if (const CXXRecordDecl *Decl = T->getAsCXXRecordDecl()) {
-    if (Decl->hasDefinition()) {
-      Decl = Decl->getDefinition();
+  // Recurse into Base classes
+  if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) {
+    if (Declaration->hasDefinition()) {
+      Declaration = Declaration->getDefinition();
 
-      for (const CXXBaseSpecifier &Base : Decl->bases()) {
+      for (const CXXBaseSpecifier &Base : Declaration->bases()) {
         if (hasEffectiveAnnotation(Base.getType())) {
           AnnotationReason Reason = {Base.getType(), RK_BaseClass, nullptr};
           Cache[Key] = Reason;
           return Reason;
         }
       }
 
       // Recurse into members
-      for (const FieldDecl *Field : Decl->fields()) {
+      for (const FieldDecl *Field : Declaration->fields()) {
         if (hasEffectiveAnnotation(Field->getType())) {
           AnnotationReason Reason = {Field->getType(), RK_Field, Field};
           Cache[Key] = Reason;
           return Reason;
         }
       }
 
       // Recurse into template arguments if the annotation
       // MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present
       if (MozChecker::hasCustomAnnotation(
-              Decl, "moz_inherit_type_annotations_from_template_args")) {
+              Declaration, "moz_inherit_type_annotations_from_template_args")) {
         const ClassTemplateSpecializationDecl *Spec =
-            dyn_cast<ClassTemplateSpecializationDecl>(Decl);
+            dyn_cast<ClassTemplateSpecializationDecl>(Declaration);
         if (Spec) {
           const TemplateArgumentList &Args = Spec->getTemplateArgs();
 
           AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray());
           if (Reason.Kind != RK_None) {
             Cache[Key] = Reason;
             return Reason;
           }
@@ -965,55 +969,56 @@ CustomTypeAnnotation::tmplArgAnnotationR
       }
     }
   }
 
   AnnotationReason Reason = {QualType(), RK_None, nullptr};
   return Reason;
 }
 
-bool isPlacementNew(const CXXNewExpr *Expr) {
+bool isPlacementNew(const CXXNewExpr *Expression) {
   // Regular new expressions aren't placement new
-  if (Expr->getNumPlacementArgs() == 0)
+  if (Expression->getNumPlacementArgs() == 0)
     return false;
-  const FunctionDecl *Decl = Expr->getOperatorNew();
-  if (Decl && MozChecker::hasCustomAnnotation(Decl, "moz_heap_allocator")) {
+  const FunctionDecl *Declaration = Expression->getOperatorNew();
+  if (Declaration && MozChecker::hasCustomAnnotation(Declaration,
+                 "moz_heap_allocator")) {
     return false;
   }
   return true;
 }
 
 DiagnosticsMatcher::DiagnosticsMatcher() {
-  astMatcher.addMatcher(varDecl().bind("node"), &scopeChecker);
-  astMatcher.addMatcher(cxxNewExpr().bind("node"), &scopeChecker);
-  astMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &scopeChecker);
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(varDecl().bind("node"), &Scope);
+  AstMatcher.addMatcher(cxxNewExpr().bind("node"), &Scope);
+  AstMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &Scope);
+  AstMatcher.addMatcher(
       callExpr(callee(functionDecl(heapAllocator()))).bind("node"),
-      &scopeChecker);
-  astMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &scopeChecker);
+      &Scope);
+  AstMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &Scope);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
                      anyOf(hasDescendant(
                                binaryOperator(
                                    allOf(binaryArithmeticOperator(),
                                          hasLHS(hasDescendant(declRefExpr())),
                                          hasRHS(hasDescendant(declRefExpr()))))
                                    .bind("node")),
                            hasDescendant(
                                unaryOperator(
                                    allOf(unaryArithmeticOperator(),
                                          hasUnaryOperand(allOf(
                                              hasType(builtinType()),
                                              anyOf(hasDescendant(declRefExpr()),
                                                    declRefExpr())))))
                                    .bind("node")))))
           .bind("call"),
-      &arithmeticArgChecker);
-  astMatcher.addMatcher(
+      &ArithmeticArg);
+  AstMatcher.addMatcher(
       cxxConstructExpr(
           allOf(hasDeclaration(noArithmeticExprInArgs()),
                 anyOf(hasDescendant(
                           binaryOperator(
                               allOf(binaryArithmeticOperator(),
                                     hasLHS(hasDescendant(declRefExpr())),
                                     hasRHS(hasDescendant(declRefExpr()))))
                               .bind("node")),
@@ -1021,122 +1026,125 @@ DiagnosticsMatcher::DiagnosticsMatcher()
                           unaryOperator(
                               allOf(unaryArithmeticOperator(),
                                     hasUnaryOperand(allOf(
                                         hasType(builtinType()),
                                         anyOf(hasDescendant(declRefExpr()),
                                               declRefExpr())))))
                               .bind("node")))))
           .bind("call"),
-      &arithmeticArgChecker);
+      &ArithmeticArg);
 
-  astMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"),
-                        &trivialCtorDtorChecker);
+  AstMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"),
+                        &TrivialCtorDtor);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       binaryOperator(
           allOf(binaryEqualityOperator(),
                 hasLHS(has(
                     declRefExpr(hasType(qualType((isFloat())))).bind("lhs"))),
                 hasRHS(has(
                     declRefExpr(hasType(qualType((isFloat())))).bind("rhs"))),
                 unless(anyOf(isInSystemHeader(), isInSkScalarDotH()))))
           .bind("node"),
-      &nanExprChecker);
+      &NaNExpr);
 
   // First, look for direct parents of the MemberExpr.
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       callExpr(
           callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")),
           hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr()))
                         .bind("member")))
           .bind("node"),
-      &noAddRefReleaseOnReturnChecker);
+      &NoAddRefReleaseOnReturn);
   // Then, look for MemberExpr that need to be casted to the right type using
   // an intermediary CastExpr before we get to the CallExpr.
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       callExpr(
           callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")),
           hasParent(castExpr(
               hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr()))
                             .bind("member")))))
           .bind("node"),
-      &noAddRefReleaseOnReturnChecker);
+      &NoAddRefReleaseOnReturn);
 
   // We want to reject any code which captures a pointer to an object of a
   // refcounted type, and then lets that value escape. As a primitive analysis,
   // we reject any occurances of the lambda as a template parameter to a class
   // (which could allow it to escape), as well as any presence of such a lambda
   // in a return value (either from lambdas, or in c++14, auto functions).
   //
   // We check these lambdas' capture lists for raw pointers to refcounted types.
-  astMatcher.addMatcher(
-      functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl"))))),
-      &refCountedInsideLambdaChecker);
-  astMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"), &refCountedInsideLambdaChecker);
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
+      functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(
+        isLambdaDecl()).bind("decl"))))),
+      &RefCountedInsideLambda);
+  AstMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"),
+      &RefCountedInsideLambda);
+  AstMatcher.addMatcher(
       classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
-        recordType(hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))),
-      &refCountedInsideLambdaChecker);
+        recordType(hasDeclaration(cxxRecordDecl(
+          isLambdaDecl()).bind("decl")))))),
+      &RefCountedInsideLambda);
 
   // Older clang versions such as the ones used on the infra recognize these
   // conversions as 'operator _Bool', but newer clang versions recognize these
   // as 'operator bool'.
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       cxxMethodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool")))
           .bind("node"),
-      &explicitOperatorBoolChecker);
+      &ExplicitOperatorBool);
 
-  astMatcher.addMatcher(cxxRecordDecl().bind("decl"), &noDuplicateRefCntMemberChecker);
+  AstMatcher.addMatcher(cxxRecordDecl().bind("decl"), &NoDuplicateRefCntMember);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       classTemplateSpecializationDecl(
           allOf(hasAnyTemplateArgument(refersToType(hasVTable())),
                 hasNeedsNoVTableTypeAttr()))
           .bind("node"),
-      &needsNoVTableTypeChecker);
+      &NeedsNoVTableType);
 
   // Handle non-mem-movable template specializations
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       classTemplateSpecializationDecl(
           allOf(needsMemMovableTemplateArg(),
                 hasAnyTemplateArgument(refersToType(isNonMemMovable()))))
           .bind("specialization"),
-      &nonMemMovableTemplateArgChecker);
+      &NonMemMovableTemplateArg);
 
   // Handle non-mem-movable members
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       cxxRecordDecl(needsMemMovableMembers())
           .bind("decl"),
-      &nonMemMovableMemberChecker);
+      &NonMemMovableMember);
 
-  astMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
+  AstMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
                                            ofClass(allOf(isConcreteClass(),
                                                          decl().bind("class"))),
                                            unless(isMarkedImplicit()))
                             .bind("ctor"),
-                        &explicitImplicitChecker);
+                        &ExplicitImplicit);
 
-  astMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"),
-                        &noAutoTypeChecker);
+  AstMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"),
+                        &NoAutoType);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"),
-      &noExplicitMoveConstructorChecker);
+      &NoExplicitMoveConstructor);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       cxxConstructExpr(
           hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(),
                                             ofClass(hasRefCntMember()))))
           .bind("node"),
-      &refCountedCopyConstructorChecker);
+      &RefCountedCopyConstructor);
 
-  astMatcher.addMatcher(
+  AstMatcher.addMatcher(
       callExpr(isAssertAssignmentTestFunc()).bind("funcCall"),
-      &assertAttributionChecker);
+      &AssertAttribution);
 }
 
 // These enum variants determine whether an allocation has occured in the code.
 enum AllocationVariety {
   AV_None,
   AV_Global,
   AV_Automatic,
   AV_Temporary,
@@ -1290,111 +1298,115 @@ void DiagnosticsMatcher::ScopeChecker::r
     NonHeapClass.reportErrorIfPresent(Diag, T, Loc, NonHeapID, HeapNoteID);
     break;
   }
 }
 
 void DiagnosticsMatcher::ArithmeticArgChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "cannot pass an arithmetic expression of built-in types to %0");
-  const Expr *expr = Result.Nodes.getNodeAs<Expr>("node");
-  if (const CallExpr *call = Result.Nodes.getNodeAs<CallExpr>("call")) {
-    Diag.Report(expr->getLocStart(), errorID) << call->getDirectCallee();
-  } else if (const CXXConstructExpr *ctr =
+  const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node");
+  if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) {
+    Diag.Report(Expression->getLocStart(), ErrorID) << Call->getDirectCallee();
+  } else if (const CXXConstructExpr *Ctr =
                  Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
-    Diag.Report(expr->getLocStart(), errorID) << ctr->getConstructor();
+    Diag.Report(Expression->getLocStart(), ErrorID) << Ctr->getConstructor();
   }
 }
 
 void DiagnosticsMatcher::TrivialCtorDtorChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "class %0 must have trivial constructors and destructors");
-  const CXXRecordDecl *node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
+  const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
 
   // We need to accept non-constexpr trivial constructors as well. This occurs
   // when a struct contains pod members, which will not be initialized. As
   // constexpr values are initialized, the constructor is non-constexpr.
-  bool badCtor = !(node->hasConstexprDefaultConstructor() ||
-                   node->hasTrivialDefaultConstructor());
-  bool badDtor = !node->hasTrivialDestructor();
-  if (badCtor || badDtor)
-    Diag.Report(node->getLocStart(), errorID) << node;
+  bool BadCtor = !(Node->hasConstexprDefaultConstructor() ||
+                   Node->hasTrivialDefaultConstructor());
+  bool BadDtor = !Node->hasTrivialDestructor();
+  if (BadCtor || BadDtor)
+    Diag.Report(Node->getLocStart(), ErrorID) << Node;
 }
 
 void DiagnosticsMatcher::NaNExprChecker::run(
     const MatchFinder::MatchResult &Result) {
   if (!Result.Context->getLangOpts().CPlusPlus) {
     // mozilla::IsNaN is not usable in C, so there is no point in issuing these
     // warnings.
     return;
   }
 
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "comparing a floating point value to itself for "
                             "NaN checking can lead to incorrect results");
-  unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "consider using mozilla::IsNaN instead");
-  const BinaryOperator *expr = Result.Nodes.getNodeAs<BinaryOperator>("node");
-  const DeclRefExpr *lhs = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
-  const DeclRefExpr *rhs = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
-  const ImplicitCastExpr *lhsExpr = dyn_cast<ImplicitCastExpr>(expr->getLHS());
-  const ImplicitCastExpr *rhsExpr = dyn_cast<ImplicitCastExpr>(expr->getRHS());
+  const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>(
+    "node");
+  const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
+  const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
+  const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>(
+    Expression->getLHS());
+  const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>(
+    Expression->getRHS());
   // The AST subtree that we are looking for will look like this:
   // -BinaryOperator ==/!=
   //  |-ImplicitCastExpr LValueToRValue
   //  | |-DeclRefExpr
   //  |-ImplicitCastExpr LValueToRValue
   //    |-DeclRefExpr
   // The check below ensures that we are dealing with the correct AST subtree
   // shape, and
   // also that both of the found DeclRefExpr's point to the same declaration.
-  if (lhs->getFoundDecl() == rhs->getFoundDecl() && lhsExpr && rhsExpr &&
-      std::distance(lhsExpr->child_begin(), lhsExpr->child_end()) == 1 &&
-      std::distance(rhsExpr->child_begin(), rhsExpr->child_end()) == 1 &&
-      *lhsExpr->child_begin() == lhs && *rhsExpr->child_begin() == rhs) {
-    Diag.Report(expr->getLocStart(), errorID);
-    Diag.Report(expr->getLocStart(), noteID);
+  if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr &&
+      std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 &&
+      std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 &&
+      *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) {
+    Diag.Report(Expression->getLocStart(), ErrorID);
+    Diag.Report(Expression->getLocStart(), NoteID);
   }
 }
 
 void DiagnosticsMatcher::NoAddRefReleaseOnReturnChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "%1 cannot be called on the return value of %0");
-  const Stmt *node = Result.Nodes.getNodeAs<Stmt>("node");
-  const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func");
-  const MemberExpr *member = Result.Nodes.getNodeAs<MemberExpr>("member");
-  const CXXMethodDecl *method =
-      dyn_cast<CXXMethodDecl>(member->getMemberDecl());
+  const Stmt *Node = Result.Nodes.getNodeAs<Stmt>("node");
+  const FunctionDecl *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+  const MemberExpr *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
+  const CXXMethodDecl *Method =
+      dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
 
-  Diag.Report(node->getLocStart(), errorID) << func << method;
+  Diag.Report(Node->getLocStart(), ErrorID) << Func << Method;
 }
 
 void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
     const MatchFinder::MatchResult &Result) {
   static DenseSet<const CXXRecordDecl*> CheckedDecls;
 
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "Refcounted variable %0 of type %1 cannot be captured by a lambda");
-  unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "Please consider using a smart pointer");
 
   const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
 
-  if (const LambdaExpr *OuterLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
+  if (const LambdaExpr *OuterLambda =
+    Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
     const CXXMethodDecl *OpCall = OuterLambda->getCallOperator();
     QualType ReturnTy = OpCall->getReturnType();
     if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) {
       Lambda = Record;
     }
   }
 
   if (!Lambda || !Lambda->isLambda()) {
@@ -1407,193 +1419,193 @@ void DiagnosticsMatcher::RefCountedInsid
   }
   CheckedDecls.insert(Lambda);
 
   for (const LambdaCapture Capture : Lambda->captures()) {
     if (Capture.capturesVariable() && Capture.getCaptureKind() != LCK_ByRef) {
       QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
 
       if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
-        Diag.Report(Capture.getLocation(), errorID) << Capture.getCapturedVar()
+        Diag.Report(Capture.getLocation(), ErrorID) << Capture.getCapturedVar()
                                                     << Pointee;
-        Diag.Report(Capture.getLocation(), noteID);
+        Diag.Report(Capture.getLocation(), NoteID);
         return;
       }
     }
   }
 }
 
 void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "bad implicit conversion operator for %0");
-  unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "consider adding the explicit keyword to %0");
-  const CXXConversionDecl *method =
+  const CXXConversionDecl *Method =
       Result.Nodes.getNodeAs<CXXConversionDecl>("node");
-  const CXXRecordDecl *clazz = method->getParent();
+  const CXXRecordDecl *Clazz = Method->getParent();
 
-  if (!method->isExplicitSpecified() &&
-      !MozChecker::hasCustomAnnotation(method, "moz_implicit") &&
-      !IsInSystemHeader(method->getASTContext(), *method) &&
-      isInterestingDeclForImplicitConversion(method)) {
-    Diag.Report(method->getLocStart(), errorID) << clazz;
-    Diag.Report(method->getLocStart(), noteID) << "'operator bool'";
+  if (!Method->isExplicitSpecified() &&
+      !MozChecker::hasCustomAnnotation(Method, "moz_implicit") &&
+      !ASTIsInSystemHeader(Method->getASTContext(), *Method) &&
+      isInterestingDeclForImplicitConversion(Method)) {
+    Diag.Report(Method->getLocStart(), ErrorID) << Clazz;
+    Diag.Report(Method->getLocStart(), NoteID) << "'operator bool'";
   }
 }
 
 void DiagnosticsMatcher::NoDuplicateRefCntMemberChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   const CXXRecordDecl *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
-  const FieldDecl *refCntMember = getClassRefCntMember(D);
-  const FieldDecl *foundRefCntBase = nullptr;
+  const FieldDecl *RefCntMember = getClassRefCntMember(D);
+  const FieldDecl *FoundRefCntBase = nullptr;
 
   if (!D->hasDefinition())
     return;
   D = D->getDefinition();
 
   // If we don't have an mRefCnt member, and we have less than 2 superclasses,
   // we don't have to run this loop, as neither case will ever apply.
-  if (!refCntMember && D->getNumBases() < 2) {
+  if (!RefCntMember && D->getNumBases() < 2) {
     return;
   }
 
   // Check every superclass for whether it has a base with a refcnt member, and
   // warn for those which do
-  for (auto &base : D->bases()) {
+  for (auto &Base : D->bases()) {
     // Determine if this base class has an mRefCnt member
-    const FieldDecl *baseRefCntMember = getBaseRefCntMember(base.getType());
+    const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType());
 
-    if (baseRefCntMember) {
-      if (refCntMember) {
+    if (BaseRefCntMember) {
+      if (RefCntMember) {
         // We have an mRefCnt, and superclass has an mRefCnt
-        unsigned error = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error,
             "Refcounted record %0 has multiple mRefCnt members");
-        unsigned note1 = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned Note1 = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Note, "Superclass %0 also has an mRefCnt member");
-        unsigned note2 = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned Note2 = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Note,
             "Consider using the _INHERITED macros for AddRef and Release here");
 
-        Diag.Report(D->getLocStart(), error) << D;
-        Diag.Report(baseRefCntMember->getLocStart(), note1)
-          << baseRefCntMember->getParent();
-        Diag.Report(refCntMember->getLocStart(), note2);
+        Diag.Report(D->getLocStart(), Error) << D;
+        Diag.Report(BaseRefCntMember->getLocStart(), Note1)
+          << BaseRefCntMember->getParent();
+        Diag.Report(RefCntMember->getLocStart(), Note2);
       }
 
-      if (foundRefCntBase) {
-        unsigned error = Diag.getDiagnosticIDs()->getCustomDiagID(
+      if (FoundRefCntBase) {
+        unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error,
             "Refcounted record %0 has multiple superclasses with mRefCnt members");
-        unsigned note = Diag.getDiagnosticIDs()->getCustomDiagID(
+        unsigned Note = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Note,
             "Superclass %0 has an mRefCnt member");
 
         // superclass has mRefCnt, and another superclass also has an mRefCnt
-        Diag.Report(D->getLocStart(), error) << D;
-        Diag.Report(baseRefCntMember->getLocStart(), note)
-          << baseRefCntMember->getParent();
-        Diag.Report(foundRefCntBase->getLocStart(), note)
-          << foundRefCntBase->getParent();
+        Diag.Report(D->getLocStart(), Error) << D;
+        Diag.Report(BaseRefCntMember->getLocStart(), Note)
+          << BaseRefCntMember->getParent();
+        Diag.Report(FoundRefCntBase->getLocStart(), Note)
+          << FoundRefCntBase->getParent();
       }
 
       // Record that we've found a base with a mRefCnt member
-      foundRefCntBase = baseRefCntMember;
+      FoundRefCntBase = BaseRefCntMember;
     }
   }
 }
 
 void DiagnosticsMatcher::NeedsNoVTableTypeChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "%0 cannot be instantiated because %1 has a VTable");
-  unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "bad instantiation of %0 requested here");
 
-  const ClassTemplateSpecializationDecl *specialization =
+  const ClassTemplateSpecializationDecl *Specialization =
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node");
 
   // Get the offending template argument
-  QualType offender;
-  const TemplateArgumentList &args =
-      specialization->getTemplateInstantiationArgs();
-  for (unsigned i = 0; i < args.size(); ++i) {
-    offender = args[i].getAsType();
-    if (typeHasVTable(offender)) {
+  QualType Offender;
+  const TemplateArgumentList &Args =
+      Specialization->getTemplateInstantiationArgs();
+  for (unsigned i = 0; i < Args.size(); ++i) {
+    Offender = Args[i].getAsType();
+    if (typeHasVTable(Offender)) {
       break;
     }
   }
 
-  Diag.Report(specialization->getLocStart(), errorID) << specialization
-                                                      << offender;
-  Diag.Report(specialization->getPointOfInstantiation(), noteID)
-      << specialization;
+  Diag.Report(Specialization->getLocStart(), ErrorID) << Specialization
+                                                      << Offender;
+  Diag.Report(Specialization->getPointOfInstantiation(), NoteID)
+      << Specialization;
 }
 
 void DiagnosticsMatcher::NonMemMovableTemplateArgChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "Cannot instantiate %0 with non-memmovable template argument %1");
-  unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned Note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "instantiation of %0 requested here");
 
   // Get the specialization
-  const ClassTemplateSpecializationDecl *specialization =
+  const ClassTemplateSpecializationDecl *Specialization =
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
-  SourceLocation requestLoc = specialization->getPointOfInstantiation();
+  SourceLocation RequestLoc = Specialization->getPointOfInstantiation();
 
   // Report an error for every template argument which is non-memmovable
-  const TemplateArgumentList &args =
-      specialization->getTemplateInstantiationArgs();
-  for (unsigned i = 0; i < args.size(); ++i) {
-    QualType argType = args[i].getAsType();
-    if (NonMemMovable.hasEffectiveAnnotation(argType)) {
-      Diag.Report(specialization->getLocation(), errorID) << specialization
-                                                          << argType;
+  const TemplateArgumentList &Args =
+      Specialization->getTemplateInstantiationArgs();
+  for (unsigned i = 0; i < Args.size(); ++i) {
+    QualType ArgType = Args[i].getAsType();
+    if (NonMemMovable.hasEffectiveAnnotation(ArgType)) {
+      Diag.Report(Specialization->getLocation(), ErrorID) << Specialization
+                                                          << ArgType;
       // XXX It would be really nice if we could get the instantiation stack
       // information
       // from Sema such that we could print a full template instantiation stack,
       // however,
       // it seems as though that information is thrown out by the time we get
       // here so we
       // can only report one level of template specialization (which in many
       // cases won't
       // be useful)
-      Diag.Report(requestLoc, note1ID) << specialization;
-      NonMemMovable.dumpAnnotationReason(Diag, argType, requestLoc);
+      Diag.Report(RequestLoc, Note1ID) << Specialization;
+      NonMemMovable.dumpAnnotationReason(Diag, ArgType, RequestLoc);
     }
   }
 }
 
 void DiagnosticsMatcher::NonMemMovableMemberChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "class %0 cannot have non-memmovable member %1 of type %2");
 
   // Get the specialization
-  const CXXRecordDecl* Decl =
+  const CXXRecordDecl* Declaration =
       Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
 
   // Report an error for every member which is non-memmovable
-  for (const FieldDecl *Field : Decl->fields()) {
+  for (const FieldDecl *Field : Declaration->fields()) {
     QualType Type = Field->getType();
     if (NonMemMovable.hasEffectiveAnnotation(Type)) {
-      Diag.Report(Field->getLocation(), errorID) << Decl
+      Diag.Report(Field->getLocation(), ErrorID) << Declaration
                                                  << Field
                                                  << Type;
-      NonMemMovable.dumpAnnotationReason(Diag, Type, Decl->getLocation());
+      NonMemMovable.dumpAnnotationReason(Diag, Type, Declaration->getLocation());
     }
   }
 }
 
 void DiagnosticsMatcher::ExplicitImplicitChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
@@ -1602,19 +1614,20 @@ void DiagnosticsMatcher::ExplicitImplici
       DiagnosticIDs::Note,
       "consider adding the explicit keyword to the constructor");
 
   // We've already checked everything in the matcher, so we just have to report
   // the error.
 
   const CXXConstructorDecl *Ctor =
       Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
-  const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
+  const CXXRecordDecl *Declaration =
+      Result.Nodes.getNodeAs<CXXRecordDecl>("class");
 
-  Diag.Report(Ctor->getLocation(), ErrorID) << Decl->getDeclName();
+  Diag.Report(Ctor->getLocation(), ErrorID) << Declaration->getDeclName();
   Diag.Report(Ctor->getLocation(), NoteID);
 }
 
 void DiagnosticsMatcher::NoAutoTypeChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "Cannot use auto to declare a variable of type %0");
@@ -1661,47 +1674,47 @@ void DiagnosticsMatcher::RefCountedCopyC
 
   Diag.Report(E->getLocation(), ErrorID);
   Diag.Report(E->getLocation(), NoteID);
 }
 
 void DiagnosticsMatcher::AssertAssignmentChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned assignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID(
+  unsigned AssignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "Forbidden assignment in assert expression");
-  const CallExpr *funcCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
+  const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
 
-  if (funcCall && HasSideEffectAssignment(funcCall)) {
-    Diag.Report(funcCall->getLocStart(), assignInsteadOfComp);
+  if (FuncCall && hasSideEffectAssignment(FuncCall)) {
+    Diag.Report(FuncCall->getLocStart(), AssignInsteadOfComp);
   }
 }
 
 class MozCheckAction : public PluginASTAction {
 public:
   ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
-                                   StringRef fileName) override {
+                                   StringRef FileName) override {
 #if CLANG_VERSION_FULL >= 306
-    std::unique_ptr<MozChecker> checker(llvm::make_unique<MozChecker>(CI));
-    ASTConsumerPtr other(checker->getOtherConsumer());
+    std::unique_ptr<MozChecker> Checker(llvm::make_unique<MozChecker>(CI));
+    ASTConsumerPtr Other(Checker->getOtherConsumer());
 
-    std::vector<ASTConsumerPtr> consumers;
-    consumers.push_back(std::move(checker));
-    consumers.push_back(std::move(other));
-    return llvm::make_unique<MultiplexConsumer>(std::move(consumers));
+    std::vector<ASTConsumerPtr> Consumers;
+    Consumers.push_back(std::move(Checker));
+    Consumers.push_back(std::move(Other));
+    return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
 #else
-    MozChecker *checker = new MozChecker(CI);
+    MozChecker *Checker = new MozChecker(CI);
 
-    ASTConsumer *consumers[] = {checker, checker->getOtherConsumer()};
-    return new MultiplexConsumer(consumers);
+    ASTConsumer *Consumers[] = {Checker, Checker->getOtherConsumer()};
+    return new MultiplexConsumer(Consumers);
 #endif
   }
 
   bool ParseArgs(const CompilerInstance &CI,
-                 const std::vector<std::string> &args) override {
+                 const std::vector<std::string> &Args) override {
     return true;
   }
 };
 }
 
 static FrontendPluginRegistry::Add<MozCheckAction> X("moz-check",
                                                      "check moz action");
 // Export the registry on Windows.
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -115,20 +115,16 @@
 #endif
 #include "mozilla/dom/ContentChild.h"
 
 #ifdef MOZ_EME
 #include "mozilla/EMEUtils.h"
 #include "mozilla/DetailedPromise.h"
 #endif
 
-#ifdef MOZ_WIDGET_GONK
-#include <cutils/properties.h>
-#endif
-
 namespace mozilla {
 namespace dom {
 
 static bool sVibratorEnabled   = false;
 static uint32_t sMaxVibrateMS  = 0;
 static uint32_t sMaxVibrateListLen = 0;
 static const char* kVibrationPermissionType = "vibration";
 
@@ -1634,167 +1630,16 @@ Navigator::PublishServer(const nsAString
                    },
                    [domPromise] (nsresult aStatus) {
                      domPromise->MaybeReject(aStatus);
                    });
 
   return domPromise.forget();
 }
 
-already_AddRefed<Promise>
-Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
-{
-  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
-  RefPtr<Promise> p = Promise::Create(go, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-#if defined(XP_LINUX)
-  if (aName.EqualsLiteral("hardware.memory")) {
-    // with seccomp enabled, fopen() should be in a non-sandboxed process
-    if (XRE_IsParentProcess()) {
-      uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
-      if (memLevel == 0) {
-        p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-        return p.forget();
-      }
-      p->MaybeResolve((int)memLevel);
-    } else {
-      mozilla::dom::ContentChild* cc =
-        mozilla::dom::ContentChild::GetSingleton();
-      RefPtr<Promise> ipcRef(p);
-      cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take()));
-    }
-    return p.forget();
-  } // hardware.memory
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-  if (StringBeginsWith(aName, NS_LITERAL_STRING("acl.")) &&
-      (aName.EqualsLiteral("acl.version") || CheckPermission("external-app"))) {
-    char value[PROPERTY_VALUE_MAX];
-    nsCString propertyKey("persist.");
-    propertyKey.Append(NS_ConvertUTF16toUTF8(aName));
-    uint32_t len = property_get(propertyKey.get(), value, nullptr);
-    if (len > 0) {
-      p->MaybeResolve(NS_ConvertUTF8toUTF16(value));
-      return p.forget();
-    }
-  }
-#endif
-
-  // Mirror the dom.apps.developer_mode pref to let apps get it read-only.
-  if (aName.EqualsLiteral("dom.apps.developer_mode")) {
-    p->MaybeResolve(Preferences::GetBool("dom.apps.developer_mode", false));
-    return p.forget();
-  }
-
-  p->MaybeResolveWithUndefined();
-  return p.forget();
-}
-
-already_AddRefed<Promise>
-Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
-{
-  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
-  RefPtr<Promise> p = Promise::Create(go, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  // Hardcoded extensions features which are b2g specific.
-#ifdef MOZ_B2G
-  if (aName.EqualsLiteral("web-extensions") ||
-      aName.EqualsLiteral("late-customization")) {
-    p->MaybeResolve(true);
-    return p.forget();
-  }
-#endif
-
-  // Hardcoded manifest features. Some are still b2g specific.
-  const char manifestFeatures[][64] = {
-    "manifest.origin"
-  , "manifest.redirects"
-#ifdef MOZ_B2G
-  , "manifest.chrome.navigation"
-  , "manifest.precompile"
-  , "manifest.role.homescreen"
-#endif
-  };
-
-  nsAutoCString feature = NS_ConvertUTF16toUTF8(aName);
-  for (uint32_t i = 0; i < MOZ_ARRAY_LENGTH(manifestFeatures); i++) {
-    if (feature.Equals(manifestFeatures[i])) {
-      p->MaybeResolve(true);
-      return p.forget();
-    }
-  }
-
-  NS_NAMED_LITERAL_STRING(apiWindowPrefix, "api.window.");
-  if (StringBeginsWith(aName, apiWindowPrefix)) {
-    const nsAString& featureName = Substring(aName, apiWindowPrefix.Length());
-
-    // Temporary hardcoded entry points due to technical constraints
-    if (featureName.EqualsLiteral("Navigator.mozTCPSocket")) {
-      p->MaybeResolve(Preferences::GetBool("dom.mozTCPSocket.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.mozMobileConnections") ||
-        featureName.EqualsLiteral("MozMobileNetworkInfo")) {
-      p->MaybeResolve(Preferences::GetBool("dom.mobileconnection.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.mozInputMethod")) {
-      p->MaybeResolve(Preferences::GetBool("dom.mozInputMethod.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.getDeviceStorage")) {
-      p->MaybeResolve(Preferences::GetBool("device.storage.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.mozNetworkStats")) {
-      p->MaybeResolve(Preferences::GetBool("dom.mozNetworkStats.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.push")) {
-      p->MaybeResolve(Preferences::GetBool("services.push.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.mozAlarms")) {
-      p->MaybeResolve(Preferences::GetBool("dom.mozAlarms.enabled"));
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("Navigator.mozCameras")) {
-      p->MaybeResolve(true);
-      return p.forget();
-    }
-
-    if (featureName.EqualsLiteral("XMLHttpRequest.mozSystem")) {
-      p->MaybeResolve(true);
-      return p.forget();
-    }
-
-    p->MaybeResolveWithUndefined();
-    return p.forget();
-  }
-
-  // resolve with <undefined> because the feature name is not supported
-  p->MaybeResolveWithUndefined();
-
-  return p.forget();
-}
-
 PowerManager*
 Navigator::GetMozPower(ErrorResult& aRv)
 {
   if (!mPowerManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -180,23 +180,16 @@ public:
                                nsIURI* aURI,
                                bool aIsCallerChrome,
                                nsAString& aUserAgent);
 
   // Clears the user agent cache by calling:
   // NavigatorBinding::ClearCachedUserAgentValue(this);
   void ClearUserAgentCache();
 
-  // Feature Detection API
-  already_AddRefed<Promise> GetFeature(const nsAString& aName,
-                                       ErrorResult& aRv);
-
-  already_AddRefed<Promise> HasFeature(const nsAString &aName,
-                                       ErrorResult& aRv);
-
   bool Vibrate(uint32_t aDuration);
   bool Vibrate(const nsTArray<uint32_t>& aDuration);
   void SetVibrationPermission(bool aPermitted, bool aPersistent);
   uint32_t MaxTouchPoints();
   void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
   {
     aRv = GetAppCodeName(aAppCodeName);
   }
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -21,11 +21,9 @@ support-files = file_navigator_resolve_i
 subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
 skip-if = buildapp == 'mulet'
 [test_bug945152.html]
 [test_bug1008126.html]
 [test_sandboxed_blob_uri.html]
 [test_websocket_frame.html]
-[test_getFeature_with_perm.html]
-[test_hasFeature.html]
 [test_mozbrowser_apis_allowed.html]
deleted file mode 100644
--- a/dom/base/test/test_getFeature_with_perm.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=979109
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 979109</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=983502">Mozilla Bug 983502</a>
-<script type="application/javascript">
-
-function testSupported() {
-  var mem;
-  navigator.getFeature("hardware.memory").then(function(mem) {
-
-    var isLinux = (navigator.platform.indexOf('Linux') != -1);
-    var isAndroid = !!navigator.userAgent.includes("Android");
-    var isB2G = !isAndroid && /Mobile|Tablet/.test(navigator.userAgent);
-
-    if (isLinux) {
-      info("It is Linux version:");
-    }
-    if (isAndroid) {
-      info("It is Android version");
-    }
-    if (isB2G) {
-      info("It is B2G version");
-    }
-
-    if (isLinux || isAndroid || isB2G) {
-      ok(typeof mem === 'number' && (mem) % 1 === 0, "We should receive an integer on this platform");
-      ok(mem > 0, "hardware.memory is supported on this platform. mem=" + mem + "MiB");
-    } else {
-      ok(typeof mem === 'undefined', "hardware.memory is not support on this platform");
-    }
-
-    runNextTest();
-
-  },function(mem) {
-    ok(false, "The Promise should not be rejected");
-  });
-}
-
-function testNotSupported() {
-  var tv;
-  navigator.getFeature("hardware.tv").then(function(tv) {
-    ok(typeof tv === 'undefined', "Resolve the Promise with undefined value (hardware.tv)");
-    runNextTest();
-  },function(tv) {
-    ok(false, "The Promise should not be rejected");
-  });
-}
-
-function testNotSupportedManifest() {
-  navigator.getFeature("manifest.origin").then(function(feature) {
-    ok(typeof feature == 'undefined', "manifest.* resolves with undefined on getFeature");
-    runNextTest();
-  }, function() {
-    ok(false, "The Promise should not be rejected");
-  });
-}
-
-function createManifestTest(aFeature) {
-  return function() {
-    var res;
-    navigator.hasFeature(aFeature).then(function(res) {
-      ok(res === true, "Resolve the Promise with 'true' for " + aFeature);
-      runNextTest();
-    }, function(tv) {
-      ok(false, "The Promise should not be rejected");
-    });
-  }
-}
-
-function testDevMode(aExpected) {
-  return function() {
-    navigator.getFeature("dom.apps.developer_mode").then(res => {
-      is(res, aExpected, "dom.apps.developer_mode is " + aExpected);
-      runNextTest();
-    }, function() {
-      ok(false, "The Promise should not be rejected");
-    });
-  }
-}
-
-function enableDevMode() {
-  SpecialPowers.pushPrefEnv({"set": [["dom.apps.developer_mode", true]]}, runNextTest);
-}
-
-var currentTest = -1;
-var tests = [
-  testNotSupported,
-  testNotSupportedManifest,
-  testSupported,
-  createManifestTest("manifest.origin"),
-  createManifestTest("manifest.redirects"),
-  testDevMode(false),
-  enableDevMode,
-  testDevMode(true)
-];
-
-function runNextTest() {
-  currentTest++;
-  if (currentTest < tests.length) {
-    tests[currentTest]();
-  } else {
-    SimpleTest.finish();
-  }
-}
-
-info("About to run " + tests.length + " tests");
-
-ok('getFeature' in navigator, "navigator.getFeature should exist");
-ok('hasFeature' in navigator, "navigator.hasFeature should exist");
-// B2G specific manifest features.
-// Touching navigator before pushPermissions makes it fail.
-if (!navigator.userAgent.includes("Android") &&
-      /Mobile|Tablet/.test(navigator.userAgent)) {
-  info("Adding B2G specific tests");
-  tests.push(createManifestTest("manifest.chrome.navigation"));
-  tests.push(createManifestTest("manifest.precompile"));
-  tests.push(createManifestTest("manifest.role.homescreen"));
-}
-runNextTest();
-ok(true, "Test DONE");
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/base/test/test_hasFeature.html
+++ /dev/null
@@ -1,101 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1009645
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 1009645</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1009645">Mozilla Bug 1009645</a>
-<script type="application/javascript">
-
-var b2gOnly;
-
-function pref(name) {
-  try {
-    return SpecialPowers.getBoolPref(name);
-  } catch (e) {
-    return false;
-  }
-}
-
-function testAPIs() {
-  var APIEndPoints = [
-    { name: "MozMobileNetworkInfo", enabled: pref("dom.mobileconnection.enabled") },
-    // { name: "Navigator.mozBluetooth", enabled: b2gOnly }, // conditional on MOZ_B2G_BT, tricky to test
-    // Bug 1266035 { name: "Navigator.mozContacts", enabled: pref("dom.mozContacts.enabled") },
-    { name: "Navigator.getDeviceStorage", enabled: pref("device.storage.enabled") },
-    // Bug 1266035 { name: "Navigator.addIdleObserver", enabled: true },
-    { name: "Navigator.mozNetworkStats", enabled: pref("dom.mozNetworkStats.enabled") },
-    { name: "Navigator.push", enabled: pref("services.push.enabled") },
-    // { name: "Navigator.mozTime", enabled: b2gOnly }, // conditional on MOZ_TIME_MANAGER, tricky to test
-    // { name: "Navigator.mozFMRadio", enabled: b2gOnly }, // conditional on MOZ_B2G_FM, tricky to test
-    { name: "Navigator.mozCameras", enabled: true },
-    { name: "Navigator.mozAlarms", enabled: pref("dom.mozAlarms.enabled") },
-    { name: "Navigator.mozTCPSocket", enabled: pref("dom.mozTCPSocket.enabled") },
-    { name: "Navigator.mozInputMethod", enabled: pref("dom.mozInputMethod.enabled") },
-    { name: "Navigator.mozMobileConnections", enabled: pref("dom.mobileconnection.enabled") },
-    { name: "XMLHttpRequest.mozSystem", enabled: true }
-  ];
-
-  var promises = [];
-  APIEndPoints.forEach(function(v) {
-    promises.push(navigator.hasFeature("api.window." + v.name));
-  });
-
-  return Promise.all(promises).then(function(values) {
-    for (var i = 0; i < values.length; ++i) {
-      is(values[i], APIEndPoints[i].enabled,
-         "Endpoint " + APIEndPoints[i].name + " resolved with the correct value. " +
-         "If this is failing because you're changing how an API is exposed, you " +
-         "must contact the Marketplace team to let them know about the change.");
-    }
-  }, function() {
-    ok(false, "The Promise should not be rejected");
-  });
-}
-
-function testExtensions() {
-  if (!b2gOnly) {
-    return Promise.resolve();
-  }
-
-  var builtInFeatures = [
-    {feature: "web-extensions", value: true},
-    {feature: "late-customization", value: true}
-  ];
-
-  builtInFeatures.forEach(function(x) {
-    navigator.hasFeature(x.feature).then(function(value) {
-      is(value, x.value, "Resolve the Promise with " + value + " for feature: " + x.feature);
-    }).catch(function(ex) {
-      ok(false, "The Promise should not be rejected");
-    });
-  });
-  return Promise.resolve();
-}
-
-SpecialPowers.pushPermissions([
-  {type: "feature-detection", allow: true, context: document}
-], function() {
-  b2gOnly = (function() {
-    var isAndroid = !!navigator.userAgent.includes("Android");
-    var isMulet = pref("b2g.is_mulet");
-    var isB2g = isMulet || (!isAndroid && /Mobile|Tablet/.test(navigator.userAgent));
-    return isB2g ? true : undefined;
-  })();
-
-  ok('hasFeature' in navigator, "navigator.hasFeature should exist");
-  testAPIs().then(testExtensions).catch(function(e) {
-    ok(false, "The Promise should not be rejected: " + e);
-  }).then(SimpleTest.finish);
-});
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</body>
-</html>
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -784,49 +784,35 @@ BrowserElementParent.prototype = {
       "modifiers": modifiers
     });
   }),
 
   sendTouchEvent: defineNoReturnMethod(function(type, identifiers, touchesX, touchesY,
                                                 radiisX, radiisY, rotationAngles, forces,
                                                 count, modifiers) {
 
-    let tabParent = this._frameLoader.tabParent;
-    if (tabParent && tabParent.useAsyncPanZoom) {
-      tabParent.injectTouchEvent(type,
-                                 identifiers,
-                                 touchesX,
-                                 touchesY,
-                                 radiisX,
-                                 radiisY,
-                                 rotationAngles,
-                                 forces,
-                                 count,
-                                 modifiers);
-    } else {
-      let offset = this.getChildProcessOffset();
-      for (var i = 0; i < touchesX.length; i++) {
-        touchesX[i] += offset.x;
-      }
-      for (var i = 0; i < touchesY.length; i++) {
-        touchesY[i] += offset.y;
-      }
-      this._sendAsyncMsg("send-touch-event", {
-        "type": type,
-        "identifiers": identifiers,
-        "touchesX": touchesX,
-        "touchesY": touchesY,
-        "radiisX": radiisX,
-        "radiisY": radiisY,
-        "rotationAngles": rotationAngles,
-        "forces": forces,
-        "count": count,
-        "modifiers": modifiers
-      });
+    let offset = this.getChildProcessOffset();
+    for (var i = 0; i < touchesX.length; i++) {
+      touchesX[i] += offset.x;
+    }
+    for (var i = 0; i < touchesY.length; i++) {
+      touchesY[i] += offset.y;
     }
+    this._sendAsyncMsg("send-touch-event", {
+      "type": type,
+      "identifiers": identifiers,
+      "touchesX": touchesX,
+      "touchesY": touchesY,
+      "radiisX": radiisX,
+      "radiisY": radiisY,
+      "rotationAngles": rotationAngles,
+      "forces": forces,
+      "count": count,
+      "modifiers": modifiers
+    });
   }),
 
   getCanGoBack: defineDOMRequestMethod('get-can-go-back'),
   getCanGoForward: defineDOMRequestMethod('get-can-go-forward'),
   getContentDimensions: defineDOMRequestMethod('get-contentdimensions'),
 
   findAll: defineNoReturnMethod(function(searchString, caseSensitivity) {
     return this._sendAsyncMsg('find-all', {
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/array-complex-indexing.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/array-complex-indexing.html
@@ -72,27 +72,16 @@ void main() {
 precision mediump float;
 out vec4 color;
 
 void main() {
   float a = (float[3](2.0, 1.0, 0.0))[0];
   color = (a == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0);
 }
 </script>
-<script id="fshader-sequence-operator" type="x-shader/x-fragment">#version 300 es
-precision mediump float;
-out vec4 color;
-
-void main() {
-  float a[2] = float[2](1.0, 0.0);
-  float b[2] = float[2](2.0, 3.0);
-  float c = (a, b)[0];
-  color = (c == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0);
-}
-</script>
 <script type="application/javascript">
 "use strict";
 description("Indexing complex array expressions");
 debug("");
 
 GLSLConformanceTester.runRenderTests([
 {
   fShaderId: 'fshader-assignment',
@@ -107,19 +96,13 @@ GLSLConformanceTester.runRenderTests([
   passMsg: 'Test indexing a function return with a side-effect: (functionReturnArray())[0]'
 },
 {
   fShaderId: 'fshader-array-initialization',
   fShaderSuccess: true,
   linkSuccess: true,
   passMsg: 'Test indexing an array initialization: (float[3](2.0, 1.0, 0.0))[0]'
 },
-{
-  fShaderId: 'fshader-sequence-operator',
-  fShaderSuccess: true,
-  linkSuccess: true,
-  passMsg: 'Test indexing a sequence operator: (a, b)[0]'
-},
 ], 2);
 
 </script>
 </body>
 </html>
--- a/dom/events/test/test_bug456273.html
+++ b/dom/events/test/test_bug456273.html
@@ -18,17 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="edit456273" contenteditable="true">text</div>
 
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 456273 **/
 
 function doTest() {
-  var ev = document.createEvent('KeyEvents');
+  var ev = document.createEvent('KeyboardEvent');
   ev.initKeyEvent("keypress", true, true, null, true, false,
                  false, false, 0, "z".charCodeAt(0));
   SpecialPowers.dispatchEvent(window, document.getElementById('edit456273'), ev);
 
   ok(true, "PASS");
   SimpleTest.finish();
 }
 
--- a/dom/events/test/test_bug508479.html
+++ b/dom/events/test/test_bug508479.html
@@ -34,25 +34,25 @@ function fireDrop(element, shouldAllowDr
   synthesizeMouse(element, 2, 2, { type: "mousedown" });
   synthesizeMouse(element, 11, 11, { type: "mousemove" });
   synthesizeMouse(element, 20, 20, { type: "mousemove" });
   window.removeEventListener("dragstart", trapDrag, true);
   synthesizeMouse(element, 20, 20, { type: "mouseup" });
 
   ds.startDragSession();
 
-  var event = document.createEvent("DragEvents");
+  var event = document.createEvent("DragEvent");
   event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
   fireEvent(element, event);
 
   is(ds.getCurrentSession().canDrop, shouldAllowDrop, "Unexpected .canDrop");
   is(ds.getCurrentSession().onlyChromeDrop, shouldAllowOnlyChromeDrop,
      "Unexpected .onlyChromeDrop");
 
-  event = document.createEvent("DragEvents");
+  event = document.createEvent("DragEvent");
   event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
   fireEvent(element, event);
 
   ds.endDragSession(false);
   ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!");
 }
 
 var chromeGotEvent = false;
--- a/dom/events/test/test_bug591249.xul
+++ b/dom/events/test/test_bug591249.xul
@@ -55,17 +55,17 @@ function RunTest() {
   // need to use real mouse action to get the dataTransfer
   window.addEventListener("dragstart", trapDrag, true);
   synthesizeMouse(image, 2, 2, { type: "mousedown" });
   synthesizeMouse(image, 11, 11, { type: "mousemove" });
   synthesizeMouse(image, 20, 20, { type: "mousemove" });
   window.removeEventListener("dragstart", trapDrag, true);
   synthesizeMouse(image, 20, 20, { type: "mouseup" });
 
-  var event = document.createEvent("DragEvents");
+  var event = document.createEvent("DragEvent");
   event.initDragEvent("dragover", true, true, iBox.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, iBox, dataTransfer);
   fireEvent(iBox, event);
   synthesizeMouse(image, 3, 3, { type: "mousedown" });
   synthesizeMouse(image, 23, 23, { type: "mousemove" });
   synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mousemove" });
   ok(window.getComputedStyle(iBox).backgroundColor == "rgb(255, 255, 0)", "The -moz-drag-over style should be applied.");
   synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mouseup" });
   window.setTimeout(function () { completeTest(iBox); }, 40);
--- a/dom/events/test/test_dom_keyboard_event.html
+++ b/dom/events/test/test_dom_keyboard_event.html
@@ -37,32 +37,32 @@ function testInitializingUntrustedEvent(
       ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
       keyCode: 0x11, charCode: 0x30 },
 
     { createEventArg: "keyboardEvent",
       type: "boo", bubbles: false, cancelable: false, view: window,
       ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
       keyCode: 0x30, charCode: 0x40 },
 
-    { createEventArg: "KeyEvents",
+    { createEventArg: "KeyBoardEvent",
       type: "foo", bubbles: true, cancelable: true, view: null,
       ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
       keyCode: 0x00, charCode: 0x50 },
 
-    { createEventArg: "keyevents",
+    { createEventArg: "keyboardevEnt",
       type: "bar", bubbles: false, cancelable: true, view: window,
       ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
       keyCode: 0x00, charCode: 0x60 },
 
-    { createEventArg: "Keyevents",
+    { createEventArg: "KeyboaRdevent",
       type: "keydown", bubbles: true, cancelable: false, view: null,
       ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
       keyCode: 0x30, charCode: 0x00 },
 
-    { createEventArg: "keyEvents",
+    { createEventArg: "KEYBOARDEVENT",
       type: "keyup", bubbles: false, cancelable: false, view: window,
       ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
       keyCode: 0x10, charCode: 0x80 },
 
     { createEventArg: "KeyboardEvent",
       type: "keypress", bubbles: false, cancelable: false, view: window,
       ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
       keyCode: 0x10, charCode: 0x80 },
--- a/dom/events/test/test_dragstart.html
+++ b/dom/events/test/test_dragstart.html
@@ -52,18 +52,18 @@ function afterDragTests()
 
   var evt = document.createEvent("dragevent");
   ok(evt instanceof DragEvent, "synthetic dragevent class")
   ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent")
   evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15,
                     false, true, false, false, 0, null, null);
   $("synthetic").dispatchEvent(evt);
 
-  var evt = document.createEvent("dragevents");
-  ok(evt instanceof DragEvent, "synthetic dragevents class")
+  var evt = document.createEvent("dragevent");
+  ok(evt instanceof DragEvent, "synthetic dragevent class")
   evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15,
                     true, false, true, true, 2, document.documentElement, null);
   $("synthetic2").dispatchEvent(evt);
 
   // next, dragging links and images
   sendMouseEventsForDrag("link");
   sendMouseEventsForDrag("image");
 
--- a/dom/flyweb/FlyWebPublishedServer.cpp
+++ b/dom/flyweb/FlyWebPublishedServer.cpp
@@ -166,16 +166,26 @@ NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPubli
 
 FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
                                                      const nsAString& aName,
                                                      const FlyWebPublishOptions& aOptions)
   : FlyWebPublishedServer(aOwner, aName, aOptions)
   , mHttpServer(new HttpServer())
 {
   LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this);
+}
+
+void
+FlyWebPublishedServerImpl::PermissionGranted(bool aGranted)
+{
+  LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted);
+  if (!aGranted) {
+    PublishedServerStarted(NS_ERROR_FAILURE);
+    return;
+  }
 
   mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this);
 }
 
 void
 FlyWebPublishedServerImpl::Close()
 {
   FlyWebPublishedServer::Close();
@@ -247,72 +257,84 @@ FlyWebPublishedServerImpl::OnWebSocketAc
 }
 
 /******** FlyWebPublishedServerChild ********/
 
 FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
                                                        const nsAString& aName,
                                                        const FlyWebPublishOptions& aOptions)
   : FlyWebPublishedServer(aOwner, aName, aOptions)
-  , mActorDestroyed(false)
+  , mActorExists(false)
 {
   LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this);
 
-  ContentChild::GetSingleton()->
-    SendPFlyWebPublishedServerConstructor(this,
-                                          PromiseFlatString(aName),
-                                          aOptions);
-
   // The matching release happens when the actor is destroyed, in
   // ContentChild::DeallocPFlyWebPublishedServerChild
   NS_ADDREF_THIS();
 }
 
+void
+FlyWebPublishedServerChild::PermissionGranted(bool aGranted)
+{
+  if (!aGranted) {
+    PublishedServerStarted(NS_ERROR_FAILURE);
+    return;
+  }
+
+  mActorExists = true;
+  FlyWebPublishOptions options;
+  options.mUiUrl = mUiUrl;
+
+  // Proceed with initialization.
+  ContentChild::GetSingleton()->
+    SendPFlyWebPublishedServerConstructor(this, mName, options);
+}
+
 bool
 FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus)
 {
   LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   PublishedServerStarted(aStatus);
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvServerClose()
 {
   LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   Close();
 
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest,
                                              const uint64_t& aRequestId)
 {
   LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   RefPtr<InternalRequest> request = new InternalRequest(aRequest);
   mPendingRequests.Put(request, aRequestId);
   FireFetchEvent(request);
 
   return true;
 }
 
 bool
 FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest,
                                                  const uint64_t& aRequestId,
                                                  PTransportProviderChild* aProvider)
 {
   LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this);
-  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT(mActorExists);
 
   RefPtr<InternalRequest> request = new InternalRequest(aRequest);
   mPendingRequests.Put(request, aRequestId);
 
   // Not addreffing here. The addref was already done when the
   // PTransportProvider child constructor original ran.
   mPendingTransportProviders.Put(aRequestId,
     dont_AddRef(static_cast<TransportProviderChild*>(aProvider)));
@@ -322,26 +344,26 @@ FlyWebPublishedServerChild::RecvWebSocke
   return true;
 }
 
 void
 FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this);
 
-  mActorDestroyed = true;
+  mActorExists = false;
 }
 
 void
 FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest,
                                             InternalResponse* aResponse)
 {
   LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
     return;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -356,17 +378,17 @@ FlyWebPublishedServerChild::OnFetchRespo
 
 already_AddRefed<nsITransportProvider>
 FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest,
                                                       const Optional<nsAString>& aProtocol,
                                                       ErrorResult& aRv)
 {
   LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this);
     return nullptr;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -395,17 +417,17 @@ FlyWebPublishedServerChild::OnWebSocketA
 }
 
 void
 FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest,
                                                 InternalResponse* aResponse)
 {
   LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
 
-  if (mActorDestroyed) {
+  if (!mActorExists) {
     LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
     return;
   }
 
   uint64_t id = mPendingRequests.Get(aRequest);
   MOZ_ASSERT(id);
   mPendingRequests.Remove(aRequest);
 
@@ -423,17 +445,17 @@ FlyWebPublishedServerChild::OnWebSocketR
 
 void
 FlyWebPublishedServerChild::Close()
 {
   LOG_I("FlyWebPublishedServerChild::Close(%p)", this);
 
   FlyWebPublishedServer::Close();
 
-  if (!mActorDestroyed) {
+  if (mActorExists) {
     LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this);
 
     Send__delete__(this);
   }
 }
 
 /******** FlyWebPublishedServerParent ********/
 
--- a/dom/flyweb/FlyWebPublishedServer.h
+++ b/dom/flyweb/FlyWebPublishedServer.h
@@ -52,16 +52,18 @@ public:
     return mName;
   }
 
   void GetUiUrl(nsAString& aUiUrl)
   {
     aUiUrl = mUiUrl;
   }
 
+  virtual void PermissionGranted(bool aGranted) = 0;
+
   virtual void OnFetchResponse(InternalRequest* aRequest,
                                InternalResponse* aResponse) = 0;
   already_AddRefed<WebSocket>
     OnWebSocketAccept(InternalRequest* aConnectRequest,
                       const Optional<nsAString>& aProtocol,
                       ErrorResult& aRv);
   virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
                                    InternalResponse* aResponse) = 0;
--- a/dom/flyweb/FlyWebPublishedServerIPC.h
+++ b/dom/flyweb/FlyWebPublishedServerIPC.h
@@ -45,16 +45,17 @@ public:
   void GetCertKey(nsACString& aKey) {
     if (mHttpServer) {
       mHttpServer->GetCertKey(aKey);
     } else {
       aKey.Truncate();
     }
   }
 
+  virtual void PermissionGranted(bool aGranted) override;
   virtual void OnFetchResponse(InternalRequest* aRequest,
                                InternalResponse* aResponse) override;
   virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
                                    InternalResponse* aResponse) override;
   virtual already_AddRefed<nsITransportProvider>
     OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
                               const Optional<nsAString>& aProtocol,
                               ErrorResult& aRv) override;
@@ -93,16 +94,17 @@ private:
 class FlyWebPublishedServerChild final : public FlyWebPublishedServer
                                        , public PFlyWebPublishedServerChild
 {
 public:
   FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
                              const nsAString& aName,
                              const FlyWebPublishOptions& aOptions);
 
+  virtual void PermissionGranted(bool aGranted) override;
   virtual bool RecvServerReady(const nsresult& aStatus) override;
   virtual bool RecvServerClose() override;
   virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest,
                                 const uint64_t& aRequestId) override;
   virtual bool RecvWebSocketRequest(const IPCInternalRequest& aRequest,
                                     const uint64_t& aRequestId,
                                     PTransportProviderChild* aProvider) override;
 
@@ -120,17 +122,17 @@ public:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   ~FlyWebPublishedServerChild() {}
 
   nsDataHashtable<nsRefPtrHashKey<InternalRequest>, uint64_t> mPendingRequests;
   nsRefPtrHashtable<nsUint64HashKey, TransportProviderChild>
     mPendingTransportProviders;
-  bool mActorDestroyed;
+  bool mActorExists;
 };
 
 class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent
                                         , public nsIDOMEventListener
 {
 public:
   FlyWebPublishedServerParent(const nsAString& aName,
                               const FlyWebPublishOptions& aOptions);
--- a/dom/flyweb/FlyWebService.cpp
+++ b/dom/flyweb/FlyWebService.cpp
@@ -4,46 +4,160 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/FlyWebService.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
+#include "mozilla/AddonPathService.h"
 #include "nsISocketTransportService.h"
 #include "mdns/libmdns/nsDNSServiceInfo.h"
 #include "nsIUUIDGenerator.h"
 #include "nsStandardURL.h"
 #include "mozilla/Services.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
 #include "prnetdb.h"
 #include "DNS.h"
+#include "nsContentPermissionHelper.h"
 #include "nsSocketTransportService2.h"
 #include "nsSocketTransport2.h"
 #include "nsHashPropertyBag.h"
 #include "nsNetUtil.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIProperty.h"
 #include "nsICertOverrideService.h"
 
 namespace mozilla {
 namespace dom {
 
 struct FlyWebPublishOptions;
 
 static LazyLogModule gFlyWebServiceLog("FlyWebService");
 #undef LOG_I
 #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
+
 #undef LOG_E
 #define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
+
 #undef LOG_TEST_I
 #define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
 
+class FlyWebPublishServerPermissionCheck final
+  : public nsIContentPermissionRequest
+  , public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
+                                     FlyWebPublishedServer* aServer)
+    : mServiceName(aServiceName)
+    , mWindowID(aWindowID)
+    , mServer(aServer)
+  {}
+
+  uint64_t WindowID() const
+  {
+    return mWindowID;
+  }
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+    if (!globalWindow) {
+      return Cancel();
+    }
+    mWindow = globalWindow->AsInner();
+    if (NS_WARN_IF(!mWindow)) {
+      return Cancel();
+    }
+
+    nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
+    if (NS_WARN_IF(!doc)) {
+      return Cancel();
+    }
+
+    mPrincipal = doc->NodePrincipal();
+    MOZ_ASSERT(mPrincipal);
+
+    mRequester = new nsContentPermissionRequester(mWindow);
+    return nsContentPermissionUtils::AskPermission(this, mWindow);
+  }
+
+  NS_IMETHOD Cancel() override
+  {
+    Resolve(false);
+    return NS_OK;
+  }
+
+  NS_IMETHOD Allow(JS::HandleValue aChoices) override
+  {
+    MOZ_ASSERT(aChoices.isUndefined());
+    Resolve(true);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetTypes(nsIArray** aTypes) override
+  {
+    nsTArray<nsString> emptyOptions;
+    return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
+                                                           NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
+  }
+
+  NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
+  {
+    NS_ENSURE_ARG_POINTER(aRequester);
+    nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
+    requester.forget(aRequester);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
+  {
+    NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
+  {
+    NS_IF_ADDREF(*aRequestingWindow = mWindow);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
+  {
+    *aRequestingElement = nullptr;
+    return NS_OK;
+  }
+
+private:
+  void Resolve(bool aResolve)
+  {
+    mServer->PermissionGranted(aResolve);
+  }
+
+  virtual ~FlyWebPublishServerPermissionCheck() = default;
+
+  nsCString mServiceName;
+  uint64_t mWindowID;
+  RefPtr<FlyWebPublishedServer> mServer;
+  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIContentPermissionRequester> mRequester;
+};
+
+NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
+                  nsIContentPermissionRequest,
+                  nsIRunnable)
+
 class FlyWebMDNSService final
   : public nsIDNSServiceDiscoveryListener
   , public nsIDNSServiceResolveListener
   , public nsIDNSRegistrationListener
   , public nsITimerCallback
 {
   friend class FlyWebService;
 
@@ -836,39 +950,88 @@ FlyWebService::Init()
       mMDNSFlywebService = nullptr;
       rv.SuppressException();
     }
   }
 
   return ErrorResult(NS_OK);
 }
 
+static already_AddRefed<FlyWebPublishPromise>
+MakeRejectionPromise(const char* name)
+{
+    MozPromiseHolder<FlyWebPublishPromise> holder;
+    RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
+    holder.Reject(NS_ERROR_FAILURE, name);
+    return promise.forget();
+}
+
 already_AddRefed<FlyWebPublishPromise>
 FlyWebService::PublishServer(const nsAString& aName,
                              const FlyWebPublishOptions& aOptions,
                              nsPIDOMWindowInner* aWindow)
 {
   // Scan uiUrl for illegal characters
 
   RefPtr<FlyWebPublishedServer> existingServer =
     FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
   if (existingServer) {
     LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
           NS_ConvertUTF16toUTF8(aName).get());
-    MozPromiseHolder<FlyWebPublishPromise> holder;
-    RefPtr<FlyWebPublishPromise> promise = holder.Ensure(__func__);
-    holder.Reject(NS_ERROR_FAILURE, __func__);
-    return promise.forget();
+    return MakeRejectionPromise(__func__);
   }
 
   RefPtr<FlyWebPublishedServer> server;
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
   } else {
     server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
+
+    // Before proceeding, ensure that the FlyWeb system addon exists.
+    nsresult rv;
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png"));
+    if (NS_FAILED(rv)) {
+      return MakeRejectionPromise(__func__);
+    }
+
+    JSAddonId *addonId = MapURIToAddonID(uri);
+    if (!addonId) {
+      LOG_E("PublishServer: Failed to find FlyWeb system addon.");
+      return MakeRejectionPromise(__func__);
+    }
+
+    JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
+    nsAutoString addonIdString;
+    AssignJSFlatString(addonIdString, flat);
+    if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
+      nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
+      LOG_E("PublishServer: FlyWeb resource found on wrong system addon: %s.", addonIdCString.get());
+      return MakeRejectionPromise(__func__);
+    }
+  }
+
+  if (aWindow) {
+    nsresult rv;
+
+    MOZ_ASSERT(NS_IsMainThread());
+    rv = NS_DispatchToCurrentThread(
+      MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
+        NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
+            NS_ConvertUTF16toUTF8(aName).get());
+      return MakeRejectionPromise(__func__);
+    }
+  } else {
+    // If aWindow is null, we're definitely in the e10s parent process.
+    // In this case, we know that permission has already been granted
+    // by the user because of content-process prompt.
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+    server->PermissionGranted(true);
   }
 
   mServers.AppendElement(server);
 
   return server->GetPublishPromise();
 }
 
 already_AddRefed<FlyWebPublishedServer>
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -1532,17 +1532,17 @@ HTMLFormElement::NamedGetter(const nsASt
 
   aFound = false;
   return nullptr;
 }
 
 void
 HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval)
 {
-  // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320
+  // TODO https://github.com/whatwg/html/issues/1731
 }
 
 already_AddRefed<nsISupports>
 HTMLFormElement::FindNamedItem(const nsAString& aName,
                                nsWrapperCache** aCache)
 {
   // FIXME Get the wrapper cache from DoResolveName.
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3284,17 +3284,17 @@ HTMLInputElement::GetRadioGroupContainer
     return mForm;
   }
 
   //XXXsmaug It isn't clear how this should work in Shadow DOM.
   return static_cast<nsDocument*>(GetUncomposedDoc());
 }
 
 already_AddRefed<nsIDOMHTMLInputElement>
-HTMLInputElement::GetSelectedRadioButton()
+HTMLInputElement::GetSelectedRadioButton() const
 {
   nsIRadioGroupContainer* container = GetRadioGroupContainer();
   if (!container) {
     return nullptr;
   }
 
   nsAutoString name;
   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
@@ -3355,16 +3355,23 @@ HTMLInputElement::SetCheckedInternal(boo
     }
   }
 
   UpdateAllValidityStates(aNotify);
 
   // Notify the document that the CSS :checked pseudoclass for this element
   // has changed state.
   UpdateState(aNotify);
+
+  // Notify all radios in the group that value has changed, this is to let
+  // radios to have the chance to update its states, e.g., :indeterminate.
+  if (mType == NS_FORM_INPUT_RADIO) {
+    nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
+    VisitGroup(visitor, aNotify);
+  }
 }
 
 void
 HTMLInputElement::Blur(ErrorResult& aError)
 {
   if (mType == NS_FORM_INPUT_NUMBER) {
     // Blur our anonymous text control, if we have one. (DOM 'change' event
     // firing and other things depend on this.)
@@ -6415,16 +6422,25 @@ HTMLInputElement::IntrinsicState() const
       state |= NS_EVENT_STATE_CHECKED;
     }
 
     // Check current indeterminate state (:indeterminate)
     if (mType == NS_FORM_INPUT_CHECKBOX && mIndeterminate) {
       state |= NS_EVENT_STATE_INDETERMINATE;
     }
 
+    if (mType == NS_FORM_INPUT_RADIO) {
+      nsCOMPtr<nsIDOMHTMLInputElement> selected = GetSelectedRadioButton();
+      bool indeterminate = !selected && !mChecked;
+
+      if (indeterminate) {
+        state |= NS_EVENT_STATE_INDETERMINATE;
+      }
+    }
+
     // Check whether we are the default checked element (:default)
     if (DefaultChecked()) {
       state |= NS_EVENT_STATE_DEFAULT;
     }
   } else if (mType == NS_FORM_INPUT_IMAGE) {
     state |= nsImageLoadingContent::ImageState();
   }
 
@@ -6638,16 +6654,19 @@ HTMLInputElement::WillRemoveFromRadioGro
 
   nsAutoString name;
   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
 
   // If this button was checked, we need to notify the group that there is no
   // longer a selected radio button
   if (mChecked) {
     container->SetCurrentRadioButton(name, nullptr);
+
+    nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
+    VisitGroup(visitor, true);
   }
 
   // Remove this radio from its group in the container.
   // We need to call UpdateValueMissingValidityStateForRadio before to make sure
   // the group validity is updated (with this element being ignored).
   UpdateValueMissingValidityStateForRadio(true);
   container->RemoveFromRadioGroup(name, static_cast<nsIFormControl*>(this));
 }
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -259,17 +259,17 @@ public:
 
  /**
    * Helper function returning the currently selected button in the radio group.
    * Returning null if the element is not a button or if there is no selectied
    * button in the group.
    *
    * @return the selected button (or null).
    */
-  already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton();
+  already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton() const;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLInputElement,
                                            nsGenericHTMLFormElementWithState)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
--- a/dom/html/nsRadioVisitor.cpp
+++ b/dom/html/nsRadioVisitor.cpp
@@ -50,8 +50,20 @@ nsRadioSetValueMissingState::Visit(nsIFo
   input->SetValidityState(nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING,
                           mValidity);
 
   input->UpdateState(true);
 
   return true;
 }
 
+bool
+nsRadioUpdateStateVisitor::Visit(nsIFormControl* aRadio)
+{
+  if (aRadio == mExcludeElement) {
+    return true;
+  }
+
+  HTMLInputElement* input = static_cast<HTMLInputElement*>(aRadio);
+  input->UpdateState(true);
+
+  return true;
+}
\ No newline at end of file
--- a/dom/html/nsRadioVisitor.h
+++ b/dom/html/nsRadioVisitor.h
@@ -89,10 +89,23 @@ public:
   virtual bool Visit(nsIFormControl* aRadio) override;
 
 protected:
   nsIFormControl* mExcludeElement;
   bool mValidity;
   bool mNotify;
 };
 
+class nsRadioUpdateStateVisitor : public nsRadioVisitor
+{
+public:
+  explicit nsRadioUpdateStateVisitor(nsIFormControl* aExcludeElement)
+    : mExcludeElement(aExcludeElement)
+    { }
+
+  virtual bool Visit(nsIFormControl* aRadio) override;
+
+protected:
+  nsIFormControl* mExcludeElement;
+};
+
 #endif // _nsRadioVisitor_h__
 
--- a/dom/html/reftests/autofocus/reftest.list
+++ b/dom/html/reftests/autofocus/reftest.list
@@ -1,13 +1,13 @@
 default-preferences pref(dom.forms.number,true)
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-load.html input-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-create.html input-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == input-number.html input-number-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-load.html button-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-create.html button-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-load.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-create.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(skiaContent,9,6) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-create.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == autofocus-after-load.html autofocus-after-load-ref.html
 fails-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) needs-focus == autofocus-leaves-iframe.html autofocus-leaves-iframe-ref.html # B2G focus difference between test and reference # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) needs-focus == autofocus-after-body-focus.html autofocus-after-body-focus-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
--- a/dom/html/test/file_fullscreen-api-keys.html
+++ b/dom/html/test/file_fullscreen-api-keys.html
@@ -4,29 +4,29 @@
   <meta charset="UTF-8">
 </head>
 <body>
 <script>
 window.addEventListener("Test:DispatchKeyEvents", aEvent => {
   var keyCode = KeyEvent["DOM_" + aEvent.detail.code];
 
   document.body.focus();
-  var evt = document.createEvent("KeyEvents");
+  var evt = document.createEvent("KeyboardEvent");
   evt.initKeyEvent("keydown", true, true, window,
                    false, false, false, false,
                    keyCode, 0);
   document.body.dispatchEvent(evt);
 
-  evt = document.createEvent("KeyEvents");
+  evt = document.createEvent("KeyboardEvent");
   evt.initKeyEvent("keypress", true, true, window,
                    false, false, false, false,
                    keyCode, 0);
   document.body.dispatchEvent(evt);
 
-  evt = document.createEvent("KeyEvents");
+  evt = document.createEvent("KeyboardEvent");
   evt.initKeyEvent("keyup", true, true, window,
                    false, false, false, false,
                    keyCode, 0);
   document.body.dispatchEvent(evt);
 });
 </script>
 </body>
 </html>
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
   test_input_number_data.js
   !/dom/html/test/reflect.js
 
 [test_bug1039548.html]
 [test_bug1283915.html]
 [test_bug1286509.html]
 skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g
 [test_button_attributes_reflection.html]
+[test_input_radio_indeterminate.html]
 [test_input_radio_radiogroup.html]
 [test_input_radio_required.html]
 [test_change_event.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_datalist_element.html]
 [test_form_attribute-1.html]
 [test_form_attribute-2.html]
 [test_form_attribute-3.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_input_radio_indeterminate.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=885359
+-->
+<head>
+  <title>Test for Bug 885359</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885359">Mozilla Bug 343444</a>
+<p id="display"></p>
+<form>
+  <input type="radio" id='radio1'/><br/>
+
+  <input type="radio" id="g1radio1" name="group1"/>
+  <input type="radio" id="g1radio2" name="group1"/></br>
+  <input type="radio" id="g1radio3" name="group1"/></br>
+
+  <input type="radio" id="g2radio1" name="group2"/>
+  <input type="radio" id="g2radio2" name="group2" checked/></br>
+</form>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var radio1 = document.getElementById("radio1");
+var g1radio1 = document.getElementById("g1radio1");
+var g1radio2 = document.getElementById("g1radio2");
+var g1radio3 = document.getElementById("g1radio3");
+var g2radio1 = document.getElementById("g2radio1");
+var g2radio2 = document.getElementById("g2radio2");
+
+SimpleTest.waitForFocus(function() {
+  test();
+  SimpleTest.finish();
+});
+
+function verifyIndeterminateState(aElement, aIsIndeterminate, aMessage) {
+  is(aElement.mozMatchesSelector(':indeterminate'), aIsIndeterminate, aMessage);
+}
+
+function test() {
+  // Initial State.
+  verifyIndeterminateState(radio1, true,
+    "Unchecked radio in its own group (no name attribute)");
+  verifyIndeterminateState(g1radio1, true, "No selected radio in its group");
+  verifyIndeterminateState(g1radio2, true, "No selected radio in its group");
+  verifyIndeterminateState(g1radio3, true, "No selected radio in its group");
+  verifyIndeterminateState(g2radio1, false, "Selected radio in its group");
+  verifyIndeterminateState(g2radio2, false, "Selected radio in its group");
+
+  // Selecting radio buttion.
+  g1radio1.checked = true;
+  verifyIndeterminateState(g1radio1, false,
+    "Selecting a radio should affect all radios in the group");
+  verifyIndeterminateState(g1radio2, false,
+    "Selecting a radio should affect all radios in the group");
+  verifyIndeterminateState(g1radio3, false,
+    "Selecting a radio should affect all radios in the group");
+
+  // Changing the selected radio button.
+  g1radio3.checked = true;
+  verifyIndeterminateState(g1radio1, false,
+    "Selecting a radio should affect all radios in the group");
+  verifyIndeterminateState(g1radio2, false,
+    "Selecting a radio should affect all radios in the group");
+  verifyIndeterminateState(g1radio3, false,
+    "Selecting a radio should affect all radios in the group");
+
+  // Deselecting radio button.
+  g2radio2.checked = false;
+  verifyIndeterminateState(g2radio1, true,
+    "Deselecting a radio should affect all radios in the group");
+  verifyIndeterminateState(g2radio2, true,
+    "Deselecting a radio should affect all radios in the group");
+
+  // Move a selected radio button to another group.
+  g1radio3.name = "group2";
+
+  // The radios' state in the original group becomes indeterminated.
+  verifyIndeterminateState(g1radio1, true,
+    "Removing a radio from a group should affect all radios in the group");
+  verifyIndeterminateState(g1radio2, true,
+    "Removing a radio from a group should affect all radios in the group");
+
+  // The radios' state in the new group becomes determinated.
+  verifyIndeterminateState(g1radio3, false,
+    "Adding a radio from a group should affect all radios in the group");
+  verifyIndeterminateState(g2radio1, false,
+    "Adding a radio from a group should affect all radios in the group");
+  verifyIndeterminateState(g2radio2, false,
+    "Adding a radio from a group should affect all radios in the group");
+
+  // Change input type to 'text'.
+  g1radio3.type = "text";
+  verifyIndeterminateState(g1radio3, false,
+    "Input type text does not have an indeterminate state");
+  verifyIndeterminateState(g2radio1, true,
+    "Changing input type should affect all radios in the group");
+  verifyIndeterminateState(g2radio2, true,
+    "Changing input type should affect all radios in the group");
+}
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -3,27 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "domstubs.idl"
 
 [builtinclass, scriptable, uuid(8e49f7b0-1f98-4939-bf91-e9c39cd56434)]
 interface nsITabParent : nsISupports
 {
-  void injectTouchEvent(in AString aType,
-                        [array, size_is(count)] in uint32_t aIdentifiers,
-                        [array, size_is(count)] in int32_t aXs,
-                        [array, size_is(count)] in int32_t aYs,
-                        [array, size_is(count)] in uint32_t aRxs,
-                        [array, size_is(count)] in uint32_t aRys,
-                        [array, size_is(count)] in float aRotationAngles,
-                        [array, size_is(count)] in float aForces,
-                        in uint32_t count,
-                        in long aModifiers);
-
   void getChildProcessOffset(out int32_t aCssX, out int32_t aCssY);
 
   readonly attribute boolean useAsyncPanZoom;
 
   /**
     * Manages the docshell active state of the remote browser.
     */
   attribute boolean docShellIsActive;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -27,17 +27,16 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
 #include "mozilla/dom/GetFilesHelper.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/ProcessGlobal.h"
-#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
@@ -2258,32 +2257,16 @@ nsresult
 ContentChild::AddRemoteAlertObserver(const nsString& aData,
                                      nsIObserver* aObserver)
 {
   NS_ASSERTION(aObserver, "Adding a null observer?");
   mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
   return NS_OK;
 }
 
-
-bool
-ContentChild::RecvSystemMemoryAvailable(const uint64_t& aGetterId,
-                                        const uint32_t& aMemoryAvailable)
-{
-  RefPtr<Promise> p = dont_AddRef(reinterpret_cast<Promise*>(aGetterId));
-
-  if (!aMemoryAvailable) {
-    p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-    return true;
-  }
-
-  p->MaybeResolve((int)aMemoryAvailable);
-  return true;
-}
-
 bool
 ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
 {
   Preferences::SetPreference(aPref);
   return true;
 }
 
 bool
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -399,19 +399,16 @@ public:
   virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL,
                                       const bool& haveBidiKeyboards) override;
 
   virtual bool RecvNotifyVisited(const URIParams& aURI) override;
 
   // auto remove when alertfinished is received.
   nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
-  virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
-                                         const uint32_t& aMemoryAvailable) override;
-
   virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
   virtual bool RecvVarUpdate(const GfxVarUpdate& pref) override;
 
   virtual bool RecvDataStoragePut(const nsString& aFilename,
                                   const DataStorageItem& aItem) override;
 
   virtual bool RecvDataStorageRemove(const nsString& aFilename,
                                      const nsCString& aKey,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3905,30 +3905,16 @@ ContentParent::RecvNSSU2FTokenSign(nsTAr
 
   MOZ_ASSERT(buffer);
   aSignature->ReplaceElementsAt(0, aSignature->Length(), buffer, bufferlen);
   free(buffer);
   return NS_SUCCEEDED(rv);
 }
 
 bool
-ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId)
-{
-  uint32_t memoryTotal = 0;
-
-#if defined(XP_LINUX)
-  memoryTotal = mozilla::hal::GetTotalSystemMemoryLevel();
-#endif
-
-  Unused << SendSystemMemoryAvailable(aGetterId, memoryTotal);
-
-  return true;
-}
-
-bool
 ContentParent::RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache)
 {
   *aLookAndFeelIntCache = LookAndFeel::GetIntCache();
   return true;
 }
 
 bool
 ContentParent::RecvIsSecureURI(const uint32_t& type,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1008,18 +1008,16 @@ private:
 
   virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
                                                    const bool& aHidden) override;
 
   virtual bool RecvAudioChannelServiceStatus(const bool& aTelephonyChannel,
                                              const bool& aContentOrNormalChannel,
                                              const bool& aAnyChannel) override;
 
-  virtual bool RecvGetSystemMemory(const uint64_t& getterId) override;
-
   virtual bool RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
 
   virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) override;
 
   virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) override;
 
   virtual bool RecvCreateFakeVolume(const nsString& aFsName,
                                     const nsString& aMountPoint) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -513,18 +513,16 @@ child:
 
     async ClearImageCache(bool privateLoader, bool chrome);
 
     async SetOffline(bool offline);
     async SetConnectivity(bool connectivity);
 
     async NotifyVisited(URIParams uri);
 
-    async SystemMemoryAvailable(uint64_t getterId, uint32_t memoryAvailable);
-
     async PreferenceUpdate(PrefSetting pref);
     async VarUpdate(GfxVarUpdate var);
 
     async DataStoragePut(nsString aFilename, DataStorageItem aItem);
     async DataStorageRemove(nsString aFilename, nsCString aKey, DataStorageType aType);
     async DataStorageClear(nsString aFilename);
 
     async NotifyAlertsObserver(nsCString topic, nsString data);
@@ -824,18 +822,16 @@ parent:
      * |challenge| The Challenge to satisfy in the response.
      * |keyHandle| The Key Handle opaque object to use.
      * |signature| The resulting signature.
      */
     sync NSSU2FTokenSign(uint8_t[] application, uint8_t[] challenge,
                          uint8_t[] keyHandle)
         returns (uint8_t[] signature);
 
-    async GetSystemMemory(uint64_t getterId);
-
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
     async AccumulateMixedContentHSTS(URIParams uri, bool active);
 
     sync GetLookAndFeelCache()
         returns (LookAndFeelInt[] lookAndFeelIntCache);
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2805,81 +2805,16 @@ TabParent::GetLoadContext()
                                   mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW,
                                   OriginAttributesRef());
     mLoadContext = loadContext;
   }
   return loadContext.forget();
 }
 
 NS_IMETHODIMP
-TabParent::InjectTouchEvent(const nsAString& aType,
-                            uint32_t* aIdentifiers,
-                            int32_t* aXs,
-                            int32_t* aYs,
-                            uint32_t* aRxs,
-                            uint32_t* aRys,
-                            float* aRotationAngles,
-                            float* aForces,
-                            uint32_t aCount,
-                            int32_t aModifiers)
-{
-  EventMessage msg;
-  nsContentUtils::GetEventMessageAndAtom(aType, eTouchEventClass, &msg);
-  if (msg != eTouchStart && msg != eTouchMove &&
-      msg != eTouchEnd && msg != eTouchCancel) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (!widget) {
-    return NS_ERROR_FAILURE;
-  }
-
-  WidgetTouchEvent event(true, msg, widget);
-  event.mModifiers = aModifiers;
-  event.mTime = PR_IntervalNow();
-
-  nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
-  if (!content || !content->OwnerDoc()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsIDocument* doc = content->OwnerDoc();
-  if (!doc || !doc->GetShell()) {
-    return NS_ERROR_FAILURE;
-  }
-  nsPresContext* presContext = doc->GetShell()->GetPresContext();
-
-  event.mTouches.SetCapacity(aCount);
-  for (uint32_t i = 0; i < aCount; ++i) {
-    LayoutDeviceIntPoint pt =
-      LayoutDeviceIntPoint::FromAppUnitsRounded(
-        CSSPoint::ToAppUnits(CSSPoint(aXs[i], aYs[i])),
-        presContext->AppUnitsPerDevPixel());
-
-    LayoutDeviceIntPoint radius =
-      LayoutDeviceIntPoint::FromAppUnitsRounded(
-        CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
-        presContext->AppUnitsPerDevPixel());
-
-    RefPtr<Touch> t =
-      new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
-
-    // Consider all injected touch events as changedTouches. For more details
-    // about the meaning of changedTouches for each event, see
-    // https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches
-    t->mChanged = true;
-    event.mTouches.AppendElement(t);
-  }
-
-  SendRealTouchEvent(event);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom)
 {
   *useAsyncPanZoom = AsyncPanZoomEnabled();
   return NS_OK;
 }
 
 // defined in nsITabParent
 NS_IMETHODIMP
--- a/dom/plugins/test/reftest/reftest.list
+++ b/dom/plugins/test/reftest/reftest.list
@@ -1,26 +1,26 @@
 # basic sanity checking
 random-if(!haveTestPlugin) != plugin-sanity.html about:blank
 fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832
 # fuzzy because of anti-aliasing in dashed border
 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430
 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html # bug 629430
 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) skip-if(!haveTestPlugin) skip-if(Android||B2G) == border-padding-3.html border-padding-3-ref.html # bug 629430 # bug 773482
 # The following two "pluginproblemui-direction" tests are unreliable on all platforms. They should be re-written or replaced.
 #random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
 #random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-1-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-2-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-5-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-10-step.html plugin-background-ref.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-1-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-2-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-5-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-10-step.html plugin-background-ref.html
 random-if(!haveTestPlugin) == plugin-transform-1.html plugin-transform-1-ref.html
 fails-if(!haveTestPlugin) == plugin-transform-2.html plugin-transform-2-ref.html
 skip-if(!haveTestPlugin) == shrink-1.html shrink-1-ref.html
 skip-if(!haveTestPlugin) == update-1.html update-1-ref.html
 skip-if(!haveTestPlugin) == windowless-layers.html windowless-layers-ref.html
--- a/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js
+++ b/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js
@@ -58,17 +58,17 @@ Event.simulateKey = function(element, ev
     ctrlKey: false,
     altKey: false,
     shiftKey: false,
     metaKey: false,
     keyCode: 0,
     charCode: 0
   }, arguments[2] || {});
 
-  var oEvent = document.createEvent("KeyEvents");
+  var oEvent = document.createEvent("KeyboardEvent");
   oEvent.initKeyEvent(eventName, true, true, window, 
     options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
     options.keyCode, options.charCode );
   $(element).dispatchEvent(oEvent);
 };
 
 Event.simulateKeys = function(element, command) {
   for (var i=0; i<command.length; i++) {
--- a/dom/tests/mochitest/ajax/scriptaculous/src/unittest.js
+++ b/dom/tests/mochitest/ajax/scriptaculous/src/unittest.js
@@ -49,17 +49,17 @@ Event.simulateKey = function(element, ev
     ctrlKey: false,
     altKey: false,
     shiftKey: false,
     metaKey: false,
     keyCode: 0,
     charCode: 0
   }, arguments[2] || {});
 
-  var oEvent = document.createEvent("KeyEvents");
+  var oEvent = document.createEvent("KeyboardEvent");
   oEvent.initKeyEvent(eventName, true, true, window, 
     options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
     options.keyCode, options.charCode );
   $(element).dispatchEvent(oEvent);
 };
 
 Event.simulateKeys = function(element, command) {
   for(var i=0; i<command.length; i++) {
--- a/dom/tests/mochitest/whatwg/test_bug477323.html
+++ b/dom/tests/mochitest/whatwg/test_bug477323.html
@@ -25,17 +25,17 @@ function start()
   element.ondragenter = function(event) {gotdragenter = true;}
   element.ondragover = function(event) {gotdragover = true;}
   element.ondragleave = function(event) {gotdragleave = true;}
   element.ondrop = function(event) {gotdrop = true;}
   element.ondragend = function(event) {gotdragend = true;}
   
   function dispatch(eventName)
   {
-    var event = document.createEvent("DragEvents");
+    var event = document.createEvent("DragEvent");
     event.initDragEvent(eventName, true, true, window, 0, 5, 5, 5, 5,
                         false, false, false, false, 0, null, null);
     element.dispatchEvent(event);
   }
   
   dispatch("dragstart");
   dispatch("drag");
   dispatch("dragenter");
--- a/dom/webidl/HTMLFormElement.webidl
+++ b/dom/webidl/HTMLFormElement.webidl
@@ -6,19 +6,17 @@
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#htmlformelement
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
-// Should be LegacyUnenumerableNamedProperties.  See
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270369
-[OverrideBuiltins]
+[OverrideBuiltins, LegacyUnenumerableNamedProperties]
 interface HTMLFormElement : HTMLElement {
            [Pure, SetterThrows]
            attribute DOMString acceptCharset;
            [Pure, SetterThrows]
            attribute DOMString action;
            [Pure, SetterThrows]
            attribute DOMString autocomplete;
            [Pure, SetterThrows]
--- a/dom/webidl/MimeTypeArray.webidl
+++ b/dom/webidl/MimeTypeArray.webidl
@@ -1,15 +1,13 @@
 /* -*- 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/.
  */
 
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270364
+[LegacyUnenumerableNamedProperties]
 interface MimeTypeArray {
   readonly attribute unsigned long length;
 
   getter MimeType? item(unsigned long index);
   getter MimeType? namedItem(DOMString name);
 };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -24,17 +24,16 @@
 interface Navigator {
   // objects implementing this interface also implement the interfaces given below
 };
 Navigator implements NavigatorID;
 Navigator implements NavigatorLanguage;
 Navigator implements NavigatorOnLine;
 Navigator implements NavigatorContentUtils;
 Navigator implements NavigatorStorageUtils;
-Navigator implements NavigatorFeatures;
 Navigator implements NavigatorConcurrentHardware;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface NavigatorID {
   // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
   [Constant, Cached]
   readonly attribute DOMString appCodeName; // constant "Mozilla"
   [Constant, Cached]
@@ -87,25 +86,16 @@ interface NavigatorContentUtils {
 };
 
 [NoInterfaceObject]
 interface NavigatorStorageUtils {
   // NOT IMPLEMENTED
   //void yieldForStorageUpdates();
 };
 
-[NoInterfaceObject]
-interface NavigatorFeatures {
-  [ChromeOnly, Throws]
-  Promise<any> getFeature(DOMString name);
-
-  [ChromeOnly, Throws]
-  Promise<any> hasFeature(DOMString name);
-};
-
 partial interface Navigator {
   [Throws]
   readonly attribute Permissions permissions;
 };
 
 // Things that definitely need to be in the spec and and are not for some
 // reason.  See https://www.w3.org/Bugs/Public/show_bug.cgi?id=22406
 partial interface Navigator {
--- a/dom/webidl/Plugin.webidl
+++ b/dom/webidl/Plugin.webidl
@@ -1,17 +1,15 @@
 /* -*- 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/.
  */
 
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366
+[LegacyUnenumerableNamedProperties]
 interface Plugin {
   readonly attribute DOMString description;
   readonly attribute DOMString filename;
   readonly attribute DOMString version;
   readonly attribute DOMString name;
 
   readonly attribute unsigned long length;
   getter MimeType? item(unsigned long index);
--- a/dom/webidl/PluginArray.webidl
+++ b/dom/webidl/PluginArray.webidl
@@ -1,17 +1,15 @@
 /* -*- 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/.
  */
 
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366
+[LegacyUnenumerableNamedProperties]
 interface PluginArray {
   readonly attribute unsigned long length;
 
   getter Plugin? item(unsigned long index);
   getter Plugin? namedItem(DOMString name);
 
   void refresh(optional boolean reloadDocuments = false);
 };
--- a/editor/libeditor/tests/test_contenteditable_text_input_handling.html
+++ b/editor/libeditor/tests/test_contenteditable_text_input_handling.html
@@ -160,17 +160,17 @@ function runTests()
     }
 
     // When key events are fired on unfocused editor.
     function testDispatchedKeyEvent(aTarget)
     {
       var targetDescription = " (dispatched to " + aTarget._description + ")";
       function dispatchKeyEvent(aKeyCode, aChar, aTarget)
       {
-        var keyEvent = document.createEvent("KeyEvents");
+        var keyEvent = document.createEvent("KeyboardEvent");
         keyEvent.initKeyEvent("keypress", true, true, null, false, false,
                                false, false, aKeyCode,
                                aChar ? aChar.charCodeAt(0) : 0);
         aTarget.dispatchEvent(keyEvent);
       }
 
       function checkValueForDispatchedKeyEvent(aElement, aInsertedText)
       {
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -285,25 +285,21 @@ APZEventState::ProcessTouchEvent(const W
   bool sentContentResponse = false;
   APZES_LOG("Handling event type %d\n", aEvent.mMessage);
   switch (aEvent.mMessage) {
   case eTouchStart: {
     mTouchEndCancelled = false;
     sentContentResponse = SendPendingTouchPreventedResponse(false);
     // sentContentResponse can be true here if we get two TOUCH_STARTs in a row
     // and just responded to the first one.
-    if (!aEvent.mFlags.mHandledByAPZ) {
-      // This condition being true means this touchstart is synthetic and is
-      // coming from TabParent.injectTouchEvent.
-      // Since APZ doesn't know about it we don't want to send a response for
-      // this block; we want to just skip over it from the point of view of
-      // prevent-default notifications.
-      APZES_LOG("Got a synthetic touch-start!\n");
-      break;
-    }
+
+    // We're about to send a response back to APZ, but we should only do it
+    // for events that went through APZ (which should be all of them).
+    MOZ_ASSERT(aEvent.mFlags.mHandledByAPZ);
+
     if (isTouchPrevented) {
       mContentReceivedInputBlockCallback(aGuid, aInputBlockId, isTouchPrevented);
       sentContentResponse = true;
     } else {
       APZES_LOG("Event not prevented; pending response for %" PRIu64 " %s\n",
         aInputBlockId, Stringify(aGuid).c_str());
       mPendingTouchPreventedResponse = true;
       mPendingTouchPreventedGuid = aGuid;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1066,16 +1066,17 @@ CompositorBridgeParent::ResumeCompositio
     __android_log_print(ANDROID_LOG_INFO, "CompositorBridgeParent", "Unable to renew compositor surface; remaining in paused state");
 #endif
     lock.NotifyAll();
     return;
   }
 
   mPaused = false;
 
+  Invalidate();
   mCompositorScheduler->ResumeComposition();
 
   // if anyone's waiting to make sure that composition really got resumed, tell them
   lock.NotifyAll();
 }
 
 void
 CompositorBridgeParent::ForceComposition()
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -494,20 +494,21 @@ gfxPlatform::gfxPlatform()
     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
     mBidiNumeralOption = UNINITIALIZED_VALUE;
 
     mSkiaGlue = nullptr;
 
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
+    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
 #ifdef USE_SKIA
     canvasMask |= BackendTypeBit(BackendType::SKIA);
+    contentMask |= BackendTypeBit(BackendType::SKIA);
 #endif
-    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
                      contentMask, BackendType::CAIRO);
     mTotalSystemMemory = mozilla::hal::GetTotalSystemMemory();
 
     VRManager::ManagerInit();
 }
 
 gfxPlatform*
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -1207,22 +1207,16 @@ StopDiskSpaceWatcher()
 }
 
 uint32_t
 GetTotalSystemMemory()
 {
   return hal_impl::GetTotalSystemMemory();
 }
 
-uint32_t
-GetTotalSystemMemoryLevel()
-{
-  return hal_impl::GetTotalSystemMemoryLevel();
-}
-
 bool IsHeadphoneEventFromInputDev()
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(IsHeadphoneEventFromInputDev(), false);
 }
 
 nsresult StartSystemService(const char* aSvcName, const char* aArgs)
 {
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -623,24 +623,16 @@ void StopDiskSpaceWatcher();
 /**
  * Get total system memory of device being run on in bytes.
  *
  * Returns 0 if we are unable to determine this information from /proc/meminfo.
  */
 uint32_t GetTotalSystemMemory();
 
 /**
- * Get the level of total system memory on device in MiB.
- * (round the value up to the next power of two)
- *
- * Returns 0 if we are unable to determine this information from /proc/meminfo.
- */
-uint32_t GetTotalSystemMemoryLevel();
-
-/**
  * Determine whether the headphone switch event is from input device
  */
 bool IsHeadphoneEventFromInputDev();
 
 /**
  * Start the system service with the specified name and arguments.
  */
 nsresult StartSystemService(const char* aSvcName, const char* aArgs);
--- a/hal/fallback/FallbackMemory.cpp
+++ b/hal/fallback/FallbackMemory.cpp
@@ -11,16 +11,10 @@ namespace mozilla {
 namespace hal_impl {
 
 uint32_t
 GetTotalSystemMemory()
 {
 	return 0;
 }
 
-uint32_t
-GetTotalSystemMemoryLevel()
-{
-	return 0;
-}
-
 } // namespace hal_impl
 } // namespace mozilla
--- a/hal/linux/LinuxMemory.cpp
+++ b/hal/linux/LinuxMemory.cpp
@@ -30,42 +30,10 @@ GetTotalSystemMemory()
     if (fclose(fd) || rv != 1) {
       return 0;
     }
   }
 
   return sTotalMemory * 1024;
 }
 
-uint32_t
-GetTotalSystemMemoryLevel()
-{
-  static uint32_t sTotalMemoryLevel = 1;
-  uint32_t sTotalMemory;
-  static bool sTotalMemoryObtained = false;
-
-  if (!sTotalMemoryObtained) {
-    sTotalMemoryObtained = true;
-
-    FILE* fd = fopen("/proc/meminfo", "r");
-    if (!fd) {
-      return 0;
-    }
-
-    int rv = fscanf(fd, "MemTotal: %i kB", &sTotalMemory);
-
-    if (fclose(fd) || rv != 1) {
-      return 0;
-    }
-
-    // From KB to MiB
-    sTotalMemory /= 1024;
-
-    while (sTotalMemoryLevel <= sTotalMemory) {
-      sTotalMemoryLevel *= 2;
-    }
-  }
-
-  return sTotalMemoryLevel;
-}
-
 } // namespace hal_impl
 } // namespace mozilla
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -82,17 +82,17 @@ fuzzy(20,999) != downscale-2d.html?203,5
 fuzzy(20,999) != downscale-2e.html?203,52,bottom about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
 fuzzy(20,999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank
 
-fuzzy(63,3386) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
+fuzzy(63,3391) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
 
 == downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
 == downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
 
 # Non-transparent and transparent ICO images
 == downscale-16px.html?ff-0RGB.ico downscale-16px.html?ff-0RGB.png
 fuzzy(1,1) == downscale-16px.html?ff-ARGB.ico downscale-16px.html?ff-ARGB.png
 
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -782,17 +782,17 @@ struct JSClass {
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
 // the beginning of every global object's slots for use by the
 // application.
 #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
 #define JSCLASS_GLOBAL_SLOT_COUNT                                             \
-    (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 37)
+    (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
--- a/js/public/GCPolicyAPI.h
+++ b/js/public/GCPolicyAPI.h
@@ -139,18 +139,21 @@ struct GCPolicy<JS::Heap<T>>
 };
 
 // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>.
 template <typename T, typename D>
 struct GCPolicy<mozilla::UniquePtr<T, D>>
 {
     static mozilla::UniquePtr<T,D> initial() { return mozilla::UniquePtr<T,D>(); }
     static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) {
-        GCPolicy<T>::trace(trc, tp->get(), name);
+        if (tp->get())
+            GCPolicy<T>::trace(trc, tp->get(), name);
     }
     static bool needsSweep(mozilla::UniquePtr<T,D>* tp) {
-        return GCPolicy<T>::needsSweep(tp->get());
+        if (tp->get())
+            return GCPolicy<T>::needsSweep(tp->get());
+        return false;
     }
 };
 
 } // namespace JS
 
 #endif // GCPolicyAPI_h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -296,16 +296,17 @@ class TryFinallyControl : public Bytecod
         return emittingSubroutine_;
     }
 };
 
 static bool
 ScopeKindIsInBody(ScopeKind kind)
 {
     return kind == ScopeKind::Lexical ||
+           kind == ScopeKind::SimpleCatch ||
            kind == ScopeKind::Catch ||
            kind == ScopeKind::With ||
            kind == ScopeKind::FunctionBodyVar ||
            kind == ScopeKind::ParameterExpressionVar;
 }
 
 static inline void
 MarkAllBindingsClosedOver(LexicalScope::Data& data)
@@ -676,16 +677,17 @@ BytecodeEmitter::EmitterScope::searchInE
             }
             break;
 
           case ScopeKind::FunctionBodyVar:
           case ScopeKind::ParameterExpressionVar:
           case ScopeKind::Lexical:
           case ScopeKind::NamedLambda:
           case ScopeKind::StrictNamedLambda:
+          case ScopeKind::SimpleCatch:
           case ScopeKind::Catch:
             if (hasEnv) {
                 for (BindingIter bi(si.scope()); bi; bi++) {
                     if (bi.name() != name)
                         continue;
 
                     // The name must already have been marked as closed
                     // over. If this assertion is hit, there is a bug in the
@@ -1407,16 +1409,17 @@ BytecodeEmitter::EmitterScope::leave(Byt
 {
     // If we aren't leaving the scope due to a non-local jump (e.g., break),
     // we must be the innermost scope.
     MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
 
     ScopeKind kind = scope(bce)->kind();
     switch (kind) {
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
         if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
             return false;
         break;
 
       case ScopeKind::With:
         if (!bce->emit1(JSOP_LEAVEWITH))
             return false;
@@ -5659,32 +5662,37 @@ BytecodeEmitter::emitLexicalScope(ParseN
 
     // Update line number notes before emitting TDZ poison in
     // EmitterScope::enterLexical to avoid spurious pausing on seemingly
     // non-effectful lines in Debugger.
     //
     // For example, consider the following code.
     //
     // L1: {
-    // L2:  let x = 42;
+    // L2:   let x = 42;
     // L3: }
     //
     // If line number notes were not updated before the TDZ poison, the TDZ
     // poison bytecode sequence of 'uninitialized; initlexical' will have line
     // number L1, and the Debugger will pause there.
     if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
         ParseNode* pnForPos = body;
         if (body->isKind(PNK_STATEMENTLIST) && body->pn_head)
             pnForPos = body->pn_head;
         if (!updateLineNumberNotes(pnForPos->pn_pos.begin))
             return false;
     }
 
     EmitterScope emitterScope(this);
-    ScopeKind kind = body->isKind(PNK_CATCH) ? ScopeKind::Catch : ScopeKind::Lexical;
+    ScopeKind kind;
+    if (body->isKind(PNK_CATCH))
+        kind = body->pn_kid1->isKind(PNK_NAME) ? ScopeKind::SimpleCatch : ScopeKind::Catch;
+    else
+        kind = ScopeKind::Lexical;
+
     if (!emitterScope.enterLexical(this, kind, pn->scopeBindings()))
         return false;
 
     if (body->isKind(PNK_FOR)) {
         // for loops need to emit {FRESHEN,RECREATE}LEXICALENV if there are
         // lexical declarations in the head. Signal this by passing a
         // non-nullptr lexical scope.
         if (!emitFor(body, &emitterScope))
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -165,25 +165,57 @@ ParseContext::Scope::removeVarForAnnexBL
         }
     }
 
     // Annex B semantics no longer applies to any functions with this name, as
     // an early error would have occurred.
     pc->removeInnerFunctionBoxesForAnnexB(name);
 }
 
+static bool
+DeclarationKindIsCatchParameter(DeclarationKind kind)
+{
+    return kind == DeclarationKind::SimpleCatchParameter ||
+           kind == DeclarationKind::CatchParameter;
+}
+
+bool
+ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope)
+{
+    if (pc->useAsmOrInsideUseAsm())
+        return true;
+
+    for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
+        DeclarationKind kind = r.front().value()->kind();
+        MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
+        JSAtom* name = r.front().key();
+        AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
+        MOZ_ASSERT(!p);
+        if (!addDeclaredName(pc, p, name, kind))
+            return false;
+    }
+
+    return true;
+}
+
 void
-ParseContext::Scope::removeSimpleCatchParameter(ParseContext* pc, JSAtom* name)
+ParseContext::Scope::removeCatchParameters(ParseContext* pc, Scope& catchParamScope)
 {
     if (pc->useAsmOrInsideUseAsm())
         return;
 
-    DeclaredNamePtr p = declared_->lookup(name);
-    MOZ_ASSERT(p && p->value()->kind() == DeclarationKind::SimpleCatchParameter);
-    declared_->remove(p);
+    for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) {
+        DeclaredNamePtr p = declared_->lookup(r.front().key());
+        MOZ_ASSERT(p);
+
+        // This check is needed because the catch body could have declared
+        // vars, which would have been added to catchParamScope.
+        if (DeclarationKindIsCatchParameter(r.front().value()->kind()))
+            declared_->remove(p);
+    }
 }
 
 void
 SharedContext::computeAllowSyntax(Scope* scope)
 {
     for (ScopeIter si(scope); si; si++) {
         if (si.kind() == ScopeKind::Function) {
             JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
@@ -916,16 +948,70 @@ static bool
 DeclarationKindIsVar(DeclarationKind kind)
 {
     return kind == DeclarationKind::Var ||
            kind == DeclarationKind::BodyLevelFunction ||
            kind == DeclarationKind::VarForAnnexBLexicalFunction ||
            kind == DeclarationKind::ForOfVar;
 }
 
+template <typename ParseHandler>
+Maybe<DeclarationKind>
+Parser<ParseHandler>::isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind)
+{
+    MOZ_ASSERT(DeclarationKindIsVar(kind));
+    MOZ_ASSERT(pc->sc()->isEvalContext());
+
+    // In the case of eval, we also need to check enclosing VM scopes to see
+    // if the var declaration is allowed in the context.
+    //
+    // This check is necessary in addition to
+    // js::CheckEvalDeclarationConflicts because we only know during parsing
+    // if a var is bound by for-of.
+    Scope* enclosingScope = pc->sc()->compilationEnclosingScope();
+    Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
+    MOZ_ASSERT(varScope);
+    for (ScopeIter si(enclosingScope); si; si++) {
+        for (js::BindingIter bi(si.scope()); bi; bi++) {
+            if (bi.name() != name)
+                continue;
+
+            switch (bi.kind()) {
+              case BindingKind::Let: {
+                  // Annex B.3.5 allows redeclaring simple (non-destructured)
+                  // catch parameters with var declarations, except when it
+                  // appears in a for-of.
+                  bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch &&
+                                           kind != DeclarationKind::ForOfVar;
+                  if (!annexB35Allowance) {
+                      return Some(ScopeKindIsCatch(si.kind())
+                                  ? DeclarationKind::CatchParameter
+                                  : DeclarationKind::Let);
+                  }
+                  break;
+              }
+
+              case BindingKind::Const:
+                return Some(DeclarationKind::Const);
+
+              case BindingKind::Import:
+              case BindingKind::FormalParameter:
+              case BindingKind::Var:
+              case BindingKind::NamedLambdaCallee:
+                break;
+            }
+        }
+
+        if (si.scope() == varScope)
+            break;
+    }
+
+    return Nothing();
+}
+
 static bool
 DeclarationKindIsParameter(DeclarationKind kind)
 {
     return kind == DeclarationKind::PositionalFormalParameter ||
            kind == DeclarationKind::FormalParameter;
 }
 
 template <typename ParseHandler>
@@ -971,68 +1057,31 @@ Parser<ParseHandler>::tryDeclareVar(Hand
                 }
             }
         } else {
             if (!scope->addDeclaredName(pc, p, name, kind))
                 return false;
         }
     }
 
+    if (!pc->sc()->strict() && pc->sc()->isEvalContext())
+        *redeclaredKind = isVarRedeclaredInEval(name, kind);
+
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name,
                                                             bool* tryAnnexB)
 {
     Maybe<DeclarationKind> redeclaredKind;
     if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind))
         return false;
 
-    // In the case of eval, we also need to check enclosing VM scopes to see
-    // if an Annex B var should be synthesized.
-    if (!redeclaredKind && pc->sc()->isEvalContext()) {
-        Scope* enclosingScope = pc->sc()->compilationEnclosingScope();
-        Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
-        MOZ_ASSERT(varScope);
-        for (ScopeIter si(enclosingScope); si; si++) {
-            for (js::BindingIter bi(si.scope()); bi; bi++) {
-                if (bi.name() != name)
-                    continue;
-
-                switch (bi.kind()) {
-                  case BindingKind::Let: {
-                    // Annex B.3.5 allows redeclaring simple (non-destructured)
-                    // catch parameters with var declarations, except when it
-                    // appears in a for-of, which a function declaration is
-                    // definitely not.
-                    bool annexB35Allowance = si.kind() == ScopeKind::Catch;
-                    if (!annexB35Allowance)
-                        redeclaredKind = Some(DeclarationKind::Let);
-                    break;
-                  }
-
-                  case BindingKind::Const:
-                    redeclaredKind = Some(DeclarationKind::Const);
-                    break;
-
-                  case BindingKind::Import:
-                  case BindingKind::FormalParameter:
-                  case BindingKind::Var:
-                  case BindingKind::NamedLambdaCallee:
-                    break;
-                }
-            }
-
-            if (si.scope() == varScope)
-                break;
-        }
-    }
-
     if (redeclaredKind) {
         // If an early error would have occurred, undo all the
         // VarForAnnexBLexicalFunction declarations.
         *tryAnnexB = false;
         ParseContext::Scope::removeVarForAnnexBLexicalFunction(pc, name);
     } else {
         *tryAnnexB = true;
     }
@@ -2699,17 +2748,17 @@ Parser<ParseHandler>::functionArguments(
     }
 
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
-                                              bool *tryAnnexB)
+                                              GeneratorKind generatorKind, bool* tryAnnexB)
 {
     if (kind == Statement) {
         TokenPos pos = handler.getPosition(pn);
         RootedPropertyName funName(context, funAtom->asPropertyName());
 
         // In sloppy mode, Annex B.3.2 allows labelled function
         // declarations. Otherwise it is a parse error.
         ParseContext::Statement* declaredInStmt = pc->innermostStatement();
@@ -2728,17 +2777,17 @@ Parser<ParseHandler>::checkFunctionDefin
                 return false;
             }
         }
 
         if (declaredInStmt) {
             MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
             MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
 
-            if (!pc->sc()->strict()) {
+            if (!pc->sc()->strict() && generatorKind == NotGenerator) {
                 // Under sloppy mode, try Annex B.3.3 semantics. If making an
                 // additional 'var' binding of the same name does not throw an
                 // early error, do so. This 'var' binding would be assigned
                 // the function object when its declaration is reached, not at
                 // the start of the block.
 
                 if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB))
                     return false;
@@ -2888,17 +2937,17 @@ Parser<ParseHandler>::functionDefinition
     if (!pn)
         return null();
 
     if (invoked)
         pn = handler.setLikelyIIFE(pn);
 
     // Note the declared name and check for early errors.
     bool tryAnnexB = false;
-    if (!checkFunctionDefinition(funName, pn, kind, &tryAnnexB))
+    if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB))
         return null();
 
     // When fully parsing a LazyScript, we do not fully reparse its inner
     // functions, which are also lazy. Instead, their free variables and
     // source extents are recorded and may be skipped.
     if (handler.canSkipLazyInnerFunctions()) {
         if (!skipLazyInnerFunction(pn, tryAnnexB))
             return null();
@@ -5969,18 +6018,16 @@ Parser<ParseHandler>::tryStatement(Yield
              * Legal catch forms are:
              *   catch (lhs)
              *   catch (lhs if <boolean_expression>)
              * where lhs is a name or a destructuring left-hand side.
              * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
              */
             MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
 
-            RootedPropertyName simpleCatchParam(context);
-
             if (!tokenStream.getToken(&tt))
                 return null();
             Node catchName;
             switch (tt) {
               case TOK_LB:
               case TOK_LC:
                 catchName = destructuringDeclaration(DeclarationKind::CatchParameter,
                                                      yieldHandling, tt);
@@ -5993,27 +6040,25 @@ Parser<ParseHandler>::tryStatement(Yield
                     return null();
                 }
 
                 // Even if yield is *not* necessarily a keyword, we still must
                 // check its validity for legacy generators.
                 if (!checkYieldNameValidity())
                     return null();
                 MOZ_FALLTHROUGH;
-              case TOK_NAME:
-                simpleCatchParam = tokenStream.currentName();
-                catchName = newName(simpleCatchParam);
+              case TOK_NAME: {
+                RootedPropertyName param(context, tokenStream.currentName());
+                catchName = newName(param);
                 if (!catchName)
                     return null();
-                if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter,
-                                      pos()))
-                {
+                if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos()))
                     return null();
-                }
                 break;
+              }
 
               default:
                 report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER);
                 return null();
             }
 
             Node catchGuard = null();
 #if JS_HAS_CATCH_GUARD
@@ -6030,17 +6075,17 @@ Parser<ParseHandler>::tryStatement(Yield
                 if (!catchGuard)
                     return null();
             }
 #endif
             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
 
             MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
 
-            Node catchBody = catchBlockStatement(yieldHandling, simpleCatchParam);
+            Node catchBody = catchBlockStatement(yieldHandling, scope);
             if (!catchBody)
                 return null();
 
             if (!catchGuard)
                 hasUnconditionalCatch = true;
 
             pnblock = finishLexicalScope(scope, catchBody);
             if (!pnblock)
@@ -6084,53 +6129,43 @@ Parser<ParseHandler>::tryStatement(Yield
     }
 
     return handler.newTryStatement(begin, innerBlock, catchList, finallyBlock);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
-                                          HandlePropertyName simpleCatchParam)
+                                          ParseContext::Scope& catchParamScope)
 {
     ParseContext::Statement stmt(pc, StatementKind::Block);
 
-    // Annex B.3.5 requires that vars be allowed to redeclare a simple
-    // (non-destructured) catch parameter (including via a direct eval), so
-    // the catch parameter needs to live in its own scope. So if we have a
-    // simple catch parameter, make a new scope.
-    Node body;
-    if (simpleCatchParam) {
-        ParseContext::Scope scope(this);
-        if (!scope.init(pc))
-            return null();
-
-        // The catch parameter name cannot be redeclared inside the catch
-        // block, so declare the name in the inner scope.
-        if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, pos()))
-            return null();
-
-        Node list = statementList(yieldHandling);
-        if (!list)
-            return null();
-
-        // The catch parameter name is not bound in this scope, so remove it
-        // before generating bindings.
-        scope.removeSimpleCatchParameter(pc, simpleCatchParam);
-
-        body = finishLexicalScope(scope, list);
-    } else {
-        body = statementList(yieldHandling);
-    }
-    if (!body)
+    // ES 13.15.7 CatchClauseEvaluation
+    //
+    // Step 8 means that the body of a catch block always has an additional
+    // lexical scope.
+    ParseContext::Scope scope(this);
+    if (!scope.init(pc))
+        return null();
+
+    // The catch parameter names cannot be redeclared inside the catch
+    // block, so declare the name in the inner scope.
+    if (!scope.addCatchParameters(pc, catchParamScope))
+        return null();
+
+    Node list = statementList(yieldHandling);
+    if (!list)
         return null();
 
     MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH);
 
-    return body;
+    // The catch parameter names are not bound in the body scope, so remove
+    // them before generating bindings.
+    scope.removeCatchParameters(pc, catchParamScope);
+    return finishLexicalScope(scope, list);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::debuggerStatement()
 {
     TokenPos p;
     p.begin = pos().begin;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -149,19 +149,20 @@ class ParseContext : public Nestable<Par
         {
             return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind)));
         }
 
         // Remove all VarForAnnexBLexicalFunction declarations of a certain
         // name from all scopes in pc's scope stack.
         static void removeVarForAnnexBLexicalFunction(ParseContext* pc, JSAtom* name);
 
-        // Remove a simple catch parameter name. Used to implement the odd
-        // semantics of Annex B.3.5.
-        void removeSimpleCatchParameter(ParseContext* pc, JSAtom* name);
+        // Add and remove catch parameter names. Used to implement the odd
+        // semantics of catch bodies.
+        bool addCatchParameters(ParseContext* pc, Scope& catchParamScope);
+        void removeCatchParameters(ParseContext* pc, Scope& catchParamScope);
 
         void useAsVarScope(ParseContext* pc) {
             MOZ_ASSERT(!pc->varScope_);
             pc->varScope_ = this;
         }
 
         // An iterator for the set of names a scope binds: the set of all
         // declared names for 'var' scopes, and the set of lexically declared
@@ -1037,17 +1038,17 @@ class Parser final : private JS::AutoGCR
 
     Node switchStatement(YieldHandling yieldHandling);
     Node continueStatement(YieldHandling yieldHandling);
     Node breakStatement(YieldHandling yieldHandling);
     Node returnStatement(YieldHandling yieldHandling);
     Node withStatement(YieldHandling yieldHandling);
     Node throwStatement(YieldHandling yieldHandling);
     Node tryStatement(YieldHandling yieldHandling);
-    Node catchBlockStatement(YieldHandling yieldHandling, HandlePropertyName simpleCatchParam);
+    Node catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope);
     Node debuggerStatement();
 
     Node variableStatement(YieldHandling yieldHandling);
 
     Node labeledStatement(YieldHandling yieldHandling);
     Node labeledItem(YieldHandling yieldHandling);
 
     Node ifStatement(YieldHandling yieldHandling);
@@ -1234,17 +1235,17 @@ class Parser final : private JS::AutoGCR
     bool declareFunctionArgumentsObject();
     bool declareFunctionThis();
     Node newInternalDotName(HandlePropertyName name);
     Node newThisName();
     Node newDotGeneratorName();
     bool declareDotGeneratorName();
 
     bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
-                                 bool *tryAnnexB);
+                                 GeneratorKind generatorKind, bool* tryAnnexB);
     bool skipLazyInnerFunction(Node pn, bool tryAnnexB);
     bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
                        InHandling inHandling, FunctionSyntaxKind kind,
                        GeneratorKind generatorKind, bool tryAnnexB,
                        Directives inheritedDirectives, Directives* newDirectives);
     bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
                                      FunctionSyntaxKind kind, GeneratorKind generatorKind,
                                      bool tryAnnexB, Directives inheritedDirectives,
@@ -1270,16 +1271,18 @@ class Parser final : private JS::AutoGCR
     bool checkStrictAssignment(Node lhs);
     bool checkStrictBinding(PropertyName* name, TokenPos pos);
 
     void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
     bool notePositionalFormalParameter(Node fn, HandlePropertyName name,
                                        bool disallowDuplicateParams = false,
                                        bool* duplicatedParam = nullptr);
     bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct);
+    mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
+                                                          DeclarationKind kind);
     bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
                        mozilla::Maybe<DeclarationKind>* redeclaredKind);
     bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB);
     bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
                                                     DeclarationKind kind, TokenPos pos);
     bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
     bool noteUsedName(HandlePropertyName name);
     bool hasUsedName(HandlePropertyName name);
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1272,16 +1272,17 @@ Scope::traceChildren(JSTracer* trc)
       case ScopeKind::Function:
         reinterpret_cast<FunctionScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::FunctionBodyVar:
       case ScopeKind::ParameterExpressionVar:
         reinterpret_cast<VarScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda:
         reinterpret_cast<LexicalScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic:
         reinterpret_cast<GlobalScope::Data*>(data_)->trace(trc);
@@ -1319,16 +1320,17 @@ js::GCMarker::eagerlyMarkChildren(Scope*
       case ScopeKind::ParameterExpressionVar: {
         VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_);
         names = data->names;
         length = data->length;
         break;
       }
 
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda: {
         LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_);
         names = data->names;
         length = data->length;
         break;
       }
deleted file mode 100644
--- a/js/src/jit-test/tests/jaeger/bug601400.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// |jit-test| error: TypeError
-
-eval("\
-    function NaN() {}\
-    for(w in s) {}\
-")
-
-// Don't assert.
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -647,17 +647,17 @@ class InlineFrameIterator
 
     struct Nop {
         void operator()(const Value& v) { }
     };
 
   private:
     void findNextFrame();
     JSObject* computeEnvironmentChain(Value envChainValue, MaybeReadFallback& fallback,
-                                      bool* hasCallObj = nullptr) const;
+                                      bool* hasInitialEnv = nullptr) const;
 
   public:
     InlineFrameIterator(JSContext* cx, const JitFrameIterator* iter);
     InlineFrameIterator(JSRuntime* rt, const JitFrameIterator* iter);
     InlineFrameIterator(JSContext* cx, const InlineFrameIterator* iter);
 
     bool more() const {
         return frame_ && framesRead_ < frameCount_;
@@ -689,27 +689,27 @@ class InlineFrameIterator
         if (more())
             return numActualArgs_;
 
         return frame_->numActualArgs();
     }
 
     template <class ArgOp, class LocalOp>
     void readFrameArgsAndLocals(JSContext* cx, ArgOp& argOp, LocalOp& localOp,
-                                JSObject** envChain, bool* hasCallObj,
+                                JSObject** envChain, bool* hasInitialEnv,
                                 Value* rval, ArgumentsObject** argsObj, Value* thisv,
                                 ReadFrameArgsBehavior behavior,
                                 MaybeReadFallback& fallback) const
     {
         SnapshotIterator s(si_);
 
         // Read the env chain.
         if (envChain) {
             Value envChainValue = s.maybeRead(fallback);
-            *envChain = computeEnvironmentChain(envChainValue, fallback, hasCallObj);
+            *envChain = computeEnvironmentChain(envChainValue, fallback, hasInitialEnv);
         } else {
             s.skip();
         }
 
         // Read return value.
         if (rval)
             *rval = s.maybeRead(fallback);
         else
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -2392,27 +2392,29 @@ InlineFrameIterator::callee(MaybeReadFal
     SnapshotIterator s(si_);
     // :TODO: Handle allocation failures from recover instruction.
     Value funval = s.maybeRead(calleeRVA_, fallback);
     return &funval.toObject().as<JSFunction>();
 }
 
 JSObject*
 InlineFrameIterator::computeEnvironmentChain(Value envChainValue, MaybeReadFallback& fallback,
-                                             bool* hasCallObj) const
+                                             bool* hasInitialEnv) const
 {
     if (envChainValue.isObject()) {
-        if (hasCallObj) {
+        if (hasInitialEnv) {
             if (fallback.canRecoverResults()) {
                 RootedObject obj(fallback.maybeCx, &envChainValue.toObject());
-                *hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject();
+                *hasInitialEnv = isFunctionFrame() &&
+                                 callee(fallback)->needsFunctionEnvironmentObjects();
                 return obj;
             } else {
                 JS::AutoSuppressGCAnalysis nogc; // If we cannot recover then we cannot GC.
-                *hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject();
+                *hasInitialEnv = isFunctionFrame() &&
+                                 callee(fallback)->needsFunctionEnvironmentObjects();
             }
         }
 
         return &envChainValue.toObject();
     }
 
     // Note we can hit this case even for functions with a CallObject, in case
     // we are walking the frame during the function prologue, before the env
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1664,37 +1664,16 @@ JSObject::swap(JSContext* cx, HandleObje
     return true;
 }
 
 static bool
 DefineStandardSlot(JSContext* cx, HandleObject obj, JSProtoKey key, JSAtom* atom,
                    HandleValue v, uint32_t attrs, bool& named)
 {
     RootedId id(cx, AtomToId(atom));
-
-    if (key != JSProto_Null) {
-        /*
-         * Initializing an actual standard class on a global object. If the
-         * property is not yet present, force it into a new one bound to a
-         * reserved slot. Otherwise, go through the normal property path.
-         */
-        Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-
-        if (!global->lookup(cx, id)) {
-            global->setConstructorPropertySlot(key, v);
-
-            uint32_t slot = GlobalObject::constructorPropertySlot(key);
-            if (!NativeObject::addProperty(cx, global, id, nullptr, nullptr, slot, attrs, 0))
-                return false;
-
-            named = true;
-            return true;
-        }
-    }
-
     named = DefineProperty(cx, obj, id, v, nullptr, nullptr, attrs);
     return named;
 }
 
 static void
 SetClassObject(JSObject* obj, JSProtoKey key, JSObject* cobj, JSObject* proto)
 {
     if (!obj->is<GlobalObject>())
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -706,16 +706,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
                     return false;
                 break;
               case ScopeKind::FunctionBodyVar:
               case ScopeKind::ParameterExpressionVar:
                 if (!VarScope::XDR(xdr, scopeKind, enclosing, &scope))
                     return false;
                 break;
               case ScopeKind::Lexical:
+              case ScopeKind::SimpleCatch:
               case ScopeKind::Catch:
               case ScopeKind::NamedLambda:
               case ScopeKind::StrictNamedLambda:
                 if (!LexicalScope::XDR(xdr, scopeKind, enclosing, &scope))
                     return false;
                 break;
               case ScopeKind::With:
                 if (mode == XDR_DECODE) {
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-generators.js
@@ -0,0 +1,26 @@
+// Tests by André Bargull <andrebargull@googlemail.com>
+
+// Annex B.3.3.1
+function f1() {
+    { function* g() {} }
+    assertEq(typeof g, "undefined");
+}
+f1();
+
+// Annex B.3.3.2
+{ function* g() {} }
+assertEq(typeof g, "undefined");
+
+// Annex B.3.3.3
+function f2() {
+    eval("{ function* g() {} }");
+    assertEq(typeof g, "undefined");
+}
+f2();
+
+// Annex B.3.3.3
+eval("{ function* g() {} }");
+assertEq(typeof g, "undefined");
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/LexicalEnvironment/catch-body.js
@@ -0,0 +1,19 @@
+function f() {
+  var probeParam, probeBlock;
+  let x = 'outside';
+
+  try {
+    throw [];
+  } catch ([_ = probeParam = function() { return x; }]) {
+    probeBlock = function() { return x; };
+    let x = 'inside';
+  }
+
+  assertEq(probeBlock(), 'inside');
+  assertEq(probeParam(), 'outside');
+}
+
+f();
+
+if (typeof reportCompare === 'function')
+  reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/LexicalEnvironment/var-in-catch-body-annex-b-eval-destructuring.js
@@ -0,0 +1,10 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+assertThrowsInstanceOf(() => evaluate(`try { throw {} } catch ({e}) { var e; }`), SyntaxError);
+assertThrowsInstanceOf(() => evaluate(`try { throw {} } catch ({e}) { eval('var e'); }`), SyntaxError);
+
+assertThrowsInstanceOf(() => new Function(`try { throw {} } catch ({e}) { var e; }`), SyntaxError);
+assertThrowsInstanceOf(new Function(`try { throw {} } catch ({e}) { eval('var e'); }`), SyntaxError);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/LexicalEnvironment/var-in-catch-body-annex-b-eval-for-of.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+assertThrowsInstanceOf(() => evaluate(`
+    try { throw null; } catch (e) { eval("for (var e of []) {}") }
+`), SyntaxError);
+
+assertThrowsInstanceOf(new Function(`
+    try { throw null; } catch (e) { eval("for (var e of []) {}") }
+`), SyntaxError);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -546,24 +546,24 @@ class js::WasmArrayRawBuffer
         MOZ_RELEASE_ASSERT(newMax.isValid());
         MOZ_RELEASE_ASSERT(newMax.value() % wasm::PageSize == 0);
 
         size_t newMapped = wasm::LegalizeMapLength(newMax.value());
 
 # ifdef XP_WIN
         if (!VirtualAlloc(dataPointer(), newMapped, MEM_RESERVE, PAGE_NOACCESS))
             return;
-# elif defined(XP_DARWIN)
+# elif defined(XP_LINUX)
+        // Note this will not move memory (no MREMAP_MAYMOVE specified)
+        if (MAP_FAILED == mremap(dataPointer(), mappedSize_, newMapped, 0))
+            return;
+# else
         // No mechanism for remapping on MaxOS. Luckily shouldn't need it here
         // as most MacOS configs are 64 bit
         return;
-#else // Unix
-        // Note this will not move memory (no MREMAP_MAYMOVE specified)
-        if (MAP_FAILED == mremap(dataPointer(), mappedSize_, newMapped, 0))
-            return;
 # endif  // !XP_WIN
 
         mappedSize_ = newMapped;
         maxSize_ = Some(newMax.value());
         return;
     }
 };
 
--- a/js/src/vm/Debugger-inl.h
+++ b/js/src/vm/Debugger-inl.h
@@ -96,9 +96,23 @@ js::DebuggerFrame::owner() const
 
 inline js::Debugger*
 js::DebuggerObject::owner() const
 {
     JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
     return Debugger::fromJSObject(dbgobj);
 }
 
+inline js::PromiseObject*
+js::DebuggerObject::promise() const
+{
+    MOZ_ASSERT(isPromise());
+
+    JSObject* referent = this->referent();
+    if (IsCrossCompartmentWrapper(referent)) {
+        referent = CheckedUnwrap(referent);
+        MOZ_ASSERT(referent);
+    }
+
+    return &referent->as<PromiseObject>();
+}
+
 #endif /* vm_Debugger_inl_h */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -15,17 +15,16 @@
 #include "jsfriendapi.h"
 #include "jshashutil.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jswrapper.h"
 
 #include "asmjs/WasmInstance.h"
-#include "builtin/Promise.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/Parser.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
 #include "js/Date.h"
 #include "js/GCAPI.h"
@@ -745,17 +744,17 @@ Debugger::getScriptFrameWithIter(JSConte
 
     FrameMap::AddPtr p = frames.lookupForAdd(referent);
     if (!p) {
         /* Create and populate the Debugger.Frame object. */
         RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_FRAME_PROTO).toObject());
         RootedNativeObject debugger(cx, object);
 
         RootedDebuggerFrame frame(cx, DebuggerFrame::create(cx, proto, referent, maybeIter,
-                                                               debugger));
+                                                            debugger));
         if (!frame)
             return false;
 
         if (!ensureExecutionObservabilityOfFrame(cx, referent))
             return false;
 
         if (!frames.add(p, referent, frame)) {
             ReportOutOfMemory(cx);
@@ -6184,56 +6183,84 @@ Debugger::observesScript(JSScript* scrip
 }
 
 /* static */ bool
 Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to,
                            ScriptFrameIter& iter)
 {
     auto removeFromDebuggerFramesOnExit = MakeScopeExit([&] {
         // Remove any remaining old entries on exit, as the 'from' frame will
-        // be gone. On success, the range will be empty.
-        Debugger::forEachDebuggerFrame(from, [&](NativeObject* frameobj) {
-            frameobj->setPrivate(nullptr);
-            Debugger::fromChildJSObject(frameobj)->frames.remove(from);
-        });
+        // be gone. This is only done in the failure case. On failure, the
+        // removeToDebuggerFramesOnExit lambda below will rollback any frames
+        // that were replaced, resulting in !frameMaps(to). On success, the
+        // range will be empty, as all from Frame.Debugger instances will have
+        // been removed.
+        MOZ_ASSERT_IF(inFrameMaps(to), !inFrameMaps(from));
+        removeFromFrameMapsAndClearBreakpointsIn(cx, from);
 
         // Rekey missingScopes to maintain Debugger.Environment identity and
         // forward liveScopes to point to the new frame.
         DebugEnvironments::forwardLiveFrame(cx, from, to);
     });
 
     // Forward live Debugger.Frame objects.
     Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx));
-    if (!getDebuggerFrames(from, &frames))
-        return false;
+    if (!getDebuggerFrames(from, &frames)) {
+        // An OOM here means that all Debuggers' frame maps still contain
+        // entries for 'from' and no entries for 'to'. Since the 'from' frame
+        // will be gone, they are removed by removeFromDebuggerFramesOnExit
+        // above.
+        return false;
+    }
 
     // If during the loop below we hit an OOM, we must also rollback any of
     // the frames that were successfully replaced. For OSR frames, OOM here
     // means those frames will pop from the OSR trampoline, which does not
     // call Debugger::onLeaveFrame.
     auto removeToDebuggerFramesOnExit = MakeScopeExit([&] {
         removeFromFrameMapsAndClearBreakpointsIn(cx, to);
     });
 
     for (size_t i = 0; i < frames.length(); i++) {
         HandleDebuggerFrame frameobj = frames[i];
         Debugger* dbg = Debugger::fromChildJSObject(frameobj);
 
         // Update frame object's ScriptFrameIter::data pointer.
         DebuggerFrame_freeScriptFrameIterData(cx->runtime()->defaultFreeOp(), frameobj);
         ScriptFrameIter::Data* data = iter.copyData();
-        if (!data)
-            return false;
+        if (!data) {
+            // An OOM here means that some Debuggers' frame maps may still
+            // contain entries for 'from' and some Debuggers' frame maps may
+            // also contain entries for 'to'. Thus both
+            // removeFromDebuggerFramesOnExit and
+            // removeToDebuggerFramesOnExit must both run.
+            //
+            // The current frameobj in question is still in its Debugger's
+            // frame map keyed by 'from', so it will be covered by
+            // removeFromDebuggerFramesOnExit.
+            return false;
+        }
         frameobj->setPrivate(data);
 
         // Remove old frame.
         dbg->frames.remove(from);
 
         // Add the frame object with |to| as key.
         if (!dbg->frames.putNew(to, frameobj)) {
+            // This OOM is subtle. At this point, both
+            // removeFromDebuggerFramesOnExit and removeToDebuggerFramesOnExit
+            // must both run for the same reason given above.
+            //
+            // The difference is that the current frameobj is no longer in its
+            // Debugger's frame map, so it will not be cleaned up by neither
+            // lambda. Manually clean it up here.
+            FreeOp* fop = cx->runtime()->defaultFreeOp();
+            DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
+            DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, to, frameobj);
+
             ReportOutOfMemory(cx);
             return false;
         }
     }
 
     // All frames successfuly replaced, cancel the rollback.
     removeToDebuggerFramesOnExit.release();
 
@@ -8597,31 +8624,30 @@ DebuggerObject::proxyHandlerGetter(JSCon
 }
 
 #ifdef SPIDERMONKEY_PROMISE
 /* static */ bool
 DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT(cx, argc, vp, "get isPromise", args, object)
 
-    bool result;
-    if (!DebuggerObject::getIsPromise(cx, object, result))
-      return false;
-
-    args.rval().setBoolean(result);
+    args.rval().setBoolean(object->isPromise());
     return true;
 }
 
 /* static */ bool
 DebuggerObject::promiseStateGetter(JSContext* cx, unsigned argc, Value* vp)
 {
-    THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseState", args, refobj);
+    THIS_DEBUGOBJECT(cx, argc, vp, "get promiseState", args, object);
+
+    if (!DebuggerObject::requirePromise(cx, object))
+        return false;
 
     RootedValue result(cx);
-    switch (promise->state()) {
+    switch (object->promiseState()) {
       case JS::PromiseState::Pending:
         result.setString(cx->names().pending);
         break;
       case JS::PromiseState::Fulfilled:
         result.setString(cx->names().fulfilled);
         break;
       case JS::PromiseState::Rejected:
         result.setString(cx->names().rejected);
@@ -8630,47 +8656,43 @@ DebuggerObject::promiseStateGetter(JSCon
 
     args.rval().set(result);
     return true;
 }
 
 /* static */ bool
 DebuggerObject::promiseValueGetter(JSContext* cx, unsigned argc, Value* vp)
 {
-    THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseValue", args, dbg, refobj);
-
-    if (promise->state() != JS::PromiseState::Fulfilled) {
+    THIS_DEBUGOBJECT(cx, argc, vp, "get promiseValue", args, object);
+
+    if (!DebuggerObject::requirePromise(cx, object))
+        return false;
+
+    if (object->promiseState() != JS::PromiseState::Fulfilled) {
         args.rval().setUndefined();
         return true;
     }
 
-    RootedValue result(cx, promise->value());
-    if (!dbg->wrapDebuggeeValue(cx, &result))
-        return false;
-
-    args.rval().set(result);
-    return true;
+    return DebuggerObject::getPromiseValue(cx, object, args.rval());;
 }
 
 /* static */ bool
 DebuggerObject::promiseReasonGetter(JSContext* cx, unsigned argc, Value* vp)
 {
-    THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseReason", args, dbg, refobj);
-
-    if (promise->state() != JS::PromiseState::Rejected) {
+    THIS_DEBUGOBJECT(cx, argc, vp, "get promiseReason", args, object);
+
+    if (!DebuggerObject::requirePromise(cx, object))
+        return false;
+
+    if (object->promiseState() != JS::PromiseState::Rejected) {
         args.rval().setUndefined();
         return true;
     }
 
-    RootedValue result(cx, promise->reason());
-    if (!dbg->wrapDebuggeeValue(cx, &result))
-        return false;
-
-    args.rval().set(result);
-    return true;
+    return DebuggerObject::getPromiseReason(cx, object, args.rval());;
 }
 
 /* static */ bool
 DebuggerObject::promiseLifetimeGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseLifetime", args, refobj);
 
     args.rval().setNumber(promise->lifetime());
@@ -9320,32 +9342,28 @@ DebuggerObject::isGlobal() const
 
 bool
 DebuggerObject::isScriptedProxy() const
 {
     return js::IsScriptedProxy(referent());
 }
 
 #ifdef SPIDERMONKEY_PROMISE
-/* static */ bool
-DebuggerObject::getIsPromise(JSContext* cx, HandleDebuggerObject object,
-                          bool& result)
-{
-    JSObject* referent = object->referent();
+bool
+DebuggerObject::isPromise() const
+{
+    JSObject* referent = this->referent();
+
     if (IsCrossCompartmentWrapper(referent)) {
         referent = CheckedUnwrap(referent);
-
-        if (!referent) {
-            JS_ReportError(cx, "Permission denied to access object");
-            return false;
-        }
-      }
-
-    result = referent->is<PromiseObject>();
-    return true;
+        if (!referent)
+            return false;
+    }
+
+    return referent->is<PromiseObject>();
 }
 #endif // SPIDERMONKEY_PROMISE
 
 /* static */ bool
 DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
                              MutableHandleString result)
 {
     RootedObject referent(cx, object->referent());
@@ -9386,16 +9404,22 @@ DebuggerObject::name() const
 JSAtom*
 DebuggerObject::displayName() const
 {
     MOZ_ASSERT(isFunction());
 
     return referent()->as<JSFunction>().displayAtom();
 }
 
+JS::PromiseState
+DebuggerObject::promiseState() const
+{
+    return promise()->state();
+}
+
 /* static */ bool
 DebuggerObject::getParameterNames(JSContext* cx, HandleDebuggerObject object,
                                   MutableHandle<StringVector> result)
 {
     MOZ_ASSERT(object->isDebuggeeFunction());
 
     RootedFunction referent(cx, &object->referent()->as<JSFunction>());
 
@@ -9525,16 +9549,38 @@ DebuggerObject::getErrorMessageName(JSCo
             }
         }
     }
 
     result.set(nullptr);
     return true;
 }
 
+#ifdef SPIDERMONKEY_PROMISE
+/* static */ bool
+DebuggerObject::getPromiseValue(JSContext* cx, HandleDebuggerObject object,
+                                MutableHandleValue result)
+{
+    MOZ_ASSERT(object->promiseState() == JS::PromiseState::Fulfilled);
+
+    result.set(object->promise()->value());
+    return object->owner()->wrapDebuggeeValue(cx, result);
+}
+
+/* static */ bool
+DebuggerObject::getPromiseReason(JSContext* cx, HandleDebuggerObject object,
+                                 MutableHandleValue result)
+{
+    MOZ_ASSERT(object->promiseState() == JS::PromiseState::Rejected);
+
+    result.set(object->promise()->reason());
+    return object->owner()->wrapDebuggeeValue(cx, result);
+}
+#endif // SPIDERMONKEY_PROMISE
+
 /* static */ bool
 DebuggerObject::isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result)
 {
     RootedObject referent(cx, object->referent());
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, referent);
     ErrorCopier ec(ac);
@@ -9994,16 +10040,40 @@ DebuggerObject::requireGlobal(JSContext*
                                   "a global object", nullptr);
         }
         return false;
     }
 
     return true;
 }
 
+#ifdef SPIDERMONKEY_PROMISE
+/* static */ bool
+DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
+{
+   RootedObject referent(cx, object->referent());
+
+   if (IsCrossCompartmentWrapper(referent)) {
+       referent = CheckedUnwrap(referent);
+       if (!referent) {
+           JS_ReportError(cx, "Permission denied to access object");
+           return false;
+       }
+   }
+
+   if (!referent->is<PromiseObject>()) {
+      JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+                           "Debugger", "Promise", object->getClass()->name);
+      return false;
+   }
+
+   return true;
+}
+#endif // SPIDERMONKEY_PROMISE
+
 /* static */ bool
 DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
                                        MutableHandleDebuggerObject result)
 {
     MOZ_ASSERT(object->isScriptedProxy());
     RootedObject referent(cx, object->referent());
     Debugger* dbg = object->owner();
     RootedObject unwrapped(cx, js::GetProxyTargetObject(referent));
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -14,16 +14,17 @@
 
 #include "jsclist.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 
 #include "asmjs/WasmJS.h"
+#include "builtin/Promise.h"
 #include "ds/TraceableFifo.h"
 #include "gc/Barrier.h"
 #include "js/Debug.h"
 #include "js/GCVariant.h"
 #include "js/HashTable.h"
 #include "vm/GlobalObject.h"
 #include "vm/SavedStacks.h"
 
@@ -1252,18 +1253,20 @@ class DebuggerObject : public NativeObje
                                             MutableHandleObject result);
     static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object,
                                                  MutableHandleString result);
     static MOZ_MUST_USE bool getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
                                                     MutableHandleDebuggerObject result);
     static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
                                                      MutableHandleDebuggerObject result);
 #ifdef SPIDERMONKEY_PROMISE
-    static MOZ_MUST_USE bool getIsPromise(JSContext* cx, HandleDebuggerObject object,
-                                          bool& result);
+    static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object,
+                                             MutableHandleValue result);
+    static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object,
+                                              MutableHandleValue result);
 #endif // SPIDERMONKEY_PROMISE
 
     // Methods
     static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
                                           bool& result);
     static MOZ_MUST_USE bool isSealed(JSContext* cx, HandleDebuggerObject object, bool& result);
     static MOZ_MUST_USE bool isFrozen(JSContext* cx, HandleDebuggerObject object, bool& result);
     static MOZ_MUST_USE bool getPrototypeOf(JSContext* cx, HandleDebuggerObject object,
@@ -1304,18 +1307,24 @@ class DebuggerObject : public NativeObje
     // Infallible properties
     bool isCallable() const;
     bool isFunction() const;
     bool isDebuggeeFunction() const;
     bool isBoundFunction() const;
     bool isArrowFunction() const;
     bool isGlobal() const;
     bool isScriptedProxy() const;
+#ifdef SPIDERMONKEY_PROMISE
+    bool isPromise() const;
+#endif // SPIDERMONKEY_PROMISE
     JSAtom* name() const;
     JSAtom* displayName() const;
+#ifdef SPIDERMONKEY_PROMISE
+    JS::PromiseState promiseState() const;
+#endif // SPIDERMONKEY_PROMISE
 
   private:
     enum {
         OWNER_SLOT
     };
 
     static const unsigned RESERVED_SLOTS = 1;
 
@@ -1330,18 +1339,25 @@ class DebuggerObject : public NativeObje
     JSObject* referent() const {
         JSObject* obj = (JSObject*) getPrivate();
         MOZ_ASSERT(obj);
         return obj;
     }
 
     Debugger* owner() const;
 
+#ifdef SPIDERMONKEY_PROMISE
+    PromiseObject* promise() const;
+#endif // SPIDERMONKEY_PROMISE
+
     static DebuggerObject* checkThis(JSContext* cx, const CallArgs& args, const char* fnname);
     static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object);
+#ifdef SPIDERMONKEY_PROMISE
+    static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object);
+#endif // SPIDERMONKEY_PROMISE
 
     static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
 
     // JSNative properties
     static MOZ_MUST_USE bool callableGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool protoGetter(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -3224,19 +3224,21 @@ CheckVarNameConflictsInEnv(JSContext* cx
                obj->as<DebugEnvironmentProxy>().environment().is<LexicalEnvironmentObject>())
     {
         env = &obj->as<DebugEnvironmentProxy>().environment().as<LexicalEnvironmentObject>();
     } else {
         // Environment cannot contain lexical bindings.
         return true;
     }
 
-    if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::Catch) {
-        // Annex B.3.5 says 'var' declarations with the same name as catch
-        // parameters are allowed.
+    if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::SimpleCatch) {
+        // Annex B.3.5 allows redeclaring simple (non-destructured) catch
+        // parameters with var declarations, except when it appears in a
+        // for-of. The for-of allowance is computed in
+        // Parser::isVarRedeclaredInEval.
         return true;
     }
 
     RootedPropertyName name(cx);
     for (BindingIter bi(script); bi; bi++) {
         name = bi.name()->asPropertyName();
         if (!CheckVarNameConflict(cx, env, name))
             return false;
@@ -3244,18 +3246,16 @@ CheckVarNameConflictsInEnv(JSContext* cx
 
     return true;
 }
 
 bool
 js::CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script,
                                   HandleObject scopeChain, HandleObject varObj)
 {
-    // We don't need to check body-level lexical bindings for conflict. Eval
-    // scripts always execute under their own lexical scope.
     if (!script->bodyScope()->as<EvalScope>().hasBindings())
         return true;
 
     RootedObject obj(cx, scopeChain);
 
     // ES6 18.2.1.2 step d
     //
     // Check that a direct eval will not hoist 'var' bindings over lexical
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -215,22 +215,22 @@ GlobalObject::resolveConstructor(JSConte
     // Create the constructor.
     RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
     if (!ctor)
         return false;
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
     if (isObjectOrFunction) {
         if (clasp->specShouldDefineConstructor()) {
-            if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
+            RootedValue ctorValue(cx, ObjectValue(*ctor));
+            if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
                 return false;
         }
 
         global->setConstructor(key, ObjectValue(*ctor));
-        global->setConstructorPropertySlot(key, ObjectValue(*ctor));
     }
 
     // Define any specified functions and properties, unless we're a dependent
     // standard class (in which case they live on the prototype), or we're
     // operating on the self-hosting global, in which case we don't want any
     // functions and properties on the builtins and their prototypes.
     if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
         if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
@@ -262,56 +262,48 @@ GlobalObject::resolveConstructor(JSConte
     }
 
     if (!isObjectOrFunction) {
         // Any operations that modifies the global object should be placed
         // after any other fallible operations.
 
         // Fallible operation that modifies the global object.
         if (clasp->specShouldDefineConstructor()) {
-            if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
+            RootedValue ctorValue(cx, ObjectValue(*ctor));
+            if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
                 return false;
         }
 
         // Infallible operations that modify the global object.
         global->setConstructor(key, ObjectValue(*ctor));
-        global->setConstructorPropertySlot(key, ObjectValue(*ctor));
         if (proto)
             global->setPrototype(key, ObjectValue(*proto));
     }
 
-    if (clasp->specShouldDefineConstructor()) {
-        // Stash type information, so that what we do here is equivalent to
-        // initBuiltinConstructor.
-        AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
-    }
-
     return true;
 }
 
 /* static */ bool
 GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
                                      JSProtoKey key, HandleObject ctor, HandleObject proto)
 {
     MOZ_ASSERT(!global->empty()); // reserved slots already allocated
     MOZ_ASSERT(key != JSProto_Null);
     MOZ_ASSERT(ctor);
     MOZ_ASSERT(proto);
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
     MOZ_ASSERT(!global->lookup(cx, id));
 
-    if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
+    RootedValue ctorValue(cx, ObjectValue(*ctor));
+    if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
         return false;
 
     global->setConstructor(key, ObjectValue(*ctor));
     global->setPrototype(key, ObjectValue(*proto));
-    global->setConstructorPropertySlot(key, ObjectValue(*ctor));
-
-    AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
     return true;
 }
 
 GlobalObject*
 GlobalObject::createInternal(JSContext* cx, const Class* clasp)
 {
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
     MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -41,43 +41,39 @@ enum class SimdType;
  *   are traced for GC purposes. Apart from that the engine never touches
  *   these slots, so the embedding can do whatever it wants with them.
  * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT)
  *   Stores the original value of the constructor for the corresponding
  *   JSProtoKey.
  * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT)
  *   Stores the prototype, if any, for the constructor for the corresponding
  *   JSProtoKey offset from JSProto_LIMIT.
- * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, APPLICATION_SLOTS + 3 * JSProto_LIMIT)
- *   Stores the current value of the global property named for the JSProtoKey
- *   for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT.
- * [APPLICATION_SLOTS + 3 * JSProto_LIMIT, RESERVED_SLOTS)
+ * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, RESERVED_SLOTS)
  *   Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
  *   the original eval for this global object (implementing |var eval =
  *   otherWindow.eval; eval(...)| as an indirect eval), a bit indicating
  *   whether this object has been cleared (see JS_ClearScope), and a cache for
  *   whether eval is allowed (per the global's Content Security Policy).
  *
- * The first two JSProto_LIMIT-sized ranges are necessary to implement
+ * The two JSProto_LIMIT-sized ranges are necessary to implement
  * js::FindClassObject, and spec language speaking in terms of "the original
  * Array prototype object", or "as if by the expression new Array()" referring
- * to the original Array constructor. The third range stores the (writable and
- * even deletable) Object, Array, &c. properties (although a slot won't be used
- * again if its property is deleted and readded).
+ * to the original Array constructor. The actual (writable and even deletable)
+ * Object, Array, &c. properties are not stored in reserved slots.
  */
 class GlobalObject : public NativeObject
 {
     /* Count of slots set aside for application use. */
     static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS;
 
     /*
-     * Count of slots to store built-in constructors, prototypes, and initial
-     * visible properties for the constructors.
+     * Count of slots to store built-in prototypes and initial visible
+     * properties for the constructors.
      */
-    static const unsigned STANDARD_CLASS_SLOTS  = JSProto_LIMIT * 3;
+    static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 2;
 
     enum : unsigned {
         /* Various function values needed by the engine. */
         EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS,
         CREATE_DATAVIEW_FOR_THIS,
         THROWTYPEERROR,
 
         /*
@@ -179,29 +175,16 @@ class GlobalObject : public NativeObject
         return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key);
     }
 
     void setPrototype(JSProtoKey key, const Value& value) {
         MOZ_ASSERT(key <= JSProto_LIMIT);
         setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value);
     }
 
-    static uint32_t constructorPropertySlot(JSProtoKey key) {
-        MOZ_ASSERT(key <= JSProto_LIMIT);
-        return APPLICATION_SLOTS + JSProto_LIMIT * 2 + key;
-    }
-
-    Value getConstructorPropertySlot(JSProtoKey key) {
-        return getSlot(constructorPropertySlot(key));
-    }
-
-    void setConstructorPropertySlot(JSProtoKey key, const Value& ctor) {
-        setSlot(constructorPropertySlot(key), ctor);
-    }
-
     bool classIsInitialized(JSProtoKey key) const {
         bool inited = !getConstructor(key).isUndefined();
         MOZ_ASSERT(inited == !getPrototype(key).isUndefined());
         return inited;
     }
 
     bool functionObjectClassesInitialized() const {
         bool inited = classIsInitialized(JSProto_Function);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -979,17 +979,20 @@ js::EnterWithOperation(JSContext* cx, Ab
     return true;
 }
 
 static void
 PopEnvironment(JSContext* cx, EnvironmentIter& ei)
 {
     switch (ei.scope().kind()) {
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
+      case ScopeKind::NamedLambda:
+      case ScopeKind::StrictNamedLambda:
         if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
             DebugEnvironments::onPopLexical(cx, ei);
         if (ei.scope().hasEnvironment())
             ei.initialFrame().popOffEnvironmentChain<LexicalEnvironmentObject>();
         break;
       case ScopeKind::With:
         if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
             DebugEnvironments::onPopWith(ei.initialFrame());
@@ -1005,18 +1008,16 @@ PopEnvironment(JSContext* cx, Environmen
       case ScopeKind::ParameterExpressionVar:
       case ScopeKind::StrictEval:
         if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
             DebugEnvironments::onPopVar(cx, ei);
         if (ei.scope().hasEnvironment())
             ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
         break;
       case ScopeKind::Eval:
-      case ScopeKind::NamedLambda:
-      case ScopeKind::StrictNamedLambda:
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic:
       case ScopeKind::Module:
         break;
     }
 }
 
 // Unwind environment chain and iterator to match the env corresponding to
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -51,16 +51,17 @@ js::ScopeKindString(ScopeKind kind)
       case ScopeKind::Function:
         return "function";
       case ScopeKind::FunctionBodyVar:
         return "function body var";
       case ScopeKind::ParameterExpressionVar:
         return "parameter expression var";
       case ScopeKind::Lexical:
         return "lexical";
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
         return "catch";
       case ScopeKind::NamedLambda:
         return "named lambda";
       case ScopeKind::StrictNamedLambda:
         return "strict named lambda";
       case ScopeKind::With:
         return "with";
@@ -269,16 +270,33 @@ Scope::XDRSizedBindingNames(XDRState<mod
 Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
 {
     Scope* scope = Allocate<Scope>(cx);
     if (scope)
         new (scope) Scope(kind, enclosing, envShape);
     return scope;
 }
 
+template <typename T, typename D>
+/* static */ Scope*
+Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
+              HandleShape envShape, mozilla::UniquePtr<T, D> data)
+{
+    Scope* scope = create(cx, kind, enclosing, envShape);
+    if (!scope)
+        return nullptr;
+
+    // It is an invariant that all Scopes that have data (currently, all
+    // ScopeKinds except With) must have non-null data.
+    MOZ_ASSERT(data);
+    scope->initData(Move(data));
+
+    return scope;
+}
+
 uint32_t
 Scope::chainLength() const
 {
     uint32_t length = 0;
     for (ScopeIter si(const_cast<Scope*>(this)); si; si++)
         length++;
     return length;
 }
@@ -313,71 +331,65 @@ Scope::clone(JSContext* cx, HandleScope 
 {
     RootedShape envShape(cx);
     if (scope->environmentShape()) {
         envShape = scope->maybeCloneEnvironmentShape(cx);
         if (!envShape)
             return nullptr;
     }
 
-    Scope* scopeClone = create(cx, scope->kind_, enclosing, envShape);
-    if (!scopeClone)
-        return nullptr;
-
     switch (scope->kind_) {
       case ScopeKind::Function:
         MOZ_CRASH("Use FunctionScope::clone.");
         break;
 
       case ScopeKind::FunctionBodyVar:
       case ScopeKind::ParameterExpressionVar: {
         Rooted<VarScope::Data*> original(cx, &scope->as<VarScope>().data());
         UniquePtr<VarScope::Data> dataClone = CopyScopeData<VarScope>(cx, original);
         if (!dataClone)
             return nullptr;
-        scopeClone->initData(Move(dataClone));
-        break;
+        return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
       }
 
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda: {
         Rooted<LexicalScope::Data*> original(cx, &scope->as<LexicalScope>().data());
         UniquePtr<LexicalScope::Data> dataClone = CopyScopeData<LexicalScope>(cx, original);
         if (!dataClone)
             return nullptr;
-        scopeClone->initData(Move(dataClone));
-        break;
+        return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
       }
 
       case ScopeKind::With:
-        break;
+        return create(cx, scope->kind_, enclosing, envShape);
 
       case ScopeKind::Eval:
       case ScopeKind::StrictEval: {
         Rooted<EvalScope::Data*> original(cx, &scope->as<EvalScope>().data());
         UniquePtr<EvalScope::Data> dataClone = CopyScopeData<EvalScope>(cx, original);
         if (!dataClone)
             return nullptr;
-        scopeClone->initData(Move(dataClone));
-        break;
+        return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
       }
 
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic:
         MOZ_CRASH("Use GlobalScope::clone.");
         break;
 
       case ScopeKind::Module:
         MOZ_CRASH("NYI");
         break;
     }
 
-    return scopeClone;
+    return nullptr;
 }
 
 void
 Scope::finalize(FreeOp* fop)
 {
     if (data_) {
         fop->free_(reinterpret_cast<void*>(data_));
         data_ = 0;
@@ -403,16 +415,17 @@ Scope::dump()
     fprintf(stderr, "\n");
 }
 
 uint32_t
 LexicalScope::firstFrameSlot() const
 {
     switch (kind()) {
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
         // For intra-frame scopes, find the enclosing scope's next frame slot.
         return nextFrameSlot(enclosing());
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda:
         // Named lambda scopes cannot have frame slots.
         return LOCALNO_LIMIT;
       default:
@@ -428,16 +441,17 @@ LexicalScope::nextFrameSlot(Scope* scope
     for (ScopeIter si(scope); si; si++) {
         switch (si.kind()) {
           case ScopeKind::Function:
             return si.scope()->as<FunctionScope>().nextFrameSlot();
           case ScopeKind::FunctionBodyVar:
           case ScopeKind::ParameterExpressionVar:
             return si.scope()->as<VarScope>().nextFrameSlot();
           case ScopeKind::Lexical:
+          case ScopeKind::SimpleCatch:
           case ScopeKind::Catch:
             return si.scope()->as<LexicalScope>().nextFrameSlot();
           case ScopeKind::NamedLambda:
           case ScopeKind::StrictNamedLambda:
             // Named lambda scopes cannot have frame slots.
             return 0;
           case ScopeKind::With:
             continue;
@@ -472,25 +486,21 @@ LexicalScope::create(ExclusiveContext* c
     Rooted<UniquePtr<Data>> copy(cx,
         CopyScopeData<LexicalScope>(cx, bi, data,
                                     &LexicalEnvironmentObject::class_,
                                     BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE,
                                     &envShape));
     if (!copy)
         return nullptr;
 
-    Scope* scope = Scope::create(cx, kind, enclosing, envShape);
+    Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(copy.get()));
     if (!scope)
         return nullptr;
-
     MOZ_ASSERT(scope->as<LexicalScope>().firstFrameSlot() == firstFrameSlot);
-
-    LexicalScope* lexicalScope = &scope->as<LexicalScope>();
-    lexicalScope->initData(Move(copy.get()));
-    return lexicalScope;
+    return &scope->as<LexicalScope>();
 }
 
 /* static */ Shape*
 LexicalScope::getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx)
 {
     const Class* cls = &LexicalEnvironmentObject::class_;
     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), BaseShape::DELEGATE);
 }
@@ -769,23 +779,20 @@ VarScope::create(ExclusiveContext* cx, S
     //   - Extensible scopes (i.e., due to direct eval)
     //   - Being a generator
     if (!envShape && needsEnvironment) {
         envShape = getEmptyEnvironmentShape(cx);
         if (!envShape)
             return nullptr;
     }
 
-    Scope* scope = Scope::create(cx, kind, enclosing, envShape);
+    Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(copy.get()));
     if (!scope)
         return nullptr;
-
-    VarScope* varScope = &scope->as<VarScope>();
-    varScope->initData(Move(copy.get()));
-    return varScope;
+    return &scope->as<VarScope>();
 }
 
 /* static */ Shape*
 VarScope::getEmptyEnvironmentShape(ExclusiveContext* cx)
 {
     const Class* cls = &VarEnvironmentObject::class_;
     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), VarScopeEnvShapeFlags);
 }
@@ -875,40 +882,34 @@ GlobalScope::copyData(ExclusiveContext *
 GlobalScope::create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data)
 {
     // The data that's passed in may be from the frontend and LifoAlloc'd.
     // Copy it now that we're creating a permanent VM scope.
     Rooted<UniquePtr<Data>> copy(cx, copyData(cx, data));
     if (!copy)
         return nullptr;
 
-    Scope* scope = Scope::create(cx, kind, nullptr, nullptr);
+    Scope* scope = Scope::create(cx, kind, nullptr, nullptr, Move(copy.get()));
     if (!scope)
         return nullptr;
-
-    GlobalScope* globalScope = &scope->as<GlobalScope>();
-    globalScope->initData(Move(copy.get()));
-    return globalScope;
+    return &scope->as<GlobalScope>();
 }
 
 /* static */ GlobalScope*
 GlobalScope::clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind)
 {
     Rooted<Data*> dataOriginal(cx, &scope->as<GlobalScope>().data());
     Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<GlobalScope>(cx, dataOriginal));
     if (!dataClone)
         return nullptr;
 
-    Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr);
+    Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr, Move(dataClone.get()));
     if (!scopeClone)
         return nullptr;
-
-    GlobalScope* globalScopeClone = &scopeClone->as<GlobalScope>();
-    globalScopeClone->initData(Move(dataClone.get()));
-    return globalScopeClone;
+    return &scopeClone->as<GlobalScope>();
 }
 
 template <XDRMode mode>
 /* static */ bool
 GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
 {
     MOZ_ASSERT((mode == XDR_DECODE) == !scope);
 
@@ -993,23 +994,20 @@ EvalScope::create(ExclusiveContext* cx, 
     // Strict eval and direct eval in parameter expressions always get their own
     // var environment even if there are no bindings.
     if (!envShape && scopeKind == ScopeKind::StrictEval) {
         envShape = getEmptyEnvironmentShape(cx);
         if (!envShape)
             return nullptr;
     }
 
-    Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape);
+    Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape, Move(copy.get()));
     if (!scope)
         return nullptr;
-
-    EvalScope* evalScope = &scope->as<EvalScope>();
-    evalScope->initData(Move(copy.get()));
-    return evalScope;
+    return &scope->as<EvalScope>();
 }
 
 /* static */ Scope*
 EvalScope::nearestVarScopeForDirectEval(Scope* scope)
 {
     for (ScopeIter si(scope); si; si++) {
         switch (si.kind()) {
           case ScopeKind::Function:
@@ -1150,16 +1148,17 @@ ScopeIter::hasSyntacticEnvironment() con
 {
     return scope()->hasEnvironment() && scope()->kind() != ScopeKind::NonSyntactic;
 }
 
 BindingIter::BindingIter(Scope* scope)
 {
     switch (scope->kind()) {
       case ScopeKind::Lexical:
+      case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
         init(scope->as<LexicalScope>().data(),
              scope->as<LexicalScope>().firstFrameSlot(), 0);
         break;
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda:
         init(scope->as<LexicalScope>().data(), LOCALNO_LIMIT, IsNamedLambda);
         break;
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -48,16 +48,17 @@ enum class ScopeKind : uint8_t
     Function,
 
     // VarScope
     FunctionBodyVar,
     ParameterExpressionVar,
 
     // LexicalScope
     Lexical,
+    SimpleCatch,
     Catch,
     NamedLambda,
     StrictNamedLambda,
 
     // WithScope
     With,
 
     // EvalScope
@@ -67,16 +68,22 @@ enum class ScopeKind : uint8_t
     // GlobalScope
     Global,
     NonSyntactic,
 
     // ModuleScope
     Module
 };
 
+static inline bool
+ScopeKindIsCatch(ScopeKind kind)
+{
+    return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
+}
+
 const char* BindingKindString(BindingKind kind);
 const char* ScopeKindString(ScopeKind kind);
 
 class BindingName
 {
     // A JSAtom* with its low bit used as a tag for whether it is closed over
     // (i.e., exists in the environment shape).
     uintptr_t bits_;
@@ -200,16 +207,20 @@ class Scope : public js::gc::TenuredCell
         enclosing_(enclosing),
         environmentShape_(environmentShape),
         data_(0)
     { }
 
     static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
                          HandleShape envShape);
 
+    template <typename T, typename D>
+    static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
+                         HandleShape envShape, mozilla::UniquePtr<T, D> data);
+
     template <typename ConcreteScope, XDRMode mode>
     static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
                                      MutableHandle<typename ConcreteScope::Data*> data);
 
     Shape* maybeCloneEnvironmentShape(JSContext* cx);
 
     template <typename T, typename D>
     void initData(mozilla::UniquePtr<T, D> data) {
@@ -293,16 +304,19 @@ class Scope : public js::gc::TenuredCell
 
 //
 // A lexical scope that holds let and const bindings. There are 4 kinds of
 // LexicalScopes.
 //
 // Lexical
 //   A plain lexical scope.
 //
+// SimpleCatch
+//   Holds the single catch parameter of a catch block.
+//
 // Catch
 //   Holds the catch parameters (and only the catch parameters) of a catch
 //   block.
 //
 // NamedLambda
 // StrictNamedLambda
 //   Holds the single name of the callee for a named lambda expression.
 //
@@ -371,16 +385,17 @@ class LexicalScope : public Scope
     static Shape* getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx);
 };
 
 template <>
 inline bool
 Scope::is<LexicalScope>() const
 {
     return kind_ == ScopeKind::Lexical ||
+           kind_ == ScopeKind::SimpleCatch ||
            kind_ == ScopeKind::Catch ||
            kind_ == ScopeKind::NamedLambda ||
            kind_ == ScopeKind::StrictNamedLambda;
 }
 
 //
 // Scope corresponding to a function. Holds formal parameter names and, if the
 // function parameters contain no expressions that might possibly be
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -120,16 +120,17 @@ AssertScopeMatchesEnvironment(Scope* sco
 
               case ScopeKind::FunctionBodyVar:
               case ScopeKind::ParameterExpressionVar:
                 MOZ_ASSERT(&env->as<VarEnvironmentObject>().scope() == si.scope());
                 env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
                 break;
 
               case ScopeKind::Lexical:
+              case ScopeKind::SimpleCatch:
               case ScopeKind::Catch:
               case ScopeKind::NamedLambda:
               case ScopeKind::StrictNamedLambda:
                 MOZ_ASSERT(&env->as<LexicalEnvironmentObject>().scope() == si.scope());
                 env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment();
                 break;
 
               case ScopeKind::With:
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -275,27 +275,31 @@ ServoRestyleManager::NoteRestyleHint(Ele
   }
 }
 
 void
 ServoRestyleManager::ProcessPendingRestyles()
 {
   MOZ_ASSERT(PresContext()->Document(), "No document?  Pshaw!");
   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
+
+  if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) {
+    // PresShell::FlushPendingNotifications doesn't early-return in the case
+    // where the PreShell hasn't yet been initialized (and therefore we haven't
+    // yet done the initial style traversal of the DOM tree). We should arguably
+    // fix up the callers and assert against this case, but we just detect and
+    // handle it for now.
+    return;
+  }
+
   if (!HasPendingRestyles()) {
     return;
   }
 
   ServoStyleSet* styleSet = StyleSet();
-  if (!styleSet->StylingStarted()) {
-    // If something caused us to restyle, and we haven't started styling yet,
-    // do nothing. Everything is dirty, and we'll style it all later.
-    return;
-  }
-
   nsIDocument* doc = PresContext()->Document();
   Element* root = doc->GetRootElement();
   if (root) {
     for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) {
       ServoElementSnapshot* snapshot = iter.UserData();
       Element* element = iter.Key();
 
       // TODO: avoid the ComputeRestyleHint call if we already have the highest
@@ -326,17 +330,17 @@ ServoRestyleManager::ProcessPendingResty
       RecreateStyleContexts(root, nullptr, styleSet, changeList);
       ProcessRestyledFrames(changeList);
 
       mInStyleRefresh = false;
     }
   }
 
   MOZ_ASSERT(!doc->IsDirtyForServo());
-  MOZ_ASSERT(!doc->HasDirtyDescendantsForServo());
+  doc->UnsetHasDirtyDescendantsForServo();
 
   mModifiedElements.Clear();
 
   IncrementRestyleGeneration();
 }
 
 void
 ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
@@ -349,16 +353,30 @@ ServoRestyleManager::RestyleForInsertOrC
   //
   // Bug 1297899 tracks this work.
   //
 }
 
 void
 ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild)
 {
+  if (aContainer == aContainer->OwnerDoc()) {
+    // If we're getting this notification for the insertion of a root element,
+    // that means either:
+    //   (a) We initialized the PresShell before the root element existed, or
+    //   (b) The root element was removed and it or another root is being
+    //       inserted.
+    //
+    // Either way the whole tree is dirty, so we should style the document.
+    MOZ_ASSERT(aChild == aChild->OwnerDoc()->GetRootElement());
+    MOZ_ASSERT(aChild->IsDirtyForServo());
+    StyleSet()->StyleDocument(/* aLeaveDirtyBits = */ false);
+    return;
+  }
+
   if (!aContainer->ServoData().get()) {
     // This can happen with display:none. Bug 1297249 tracks more investigation
     // and assertions here.
     return;
   }
 
   // Style the new subtree because we will most likely need it during subsequent
   // frame construction. Bug 1298281 tracks deferring this work in the lazy
--- a/layout/base/TouchManager.cpp
+++ b/layout/base/TouchManager.cpp
@@ -228,17 +228,17 @@ TouchManager::PreHandleEvent(WidgetEvent
 
         int32_t id = touch->Identifier();
         TouchInfo info;
         if (!sCaptureTouchList->Get(id, &info)) {
           continue;
         }
         nsCOMPtr<EventTarget> targetPtr = info.mTouch->mTarget;
         nsCOMPtr<nsINode> targetNode(do_QueryInterface(targetPtr));
-        if (!targetNode->IsInComposedDoc()) {
+        if (targetNode && !targetNode->IsInComposedDoc()) {
           targetPtr = do_QueryInterface(info.mNonAnonymousTarget);
         }
 
         aCurrentEventContent = do_QueryInterface(targetPtr);
         touch->SetTarget(targetPtr);
         sCaptureTouchList->Remove(id);
       }
       // add any touches left in the touch list, but ensure changed=false
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2497,18 +2497,19 @@ nsPresContext::HasCachedStyleData()
 {
   if (!mShell) {
     return false;
   }
 
   nsStyleSet* styleSet = mShell->StyleSet()->GetAsGecko();
   if (!styleSet) {
     // XXXheycam ServoStyleSets do not use the rule tree, so just assume for now
-    // that we need to restyle when e.g. dppx changes.
-    return true;
+    // that we need to restyle when e.g. dppx changes assuming we're sufficiently
+    // bootstrapped.
+    return mShell->DidInitialize();
   }
 
   return styleSet->HasCachedStyleData();
 }
 
 already_AddRefed<nsITimer>
 nsPresContext::CreateTimer(nsTimerCallbackFunc aCallback,
                            uint32_t aDelay)
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1677,18 +1677,25 @@ PresShell::Initialize(nscoord aWidth, ns
   }
 #endif
 
   // XXX Do a full invalidate at the beginning so that invalidates along
   // the way don't have region accumulation issues?
 
   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
 
-  if (mStyleSet->IsServo()) {
-    mStyleSet->AsServo()->StartStyling(GetPresContext());
+  if (mStyleSet->IsServo() && mDocument->GetRootElement()) {
+    // If we have the root element already, go ahead style it along with any
+    // descendants.
+    //
+    // Some things, like nsDocumentViewer::GetPageMode, recreate the PresShell
+    // while keeping the content tree alive (see bug 1292280) - so we
+    // unconditionally mark the root as dirty.
+    mDocument->GetRootElement()->SetIsDirtyForServo();
+    mStyleSet->AsServo()->StyleDocument(/* aLeaveDirtyBits = */ false);
   }
 
   // Get the root frame from the frame manager
   // XXXbz it would be nice to move this somewhere else... like frame manager
   // Init(), say.  But we need to make sure our views are all set up by the
   // time we do this!
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
--- a/layout/base/tests/test_bug603550.html
+++ b/layout/base/tests/test_bug603550.html
@@ -53,21 +53,21 @@ function fireEvent(target, event) {
 }
 
 function fireDrop(element) {
   var ds = SpecialPowers.Cc["@mozilla.org/widget/dragservice;1"].
     getService(SpecialPowers.Ci.nsIDragService);
 
   ds.startDragSession();
 
-  var event = document.createEvent("DragEvents");
+  var event = document.createEvent("DragEvent");
   event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null);
   fireEvent(element, event);
 
-  event = document.createEvent("DragEvents");
+  event = document.createEvent("DragEvent");
   event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null);
   fireEvent(element, event);
 
   ds.endDragSession(false);
   ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!");
 }
 
 function runTest() {
--- a/layout/forms/test/test_bug477531.html
+++ b/layout/forms/test/test_bug477531.html
@@ -38,18 +38,18 @@ is(document.defaultView.getComputedStyle
 
 is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"),
    "30px",
    "Indeterminate checkbox should have a margin of 30px");
 
 $("s").setAttribute("type", "radio");
 
 is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"),
-   "10px",
-   "Only checkboxes should have indeterminate styles applied to them");
+   "30px",
+   "Setting an indeterminate element to type radio should give it indeterminate styles");
 
 $("s").setAttribute("type", "checkbox");
 
 is(document.defaultView.getComputedStyle($("s"), null).getPropertyValue("margin-left"),
    "30px",
    "Setting an indeterminate element to type checkbox should give it indeterminate styles");
 
 $("s").indeterminate = false;
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -29,17 +29,17 @@ skip-if(!asyncPan) == fixed-pos-scrollab
 skip-if(!asyncPan) == culling-1.html culling-1-ref.html
 skip-if(!asyncPan) == position-fixed-iframe-1.html position-fixed-iframe-1-ref.html
 skip-if(!asyncPan) == position-fixed-iframe-2.html position-fixed-iframe-2-ref.html
 fuzzy-if(skiaContent,1,11300) skip-if(!asyncPan) == position-fixed-in-scroll-container.html position-fixed-in-scroll-container-ref.html
 skip-if(!asyncPan) == position-fixed-inside-sticky-1.html position-fixed-inside-sticky-1-ref.html
 fuzzy(1,60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group-opacity-surface-size-1-ref.html
 skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html
 skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
-fuzzy-if(Android,6,4) fuzzy-if(skiaContent,1,34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
+fuzzy-if(Android,6,4) fuzzy-if(skiaContent&&!Android,1,34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html
 pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -41,17 +41,17 @@ fuzzy-if(asyncPan&&!layersGPUAccelerated
 == border-image-style-none-length.html border-image-style-none-length-ref.html
 == border-image-style-none-auto.html border-image-style-none-auto-ref.html
 
 # border images with gradients
 == border-image-linear-gradient.html border-image-linear-gradient-ref.html
 fuzzy(1,98) fuzzy-if(skiaContent,1,350) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
 fuzzy(1,149) fuzzy-if(OSX,1,10595) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
 fuzzy(1,433) fuzzy-if(skiaContent,1,2500) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html
-fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent,1,300) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
+fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent,1,400) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
 fuzzy(1,48)  fuzzy-if(OSX,5,1676) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html
 fuzzy(1,5000) fuzzy-if(OSX,1,15000) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html
 fuzzy(1,3000) fuzzy-if(OSX,1,6000) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html
 fuzzy(1,12) fuzzy-if(skiaContent,1,400) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html
 fuzzy(1,13) fuzzy-if(skiaContent,1,300) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html
 == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html
 fuzzy(1,576) fuzzy-if(skiaContent,1,2000) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html
 fuzzy(1,8533) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -47,17 +47,17 @@ fuzzy-if(true,1,20) fuzzy-if(d2d,64,196)
 fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,140) == clipping-4-image.html clipping-4-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,77) == clipping-4-overflow-hidden.html clipping-4-ref.html
 == clipping-5-canvas.html clipping-5-refc.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,77) == clipping-5-refi.html clipping-5-ref.html
 fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
 fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
-fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,16,27) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
+fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,19,29) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
 == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
 == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
 fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,250) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
 fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
 
 # Inheritance
@@ -66,17 +66,17 @@ fuzzy-if(true,1,33) fuzzy-if(d2d,48,350)
 # Table elements
 == table-collapse-1.html table-collapse-1-ref.html # border-radius is ignored on internal table elements
 # when border-collapse: collapse
 
 fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,116) == invalidate-1a.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(azureQuartz,1,3) skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,117) == invalidate-1b.html invalidate-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 
 # test that border-radius is reduced for scrollbars
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,12,12) fuzzy-if(browserIsRemote&&layersGPUAccelerated&&/^Windows\x20NT\x206\.1/.test(http.oscpu),12,12) fuzzy-if(skiaContent,1,50) fuzzy-if(gtkWidget&&layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,12,12) fuzzy-if(browserIsRemote&&layersGPUAccelerated&&/^Windows\x20NT\x206\.1/.test(http.oscpu),12,12) fuzzy-if(skiaContent&&!Android,1,50) fuzzy-if(gtkWidget&&layersGPUAccelerated,12,12) == scrollbar-clamping-1.html scrollbar-clamping-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) == scrollbar-clamping-2.html scrollbar-clamping-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 
 # Test for bad corner joins.
 fuzzy-if(true,1,1) == corner-joins-1.xhtml corner-joins-1-ref.xhtml
 fuzzy(255,20) skip-if(B2G||Mulet) random-if(winWidget) fuzzy-if(skiaContent,255,610) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop
 
 skip-if(B2G||Mulet) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(d2d,64,157) fuzzy-if(Android,166,400) fuzzy-if(skiaContent,64,70) == scroll-1.html scroll-1-ref.html # see bug 732535 #Bug 959166 # Initial mulet triage: parity with B2G/B2G Desktop
 
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -235,17 +235,17 @@ skip-if((B2G&&browserIsRemote)||Mulet) =
 == 234686-15.html 234686-ref.html
 == 234686-16.html 234686-ref.html
 == 234686-17.html 234686-ref.html
 == 234686-18.html 234686-ref.html
 == 234686-19.html 234686-ref.html
 skip-if(B2G||Mulet) == 234964-1.html 234964-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 234964-2.html 234964-2-ref.html
 == 235593-1.html 235593-1-ref.html
-== 236539-1.html 236539-1-ref.html
+fuzzy-if(skiaContent,4,2) == 236539-1.html 236539-1-ref.html
 == 240029-1.html 240029-1-ref.html
 == 240470-1.html 240470-1-ref.html
 skip-if(B2G||Mulet) == 240933-1.html 240933-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Android||B2G||Mulet) == 240933-2.html 240933-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 243266-1.html 243266-1-ref.html
 == 243302-1.html 243302-1-ref.html
 skip-if(B2G||Mulet||(Android&&asyncPan)) == 243519-1.html 243519-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 243519-2.html 243519-2-ref.html
@@ -456,17 +456,17 @@ fuzzy-if(skiaContent,2,3) == 339289-1.ht
 == 343538-1.html 343538-1-ref.html
 == 343540-1.html 343540-1-ref.html
 == 345267-1a.html 345267-1-ref.html
 == 345267-1b.html 345267-1-ref.html
 == 345267-1c.html 345267-1-ref.html
 == 345267-1d.html 345267-1-ref.html
 != 345563-sub.xhtml 345563-sup.xhtml
 skip-if((B2G&&browserIsRemote)||Mulet) == 346189-1.xul 346189-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
-== 346774-1a.html 346774-1-ref.html
+fuzzy-if(skiaContent,4,2) == 346774-1a.html 346774-1-ref.html
 == 346774-1b.html 346774-1-ref.html
 == 346774-1c.html 346774-1-ref.html
 == 347348-1.xhtml 347348-1-ref.xhtml
 == 347496-1.xhtml 347496-1-ref.xhtml
 == 347912-1.html 347912-1-ref.html
 skip-if((B2G&&browserIsRemote)||Mulet) == 348049-1.xhtml 348049-1-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop
 == 348516-1.html 348516-1-ref.html
 == 348516-2.html 348516-2-ref.html
@@ -653,17 +653,17 @@ skip-if(B2G||Mulet) == 372037-1.html 372
 == 372063-1.html 372063-1-ref.html
 == 372323-1.xhtml 372323-1-ref.xhtml
 == 372553-1.html 372553-1-ref.html
 == 372632-1.html 372632-1-ref.html
 == 372768-1.html 372768-1-ref.html
 == 373295-1.html 373295-1-ref.html
 == 373298-1.html 373298-1-ref.html
 skip-if(B2G||Mulet) fails-if(Android) == 373381-1.html 373381-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,40) == 373381-2.html 373381-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,40) == 373381-2.html 373381-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) random-if(d2d) == 373381-3.html 373381-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(Android) == 373381-4.html 373381-4-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 373383-1.html 373383-1-ref.html
 == 373433-1.html 373433-1-ref.html
 skip-if((B2G&&browserIsRemote)||Mulet) == 373533-1.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if((B2G&&browserIsRemote)||Mulet) == 373533-2.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if((B2G&&browserIsRemote)||Mulet) == 373533-3.xhtml about:blank # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if((B2G&&browserIsRemote)||Mulet) == 374038-1.xul 374038-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
@@ -799,17 +799,17 @@ fuzzy-if(skiaContent,1,600) == 393649-1.
 == 393655-2.html 393655-2-ref.html
 == 393655-3.html 393655-3-ref.html
 == 393655-4.html 393655-4-ref.html
 == 393655-5.html 393655-5-ref.html
 == 393671-1.html 393671-1-ref.html
 == 393671-2.html 393671-2-ref.html
 == 393671-3.html 393671-3-ref.html
 == 393760-1.xml 393760-1-ref.xml
-fuzzy-if(skiaContent,1,400) == 393760-2.xml 393760-2-ref.xml
+fuzzy-if(skiaContent,1,500) == 393760-2.xml 393760-2-ref.xml
 == 394111-1.html about:blank  # Really an assertion test rather than a rendering test
 == 394534-1.html 394534-1-ref.html
 skip-if((B2G&&browserIsRemote)||Mulet) == 394676-1.xhtml 394676-1-ref.xhtml # bug 975911 # Initial mulet triage: parity with B2G/B2G Desktop
 == 395107-1.html 395107-1-ref.html
 == 395107-2.html 395107-2-ref.html
 fuzzy-if(skiaContent,1,118) == 395107-3.html 395107-3-ref.html
 == 395107-4.html 395107-4-ref.html
 == 395107-5.html 395107-5-ref.html
@@ -1497,18 +1497,18 @@ skip-if(B2G||Mulet) fuzzy-if(Android,12,
 # the test is not currently relevant under harfbuzz shaping.
 # Keeping it here for the record, and because we may evolve HB's dotted-circle
 # behavior further in the future, which could make this become relevant again.
 # Marked "random" rather than "fails" because it may (spuriously) appear to pass
 # on B2G or Android devices that completely lack any Sinhala font support.
 random != 553571-1.html 553571-1-notref.html # expect dotted circle in test, not in ref: "fails" under harfbuzz, which doesn't consider the sequence invalid
 fuzzy-if(!contentSameGfxBackendAsCanvas,128,91) random-if(d2d) skip-if(azureSkiaGL) fuzzy-if(skiaContent,32,150) == 555388-1.html 555388-1-ref.html
 == 556661-1.html 556661-1-ref.html
-skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) == 557087-1.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,5) == 557087-2.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fuzzy-if(skiaContent,4,5) == 557087-1.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,5) == 557087-2.html 557087-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 557736-1.html 557736-1-ref.html
 skip-if((B2G&&browserIsRemote)||Mulet) != 558011-1.xul 558011-1-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop
 == 559284-1.html 559284-1-ref.html
 skip-if(B2G||Mulet) fails-if(Android) == 560455-1.xul 560455-1-ref.xul # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,2,5) == 561981-1.html 561981-1-ref.html
 == 561981-2.html 561981-2-ref.html
 fuzzy-if(skiaContent,1,5) == 561981-3.html 561981-3-ref.html
 == 561981-4.html 561981-4-ref.html
@@ -1646,25 +1646,25 @@ HTTP(..) == 621253-2-externalFilter.html
 == 621253-2-internalFilter.html 621253-2-ref.html
 skip-if(B2G||Mulet) random-if(winWidget) fuzzy-if(OSX==1008,19,17) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts) # Initial mulet triage: parity with B2G/B2G Desktop
 random-if(winWidget) HTTP(..) == 621918-2.svg 621918-2-ref.svg # same 1px issue as above, and HTTP(..) for filters.svg, used to mask antialiasing issues where glyphs touch
 fuzzy-if(d2d,5,1) == 622585-1.html 622585-1-ref.html # bug 789402
 fuzzy-if(Android,8,300) fuzzy-if(skiaContent,1,40000) == 625409-1.html 625409-1-ref.html
 == 627393-1.html about:blank
 fuzzy-if(skiaContent,1,500) == 630835-1.html about:blank
 == 631352-1.html 631352-1-ref.html
-skip-if(!haveTestPlugin) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(winWidget&&!layersGPUAccelerated,102,535) fuzzy-if(skiaContent,102,11000) == 632423-1.html 632423-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(!haveTestPlugin) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(winWidget&&!layersGPUAccelerated,102,535) fuzzy-if(skiaContent&&!Android,102,11000) == 632423-1.html 632423-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(Android||B2G||Mulet) random-if(winWidget||OSX==1010) == 632781-verybig.html 632781-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 632781-normalsize.html 632781-ref.html
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,559) fuzzy-if(!isDebugBuild&&gtkWidget&&/^Linux\x20i686/.test(http.oscpu),102,140) == 633344-1.html 633344-1-ref.html # bug 1103623, Linux32 from GCC update
 fuzzy-if(skiaContent,1,500) == 634232-1.html 634232-1-ref.html
 fuzzy-if(skiaContent,3,120000) == 635302-1.html 635302-1-ref.html
-fuzzy(1,68) fuzzy-if(gtkWidget,1,70) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,1,300) == 635373-1.html 635373-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent,2,550) == 635373-2.html 635373-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent,2,650) == 635373-3.html 635373-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy(1,68) fuzzy-if(gtkWidget,1,70) skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,300) == 635373-1.html 635373-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent&&!Android,2,550) == 635373-2.html 635373-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent&&!Android,2,650) == 635373-3.html 635373-3-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 HTTP(..) == 635639-1.html 635639-1-ref.html
 HTTP(..) == 635639-2.html 635639-2-ref.html
 random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
 fuzzy-if(Android,8,500) == 637852-1.html 637852-1-ref.html
 fuzzy-if(Android,8,500) == 637852-2.html 637852-2-ref.html
 fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html
 skip-if(B2G||Mulet) == 641770-1.html 641770-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == 641856-1.html 641856-1-ref.html
@@ -1673,17 +1673,17 @@ skip-if(B2G||Mulet) == 641770-1.html 641
 == 645647-2.html 645647-2-ref.html
 == 645768-1.html 645768-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) fuzzy-if(!layersGPUAccelerated,41,260) fuzzy-if(skiaContent,49,11000) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 needs-focus == 652301-1a.html 652301-1-ref.html
 needs-focus == 652301-1b.html 652301-1-ref.html
 fuzzy-if(skiaContent,2,5) == 652775-1.html 652775-1-ref.html
 fuzzy-if(skiaContent,1,5) == 653930-1.html 653930-1-ref.html
 HTTP(..) == 654057-1.html 654057-1-ref.html
-fails-if(layersGPUAccelerated&&cocoaWidget&&!skiaContent) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
+fuzzy-if(skiaContent,1,4500) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 655549-1.html 655549-1-ref.html
 == 655836-1.html 655836-1-ref.html
 != 656875.html about:blank
 == 658952.html 658952-ref.html
 fuzzy-if(skiaContent,1,3500) == 660682-1.html 660682-1-ref.html
 fuzzy-if(d2d,1,256) skip-if((B2G&&browserIsRemote)||Mulet) skip-if(Android) fuzzy-if(skiaContent,1,68000) == 664127-1.xul 664127-1-ref.xul # B2G: bug 974780. Android: Intermittent failures - bug 1019131 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == 665597-1.html 665597-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == 665597-2.html 665597-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
@@ -1925,17 +1925,17 @@ skip-if(!B2G) fuzzy-if(B2G,102,577) == 1
 skip-if(!B2G) fuzzy-if(B2G,102,877) == 1133905-6-vh-rtl.html 1133905-ref-vh-rtl.html
 skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul
 == 1151145-1.html 1151145-1-ref.html
 == 1151306-1.html 1151306-1-ref.html
 == 1153845-1.html 1153845-1-ref.html
 == 1155828-1.html 1155828-1-ref.html
 == 1156129-1.html 1156129-1-ref.html
 pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html
-fuzzy-if(Android,1,1) == 1169331-1.html 1169331-1-ref.html
+fuzzy-if(Android,2,5) == 1169331-1.html 1169331-1-ref.html
 fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html
 == 1179078-1.html 1179078-1-ref.html
 == 1179288-1.html 1179288-1-ref.html
 == 1190635-1.html 1190635-1-ref.html
 == 1202512-1.html 1202512-1-ref.html
 == 1202512-2.html 1202512-2-ref.html
 != 1207326-1.html about:blank
 == 1209603-1.html 1209603-1-ref.html
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,12 +1,12 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
-fuzzy(1,20) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
+fuzzy(1,20) fuzzy-if(skiaContent,1,700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
 random-if(!gtkWidget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,1,5) fuzzy-if(Android,8,6627) fuzzy-if(skiaContent,1,24) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html
 == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
--- a/layout/reftests/css-disabled/select/reftest.list
+++ b/layout/reftests/css-disabled/select/reftest.list
@@ -1,9 +1,9 @@
 == select-fieldset-1.html select-fieldset-ref.html
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,17) == select-fieldset-2.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,17) == select-fieldset-3.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(Android) fuzzy-if(skiaContent,2,13) == select-fieldset-4.html select-fieldset-ref.html
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,17) == select-fieldset-2.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,17) == select-fieldset-3.html select-fieldset-ref-disabled.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android) fuzzy-if(skiaContent&&!Android,2,13) == select-fieldset-4.html select-fieldset-ref.html
 == select-fieldset-legend-1.html select-fieldset-legend-ref-1.html
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,6) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,8) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,6) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,8) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,2,12) == select-fieldset-legend-4.html select-fieldset-legend-ref-4.html
 fuzzy-if(skiaContent,2,5) == select-fieldset-legend-5.html select-fieldset-legend-ref-5.html
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -117,17 +117,17 @@ fuzzy-if(skiaContent,18,600) == twostops
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent&&layersGPUAccelerated,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1a.html aja-linear-1-ref.html
 fails-if(!d2d&&!skiaContent) == aja-linear-1b.html aja-linear-1-ref.html # bug 526694
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1c.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1d.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1e.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1f.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,3,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4646) == aja-linear-1g.html aja-linear-1-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2a.html aja-linear-2-ref.html 
-fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2b.html aja-linear-2-ref.html 
+fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,4667) == aja-linear-2b.html aja-linear-2-ref.html 
 fails == aja-linear-2c.html aja-linear-2-ref.html # bug 522607
 fails-if(!d2d&&!(skiaContent&&winWidget)) fuzzy-if(skiaContent&&!winWidget,1,200) == aja-linear-2d.html aja-linear-2-ref.html # bug 526694
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,19999) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,1,10553) == aja-linear-3a.html aja-linear-3-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,19999) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,1,10553) == aja-linear-3b.html aja-linear-3-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,8655) == aja-linear-4a.html aja-linear-4-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,1,8655) == aja-linear-4b.html aja-linear-4-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,4,20000) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz&&OSX==1006,2,7878) == aja-linear-5a.html aja-linear-5-ref.html 
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,16500) fuzzy-if(azureSkiaGL||skiaContent,8,20000) fuzzy-if(azureQuartz,2,10163) == aja-linear-6a.html aja-linear-6-ref.html # bug 526708 
--- a/layout/reftests/css-invalid/select/reftest.list
+++ b/layout/reftests/css-invalid/select/reftest.list
@@ -2,11 +2,11 @@ needs-focus == select-valid.html select-
 fuzzy-if(skiaContent,1,3) needs-focus == select-invalid.html select-ref.html
 fuzzy-if(skiaContent,2,6) needs-focus == select-disabled.html select-disabled-ref.html
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,6) needs-focus == select-dyn-disabled.html select-disabled-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,1,3) needs-focus == select-dyn-not-disabled.html select-ref.html
 needs-focus == select-required-invalid.html select-required-ref.html
 needs-focus == select-required-valid.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
 fuzzy-if(skiaContent,1,250) needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,1,3) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,3) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,2,5) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
--- a/layout/reftests/css-ui-invalid/select/reftest.list
+++ b/layout/reftests/css-ui-invalid/select/reftest.list
@@ -7,12 +7,12 @@ fuzzy-if(skiaContent,1,3) needs-focus ==
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-1.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-2.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-changed-1.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-invalid-changed-2.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,84,77) fuzzy-if(skiaContent,1,1000) needs-focus == select-required-multiple-invalid-changed.html select-required-multiple-ref.html
 needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet) fails-if(Android) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,2,10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
 fuzzy-if(skiaContent,1,5) needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/css-ui-valid/select/reftest.list
+++ b/layout/reftests/css-ui-valid/select/reftest.list
@@ -8,11 +8,11 @@ fuzzy-if(skiaContent,2,5) needs-focus ==
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-1.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-2.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-changed-1.html select-required-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-required-valid-changed-2.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
 needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
 fuzzy(64,4) fuzzy-if(asyncPan&&layersGPUAccelerated,84,77) fuzzy-if(skiaContent,1,1000) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html
 fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(skiaContent,2,10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-novalidate.html select-required-ref.html
--- a/layout/reftests/css-valid/select/reftest.list
+++ b/layout/reftests/css-valid/select/reftest.list
@@ -3,10 +3,10 @@ fuzzy-if(skiaContent,2,5) needs-focus ==
 needs-focus == select-disabled.html select-disabled-ref.html
 fuzzy-if(skiaContent,1,5) needs-focus == select-dyn-disabled.html select-disabled-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-dyn-not-disabled.html select-ref.html
 needs-focus == select-required-invalid.html select-required-ref.html
 needs-focus == select-required-valid.html select-required-ref.html
 needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
 fuzzy-if(skiaContent,1,250) needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
 fails-if(Android||B2G||Mulet) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,1,3) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
--- a/layout/reftests/font-inflation/reftest.list
+++ b/layout/reftests/font-inflation/reftest.list
@@ -44,17 +44,17 @@ skip-if(B2G||Mulet) test-pref(font.size.
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1a.html intrinsic-fit-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-1c.html intrinsic-fit-1c-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2a.html intrinsic-fit-1a-ref.html
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2b.html intrinsic-fit-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) HTTP(..) == intrinsic-fit-2c.html intrinsic-fit-1c-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-listbox-1.html select-listbox-1-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-listbox-1.html select-listbox-1.html
-test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-1.html select-combobox-1-ref.html
+fuzzy-if(skiaContent,4,2) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-1.html select-combobox-1-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-1.html select-combobox-1.html
 skip-if(B2G||Mulet) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-listbox-2.html select-listbox-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-listbox-2.html select-listbox-2.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-2.html select-combobox-2-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-2.html select-combobox-2.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-3.html select-combobox-3-ref.html
 asserts-if(gtkWidget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-checkbox.html input-checkbox.html
 asserts-if(gtkWidget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-radio.html input-radio.html
--- a/layout/reftests/forms/select/reftest.list
+++ b/layout/reftests/forms/select/reftest.list
@@ -1,9 +1,9 @@
-fuzzy-if(Android,2,2) skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy-if(Android,4,11) skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == multiple.html multiple-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == boguskids.html boguskids-ref.html
 == dynamic-boguskids.html boguskids-ref.html
 == option-children.html option-children-ref.html
 fuzzy(1,4) == padding-button-placement.html padding-button-placement-ref.html
 HTTP(../..) == vertical-centering.html vertical-centering-ref.html
 == 997709-2.html 997709-2-ref.html
 needs-focus == focusring-1.html focusring-1-ref.html
--- a/layout/reftests/forms/textarea/reftest.list
+++ b/layout/reftests/forms/textarea/reftest.list
@@ -1,11 +1,11 @@
 skip-if(B2G||Mulet||Android) == resize.html resize-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 # an offset seems to apply to the native resizer on windows so skip this test for now
-skip-if(B2G||Mulet||Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) fuzzy-if(skiaContent&&!winWidget,5,10) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(B2G||Mulet||Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) fuzzy-if(skiaContent&&!winWidget&&!Android,5,10) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet||Android) != ltr.html rtl.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet||Android) != ltr-scrollbar.html rtl-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet||Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet||Android) != ltr.html no-resize.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet||Android) fails-if(xulRuntime.widgetToolkit=="gtk2") != rtl.html no-resize.html # bug 834724 # Initial mulet triage: parity with B2G/B2G Desktop
 == rtl.html rtl-dynamic-attr.html
 == rtl.html rtl-dynamic-style.html
 == rtl.html in-dynamic-rtl-doc.html
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -10,17 +10,17 @@ skip-if(B2G||Mulet) fails-if(azureSkia) 
 == element-paint-simple.html element-paint-simple-ref.html
 == element-paint-repeated.html element-paint-repeated-ref.html
 == element-paint-recursion.html element-paint-recursion-ref.html
 skip-if(B2G||Mulet) HTTP(..) == element-paint-continuation.html element-paint-continuation-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == element-paint-transform-01.html element-paint-transform-01-ref.html
 random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref.html # bug 587133
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint-background-size-01.html element-paint-background-size-01-ref.html
 == element-paint-background-size-02.html element-paint-background-size-02-ref.html
-== element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
+fuzzy-if(skiaContent,255,4) == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
 fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
 fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,2,106) == element-paint-native-widget.html element-paint-native-widget-ref.html   # in -ref the scrollframe is active and layerized differently with APZ
 fails-if(usesRepeatResampling) == element-paint-subimage-sampling-restriction.html about:blank
 == element-paint-clippath.html element-paint-clippath-ref.html
 == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
 fuzzy-if(skiaContent,1,326) == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
 == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
 == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
--- a/layout/reftests/svg/smil/transform/reftest.list
+++ b/layout/reftests/svg/smil/transform/reftest.list
@@ -4,15 +4,15 @@
 fuzzy(111,1802) fuzzy-if(skiaContent,130,1000) == additive-1.svg additive-1-ref.svg # bug 981344, bug 1239766
 == animate-width-1.svg lime.svg
 fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,4) == paced-1.svg paced-1-ref.svg # bug 981640
 fuzzy-if(skiaContent,1,220) == rotate-angle-1.svg rotate-angle-ref.svg
 == rotate-angle-2.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,1,130) == rotate-angle-3.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,1,110) == rotate-angle-4.svg rotate-angle-ref.svg
 fuzzy-if(skiaContent,1,130) == rotate-angle-5.svg rotate-angle-ref.svg
-fuzzy(12,27) fuzzy-if(skiaContent,1,180) == scale-1.svg scale-1-ref.svg  # bug 981004
+fuzzy(12,27) fuzzy-if(skiaContent,1,180) fuzzy-if(Android,16,3) == scale-1.svg scale-1-ref.svg  # bug 981004
 == set-transform-1.svg lime.svg
-fuzzy-if(winWidget,1,3) == skew-1.svg skew-1-ref.svg # bug 983671
+fuzzy-if(winWidget,1,3) fuzzy-if(skiaContent,1,20) == skew-1.svg skew-1-ref.svg # bug 983671
 == translate-clipPath-1.svg lime.svg
 fails-if(OSX==1006&&!skiaContent) == translate-gradient-1.svg lime.svg
 == translate-pattern-1.svg lime.svg
 == use-1.svg lime.svg
--- a/layout/reftests/table-background/reftest.list
+++ b/layout/reftests/table-background/reftest.list
@@ -53,10 +53,10 @@ fuzzy-if(d2d,1,37170) fuzzy-if(skiaConte
 skip-if(B2G||Mulet) fuzzy-if(d2d,1,12390) fuzzy-if(skiaContent,1,13000) == border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fuzzy-if(d2d||skiaContent,1,95000) == border-separate-opacity-table.html border-separate-opacity-table-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
 != scrollable-rowgroup-collapse-background.html scrollable-rowgroup-collapse-notref.html 
 != scrollable-rowgroup-collapse-border.html scrollable-rowgroup-collapse-notref.html     
 != scrollable-rowgroup-separate-background.html scrollable-rowgroup-separate-notref.html
 == scrollable-rowgroup-separate-border.html scrollable-rowgroup-separate-notref.html # scrolling rowgroups were removed in bug 28800
 == empty-cells-default-1.html empty-cells-default-1-ref.html
 == empty-cells-default-2.html empty-cells-default-2-ref.html
-fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(Android,1,39) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,77,5400) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html
+fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(Android,1,39) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,77,5500) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html
 == table-row-opacity-dynamic-2.html table-row-opacity-dynamic-2-ref.html
--- a/layout/reftests/text-decoration/reftest.list
+++ b/layout/reftests/text-decoration/reftest.list
@@ -100,13 +100,13 @@ fuzzy-if(cocoaWidget,1,5) == decoration-
 == decoration-color-override-standards.html decoration-color-override-standards-ref.html
 != decoration-color-override-standards-ref.html decoration-color-override-quirks-ref.html
 == decoration-css21-block.html decoration-css21-block-ref.html
 != inline-baseline-almost-standards.html inline-baseline-almost-standards-ref.html
 != inline-baseline-quirks.html inline-baseline-quirks-ref.html
 == 676538-1.html 676538-1-ref.html
 fuzzy-if(OSX==1010,1,4) == underline-button-1.html underline-button-1-ref.html
 fuzzy-if(OSX==1010,1,2) == underline-button-2.html underline-button-2-ref.html
-== underline-select-1.html underline-select-1-ref.html
+fuzzy-if(skiaContent,4,2) == underline-select-1.html underline-select-1-ref.html
 == underline-select-2.html underline-select-2-ref.html
 == 1133392.html 1133392-ref.html
 != 1159729-offset-adjustment.html 1159729-offset-adjustment-notref.html
 == emphasis-style-dynamic.html emphasis-style-dynamic-ref.html
--- a/layout/reftests/text-shadow/reftest.list
+++ b/layout/reftests/text-shadow/reftest.list
@@ -21,19 +21,19 @@ HTTP(..) == blur-opacity.html blur-opaci
 == textindent.html textindent-ref.html
 == lineoverflow.html lineoverflow-ref.html
 
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
 == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
 
 needs-focus != text-shadow-selected-1.html text-shadow-selected-1-notref.html
-fails-if(Android||B2G) fuzzy-if(skiaContent,1,1000) needs-focus == text-shadow-selected-1.html text-shadow-selected-1-ref.html # different foreground selection color on Android/B2G
+fails-if(Android||B2G) fuzzy-if(skiaContent&&!Android,1,1000) needs-focus == text-shadow-selected-1.html text-shadow-selected-1-ref.html # different foreground selection color on Android/B2G
 needs-focus != text-shadow-selected-2.html text-shadow-selected-2-notref.html
-fails-if(Android||B2G) fuzzy-if(skiaContent,1,1400) needs-focus == text-shadow-selected-2.html text-shadow-selected-2-ref.html # different foreground selection color on Android/B2G
+fails-if(Android||B2G) fuzzy-if(skiaContent&&!Android,1,1400) needs-focus == text-shadow-selected-2.html text-shadow-selected-2-ref.html # different foreground selection color on Android/B2G
 
 # bug 692744
 == text-shadow-on-space-1.html text-shadow-on-space-1-ref.html
 
 # bug 721750
 needs-focus == text-shadow-on-selection-1.html text-shadow-on-selection-1-ref.html
 needs-focus == text-shadow-on-selection-2.html text-shadow-on-selection-2-ref.html
 
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -147,17 +147,17 @@ random-if(cocoaWidget) HTTP(..) == zwnj-
 HTTP(..) == zwnj-02.xhtml zwnj-02-ref.xhtml # HTTP(..) for ../filters.svg
 != zwnj-01.html zwnj-01-notref.html
 == initial-zwj-1.html initial-zwj-1-ref.html
 == cgj-01.html cgj-01-ref.html
 == 444656.html 444656-ref.html
 == 449555-1.html 449555-1-ref.html
 == 467722.html 467722-ref.html
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,600) HTTP(..) == 475092-sub.html 475092-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
-fails-if(!winWidget&&!gtkWidget) skip-if(B2G||Mulet) fuzzy-if(skiaContent,89,3100) HTTP(..) == 475092-pos.html 475092-sub.html # bug 482596 # Initial mulet triage: parity with B2G/B2G Desktop
+fails-if(Android) skip-if(B2G||Mulet) fuzzy-if(skiaContent&&!Android,89,3100) HTTP(..) == 475092-pos.html 475092-sub.html # bug 482596 # Initial mulet triage: parity with B2G/B2G Desktop
 == 476378-soft-hyphen-fallback.html 476378-soft-hyphen-fallback-ref.html
 # Test for bug 484954
 == rgba-text.html rgba-text-ref.html
 # Test for bug 575695, 'kern' table support
 HTTP(..) != kerning-01.html kerning-01-notref.html
 # Test for bug 577380, support for AAT layout (on OS X only)
 random-if(!cocoaWidget) == 577380.html 577380-ref.html
 # Test for OpenType Arabic shaping support
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -64,17 +64,17 @@ fuzzy(116,94) fuzzy-if(skiaContent&&dwri
 == ua-style-sheet-size-1.html ua-style-sheet-size-1-ref.html
 == ua-style-sheet-size-2.html ua-style-sheet-size-2-ref.html
 
 == ua-style-sheet-fieldset-1.html ua-style-sheet-fieldset-1-ref.html
 skip-if(Android||B2G||Mulet||(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu))) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(!(Android||B2G||Mulet)) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(!winWidget||/^Windows\x20NT\x205\.1/.test(http.oscpu)) == ua-style-sheet-textarea-1.html ua-style-sheet-textarea-1c-ref.html
 == ua-style-sheet-checkbox-radio-1.html ua-style-sheet-checkbox-radio-1-ref.html
-skip-if(Android||B2G||Mulet) fuzzy-if(skiaContent,2,6) == ua-style-sheet-button-1.html ua-style-sheet-button-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+skip-if(Android||B2G||Mulet) fuzzy-if(skiaContent&&!Android,2,6) == ua-style-sheet-button-1.html ua-style-sheet-button-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(!(Android||B2G||Mulet)) == ua-style-sheet-button-1.html ua-style-sheet-button-1b-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == ua-style-sheet-input-color-1.html ua-style-sheet-input-color-1-ref.html
 fuzzy-if(gtkWidget,1,15) == ua-style-sheet-input-number-1.html ua-style-sheet-input-number-1-ref.html
 
 HTTP(..) == 1127488-align-default-horizontal-tb-ltr.html 1127488-align-top-left-ref.html
 HTTP(..) == 1127488-align-start-horizontal-tb-ltr.html 1127488-align-top-left-ref.html
 HTTP(..) == 1127488-align-end-horizontal-tb-ltr.html 1127488-align-top-right-ref.html
 HTTP(..) == 1127488-align-left-horizontal-tb-ltr.html 1127488-align-top-left-ref.html
--- a/layout/reftests/writing-mode/tables/reftest.list
+++ b/layout/reftests/writing-mode/tables/reftest.list
@@ -71,18 +71,18 @@ fuzzy-if(winWidget,48,600) fuzzy-if(coco
 fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-003.xht multicol-count-002-ref.xht
 fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-004.xht multicol-count-002-ref.xht
 fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-005.xht multicol-count-002-ref.xht
 fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-006.xht multicol-count-002-ref.xht
 fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-007.xht multicol-count-002-ref.xht
 
 fuzzy-if(Android,255,38) == table-caption-top-1.html table-caption-top-1-ref.html
 fuzzy-if(Android,255,38) == table-caption-bottom-1.html table-caption-bottom-1-ref.html
-== table-caption-left-1.html table-caption-left-1-ref.html
-== table-caption-right-1.html table-caption-right-1-ref.html
+fuzzy-if(Android,244,27) == table-caption-left-1.html table-caption-left-1-ref.html
+fuzzy-if(Android,244,27) == table-caption-right-1.html table-caption-right-1-ref.html
 
 == border-collapse-bevels-1a.html border-collapse-bevels-1-ref.html
 fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1b.html border-collapse-bevels-1-ref.html
 fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1c.html border-collapse-bevels-1-ref.html
 fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1d.html border-collapse-bevels-1-ref.html
 fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1e.html border-collapse-bevels-1-ref.html
 
 == vertical-rl-row-progression-1a.html vertical-rl-row-progression-1-ref.html
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -17,17 +17,16 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ServoStyleSet::ServoStyleSet()
   : mPresContext(nullptr)
   , mRawSet(Servo_StyleSet_Init())
   , mBatching(0)
-  , mStylingStarted(false)
 {
 }
 
 void
 ServoStyleSet::Init(nsPresContext* aPresContext)
 {
   mPresContext = aPresContext;
 }
@@ -68,34 +67,16 @@ ServoStyleSet::EndUpdate()
   if (--mBatching > 0) {
     return NS_OK;
   }
 
   // ... do something ...
   return NS_OK;
 }
 
-void
-ServoStyleSet::StartStyling(nsPresContext* aPresContext)
-{
-  MOZ_ASSERT(!mStylingStarted);
-
-  // Some things, like nsDocumentViewer::GetPageMode, recreate the presShell,
-  // while keeping the content tree alive. See bug 1292280.
-  //
-  // That's why we need to force a restyle.
-  nsIContent* root = mPresContext->Document()->GetRootElement();
-  if (root) {
-    root->SetIsDirtyForServo();
-  }
-
-  StyleDocument(/* aLeaveDirtyBits = */ false);
-  mStylingStarted = true;
-}
-
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleFor(Element* aElement,
                                nsStyleContext* aParentContext)
 {
   return GetContext(aElement, aParentContext, nullptr,
                     CSSPseudoElementType::NotPseudo);
 }
 
@@ -479,31 +460,26 @@ ClearDirtyBits(nsIContent* aContent)
   for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
     ClearDirtyBits(n);
   }
 }
 
 void
 ServoStyleSet::StyleDocument(bool aLeaveDirtyBits)
 {
-  // Unconditionally clear the flag on the document so that HasPendingRestyles
-  // returns false.
+  // Grab the root.
   nsIDocument* doc = mPresContext->Document();
-  doc->UnsetHasDirtyDescendantsForServo();
-
-  // Grab the root.
-  nsIContent* root = mPresContext->Document()->GetRootElement();
-  if (!root) {
-    return;
-  }
+  nsIContent* root = doc->GetRootElement();
+  MOZ_ASSERT(root);
 
   // Restyle the document, clearing the dirty bits if requested.
   Servo_RestyleSubtree(root, mRawSet.get());
   if (!aLeaveDirtyBits) {
     ClearDirtyBits(root);
+    doc->UnsetHasDirtyDescendantsForServo();
   }
 }
 
 void
 ServoStyleSet::StyleNewSubtree(nsIContent* aContent)
 {
   MOZ_ASSERT(aContent->IsDirtyForServo());
   Servo_RestyleSubtree(aContent, mRawSet.get());
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -50,18 +50,16 @@ public:
   void Shutdown();
 
   bool GetAuthorStyleDisabled() const;
   nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
 
   void BeginUpdate();
   nsresult EndUpdate();
 
-  void StartStyling(nsPresContext* aPresContext);
-
   already_AddRefed<nsStyleContext>
   ResolveStyleFor(dom::Element* aElement,
                   nsStyleContext* aParentContext);
 
   already_AddRefed<nsStyleContext>
   ResolveStyleFor(dom::Element* aElement,
                   nsStyleContext* aParentContext,
                   TreeMatchContext& aTreeMatchContext);
@@ -123,17 +121,17 @@ public:
   /**
    * Computes a restyle hint given a element and a previous element snapshot.
    */
   nsRestyleHint ComputeRestyleHint(dom::Element* aElement,
                                    ServoElementSnapshot* aSnapshot);
 
   /**
    * Performs a Servo traversal to compute style for all dirty nodes in the
-   * document.
+   * document. The root element must be non-null.
    *
    * If aLeaveDirtyBits is true, the dirty/dirty-descendant bits are not
    * cleared.
    */
   void StyleDocument(bool aLeaveDirtyBits);
 
   /**
    * Eagerly styles a subtree of dirty nodes that were just appended to the
@@ -150,32 +148,29 @@ public:
    * Like the above, but does not assume that the root node is dirty. When
    * appending multiple children to a potentially-non-dirty node, it's
    * preferable to call StyleNewChildren on the node rather than making multiple
    * calls to StyleNewSubtree on each child, since it allows for more
    * parallelism.
    */
   void StyleNewChildren(nsIContent* aParent);
 
-  bool StylingStarted() const { return mStylingStarted; }
-
 private:
   already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
                                               nsStyleContext* aParentContext,
                                               nsIAtom* aPseudoTag,
                                               CSSPseudoElementType aPseudoType);
 
   already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent,
                                               nsStyleContext* aParentContext,
                                               nsIAtom* aPseudoTag,
                                               CSSPseudoElementType aPseudoType);
 
   nsPresContext* mPresContext;
   UniquePtr<RawServoStyleSet> mRawSet;
   EnumeratedArray<SheetType, SheetType::Count,
                   nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
   int32_t mBatching;
-  bool mStylingStarted;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleSet_h
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -5624,20 +5624,19 @@ SVGTextFrame::TransformFrameRectFromText
       AppUnitsToFloatCSSPixels(gfxRect(rectInTextFrame.x,
                                        rectInTextFrame.y,
                                        rectInTextFrame.width,
                                        rectInTextFrame.height), presContext);
 
     // Intersect it with the run.
     uint32_t flags = TextRenderedRun::eIncludeFill |
                      TextRenderedRun::eIncludeStroke;
-    rectInFrameUserSpace.IntersectRect
-      (rectInFrameUserSpace, run.GetFrameUserSpaceRect(presContext, flags).ToThebesRect());
-
-    if (!rectInFrameUserSpace.IsEmpty()) {
+
+    if (rectInFrameUserSpace.IntersectRect(rectInFrameUserSpace,
+        run.GetFrameUserSpaceRect(presContext, flags).ToThebesRect())) {
       // Transform it up to user space of the <text>, also taking into
       // account the font size scale.
       gfxMatrix m = run.GetTransformFromRunUserSpaceToUserSpace(presContext);
       m.Scale(mFontSizeScaleFactor, mFontSizeScaleFactor);
       gfxRect rectInUserSpace = m.Transform(rectInFrameUserSpace);
 
       // Union it into the result.
       result.UnionRect(result, rectInUserSpace);
--- a/layout/xul/test/test_bug381167.xhtml
+++ b/layout/xul/test/test_bug381167.xhtml
@@ -22,17 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 381167 **/
 
 SimpleTest.waitForExplicitFinish();
 
 function closeit() {
-  var evt = document.createEvent('KeyEvents');
+  var evt = document.createEvent('KeyboardEvent');
                                  evt.initKeyEvent('keypress', true, true,
                                  window,
                                  true, false, false, false,
                                  'W'.charCodeAt(0), 0);
   window.dispatchEvent(evt);
 
   setTimeout(finish, 200);
 }
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -2678,17 +2678,18 @@ public class BrowserApp extends GeckoApp
 
         if (mFirstrunAnimationContainer == null) {
             final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub);
             mFirstrunAnimationContainer = (FirstrunAnimationContainer) firstrunPagerStub.inflate();
             mFirstrunAnimationContainer.load(getApplicationContext(), getSupportFragmentManager());
             mFirstrunAnimationContainer.registerOnFinishListener(new FirstrunAnimationContainer.OnFinishListener() {
                 @Override
                 public void onFinish() {
-                    if (mFirstrunAnimationContainer.showBrowserHint()) {
+                    if (mFirstrunAnimationContainer.showBrowserHint() &&
+                        TextUtils.isEmpty(getHomepage())) {
                         enterEditingMode();
                     }
                 }
             });
         }
 
         mHomeScreenContainer.setVisibility(View.VISIBLE);
     }
--- a/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
+++ b/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
@@ -218,17 +218,24 @@ public class Distribution {
 
     private static Distribution init(final Distribution distribution) {
         // Read/write preferences and files on the background thread.
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 boolean distributionSet = distribution.doInit();
                 if (distributionSet) {
-                    GeckoAppShell.notifyObservers("Distribution:Set", "");
+                    String preferencesJSON = "";
+                    try {
+                        final File descFile = distribution.getDistributionFile("preferences.json");
+                        preferencesJSON = FileUtils.readStringFromFile(descFile);
+                    } catch (IOException e) {
+                        Log.e(LOGTAG, "Error getting distribution descriptor file.", e);
+                    }
+                    GeckoAppShell.notifyObservers("Distribution:Set", preferencesJSON);
                 }
             }
         });
 
         return distribution;
     }
 
     /**
--- a/mobile/android/chrome/content/PermissionsHelper.js
+++ b/mobile/android/chrome/content/PermissionsHelper.js
@@ -1,27 +1,33 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 var PermissionsHelper = {
   _permissonTypes: ["password", "geolocation", "popup", "indexedDB",
-                    "offline-app", "desktop-notification", "plugins", "native-intent"],
+                    "offline-app", "desktop-notification", "plugins", "native-intent",
+                    "flyweb-publish-server"],
   _permissionStrings: {
     "password": {
       label: "password.logins",
       allowed: "password.save",
       denied: "password.dontSave"
     },
     "geolocation": {
       label: "geolocation.location",
       allowed: "geolocation.allow",
       denied: "geolocation.dontAllow"
     },
+    "flyweb-publish-server": {
+      label: "flyWebPublishServer.publishServer",
+      allowed: "flyWebPublishServer.allow",
+      denied: "flyWebPublishServer.dontAllow"
+    },
     "popup": {
       label: "blockPopups.label2",
       allowed: "popup.show",
       denied: "popup.dontShow"
     },
     "indexedDB": {
       label: "offlineApps.offlineData",
       allowed: "offlineApps.allow",
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6783,16 +6783,18 @@ var ExternalApps = {
     delete this._pageActionId;
   },
 };
 
 var Distribution = {
   // File used to store campaign data
   _file: null,
 
+  _preferencesJSON: null,
+
   init: function dc_init() {
     Services.obs.addObserver(this, "Distribution:Changed", false);
     Services.obs.addObserver(this, "Distribution:Set", false);
     Services.obs.addObserver(this, "prefservice:after-app-defaults", false);
     Services.obs.addObserver(this, "Campaign:Set", false);
 
     // Look for file outside the APK:
     // /data/data/org.mozilla.xxx/distribution.json
@@ -6808,16 +6810,23 @@ var Distribution = {
         try {
           Services.search._asyncReInit();
         } catch (e) {
           console.log("Unable to reinit search service.");
         }
         // Fall through.
 
       case "Distribution:Set":
+        if (aData) {
+          try {
+            this._preferencesJSON = JSON.parse(aData);
+          } catch (e) {
+            console.log("Invalid distribution JSON.");
+          }
+        }
         // Reload the default prefs so we can observe "prefservice:after-app-defaults"
         Services.prefs.QueryInterface(Ci.nsIObserver).observe(null, "reload-default-prefs", null);
         this.installDistroAddons();
         break;
 
       case "prefservice:after-app-defaults":
         this.getPrefs();
         break;
@@ -6842,16 +6851,22 @@ var Distribution = {
   update: function dc_update(aData) {
     // Force the distribution preferences on the default branch
     let defaults = Services.prefs.getDefaultBranch(null);
     defaults.setCharPref("distribution.id", aData.id);
     defaults.setCharPref("distribution.version", aData.version);
   },
 
   getPrefs: function dc_getPrefs() {
+    if (this._preferencesJSON) {
+        this.applyPrefs(this._preferencesJSON);
+        this._preferencesJSON = null;
+        return;
+    }
+
     // Get the distribution directory, and bail if it doesn't exist.
     let file = FileUtils.getDir("XREAppDist", [], false);
     if (!file.exists())
       return;
 
     file.append("preferences.json");
     this.readJSON(file, this.applyPrefs);
   },
--- a/mobile/android/components/ContentPermissionPrompt.js
+++ b/mobile/android/components/ContentPermissionPrompt.js
@@ -13,22 +13,24 @@ Cu.import("resource://gre/modules/Servic
 const kEntities = {
   "contacts": "contacts",
   "desktop-notification": "desktopNotification2",
   "device-storage:music": "deviceStorageMusic",
   "device-storage:pictures": "deviceStoragePictures",
   "device-storage:sdcard": "deviceStorageSdcard",
   "device-storage:videos": "deviceStorageVideos",
   "geolocation": "geolocation",
+  "flyweb-publish-server": "flyWebPublishServer",
 };
 
 // For these types, prompt for permission if action is unknown.
 const PROMPT_FOR_UNKNOWN = [
   "desktop-notification",
   "geolocation",
+  "flyweb-publish-server",
 ];
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
   classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -126,16 +126,28 @@ geolocation.dontAskAgain=Don't ask again
 # Desktop notification UI
 desktopNotification2.allow=Always
 desktopNotification2.dontAllow=Never
 desktopNotification2.ask=Would you like to receive notifications from this site?
 # LOCALIZATION NOTE (desktopNotification.notifications): Label that will be
 # used in site settings dialog.
 desktopNotification.notifications=Notifications
 
+# FlyWeb UI
+# LOCALIZATION NOTE (flyWebPublishServer.allow): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.allow=Allow
+# LOCALIZATION NOTE (flyWebPublishServer.dontAllow): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.dontAllow=Deny
+# LOCALIZATION NOTE (flyWebPublishServer.ask): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.ask=Would you like to let this site start a server accessible to nearby devices and people?
+# LOCALIZATION NOTE (flyWebPublishServer.dontAskAgain): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.dontAskAgain=Don't ask again for this site
+# LOCALIZATION NOTE (flyWebPublishServer.publishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
+flyWebPublishServer.publishServer=Publish Server
+
 # Imageblocking
 imageblocking.downloadedImage=Image unblocked
 imageblocking.showAllImages=Show All
 
 # Device Storage API
 deviceStorageMusic.allow=Allow
 deviceStorageMusic.dontAllow=Don't allow
 deviceStorageMusic.ask=Allow %S access to your music?
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -1398,17 +1398,17 @@ nsSocketTransportService::ProbeMaxCount(
             else
                 gMaxCount = index;
             break;
         }
         ++numAllocated;
     }
 
     // Test
-    PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U);
+    static_assert(SOCKET_LIMIT_MIN >= 32U, "Minimum Socket Limit is >= 32");
     while (gMaxCount <= numAllocated) {
         int32_t rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0));
         
         SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",
                     gMaxCount, rv));
 
         if (rv >= 0)
             break;
@@ -1467,17 +1467,17 @@ nsSocketTransportService::DiscoverMaxCou
     setrlimit(RLIMIT_NOFILE, &rlimitData);
     if ((getrlimit(RLIMIT_NOFILE, &rlimitData) != -1) &&
         (rlimitData.rlim_cur > SOCKET_LIMIT_MIN)) {
         gMaxCount = rlimitData.rlim_cur;
     }
 
 #elif defined(XP_WIN) && !defined(WIN_CE)
     // >= XP is confirmed to have at least 1000
-    PR_STATIC_ASSERT(SOCKET_LIMIT_TARGET <= 1000);
+    static_assert(SOCKET_LIMIT_TARGET <= 1000, "SOCKET_LIMIT_TARGET max value is 1000");
     gMaxCount = SOCKET_LIMIT_TARGET;
 #else
     // other platforms are harder to test - so leave at safe legacy value
 #endif
 
     return PR_SUCCESS;
 }
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -852,20 +852,17 @@ HttpChannelChild::MaybeDivertOnStop(cons
 
 void
 HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
                                 const ResourceTimingStruct& timing)
 {
   LOG(("HttpChannelChild::OnStopRequest [this=%p status=%x]\n",
        this, channelStatus));
 
-  if (mUploadStream) {
-    mUploadStream->Close();
-    mUploadStream = nullptr;
-  }
+  mUploadStream = nullptr;
 
   if (mDivertingToParent) {
     MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
       "Should not be processing any more callbacks from parent!");
 
     SendDivertOnStopRequest(channelStatus);
     return;
   }
--- a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
+++ b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
@@ -213,17 +213,17 @@ MozMillElement.prototype.dragToElement =
 
   try {
     srcWindow.addEventListener("dragstart", trapDrag, true);
     EventUtils.synthesizeMouse(srcNode, srcCoords.x, srcCoords.y,
                                { type: "mousedown" }, srcWindow);
     EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y,
                                { type: "mousemove" }, destWindow);
 
-    var event = destWindow.document.createEvent("DragEvents");
+    var event = destWindow.document.createEvent("DragEvent");
     event.initDragEvent("dragenter", true, true, destWindow, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
     event.initDragEvent("dragover", true, true, destWindow, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
     event.initDragEvent("drop", true, true, destWindow, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
     windowUtils.dispatchDOMEventViaPresShell(destNode, event, true);
 
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -592,17 +592,17 @@ function emitTouchEvent(type, touch) {
   if (!wasInterrupted()) {
     let loggingInfo = "emitting Touch event of type " + type + " to element with id: " + touch.target.id + " and tag name: " + touch.target.tagName + " at coordinates (" + touch.clientX + ", " + touch.clientY + ") relative to the viewport";
     dumpLog(loggingInfo);
     var docShell = curContainer.frame.document.defaultView.
                    QueryInterface(Components.interfaces.nsIInterfaceRequestor).
                    getInterface(Components.interfaces.nsIWebNavigation).
                    QueryInterface(Components.interfaces.nsIDocShell);
     if (docShell.asyncPanZoomEnabled && actions.scrolling) {
-      // if we're in APZ and we're scrolling, we must use injectTouchEvent to dispatch our touchmove events
+      // if we're in APZ and we're scrolling, we must use sendNativeTouchPoint to dispatch our touchmove events
       let index = sendSyncMessage("MarionetteFrame:getCurrentFrameId");
       // only call emitTouchEventForIFrame if we're inside an iframe.
       if (index != null) {
         sendSyncMessage("Marionette:emitTouchEvent",
           { index: index, type: type, id: touch.identifier,
             clientX: touch.clientX, clientY: touch.clientY,
             screenX: touch.screenX, screenY: touch.screenY,
             radiusX: touch.radiusX, radiusY: touch.radiusY,
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/selectors/pseudo-classes/indeterminate.html.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[indeterminate.html]
-  type: testharness
-  [':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute]
-    expected: FAIL
-
-  [dynamically check a radio input in a radio button group]
-    expected: FAIL
-
-  [click on radio4 which is in the indeterminate state]
-    expected: FAIL
-
--- a/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-form-element/form-nameditem.html
@@ -110,16 +110,21 @@ test(function() {
   assert_false("namedItem" in form)
 }, "Forms should not have a namedItem method")
 
 test(function() {
   var form = document.getElementsByTagName("form")[0]
   var button = document.getElementsByTagName("input")[0]
   assert_equals(button.type, "button")
   assert_equals(form.button, button)
+  var desc = Object.getOwnPropertyDescriptor(form, "button");
+  assert_equals(desc.value, button);
+  assert_false(desc.writable);
+  assert_true(desc.configurable);
+  assert_false(desc.enumerable);
   assert_equals(form.button.length, undefined)
 }, "Name for a single element should work")
 
 test(function() {
   var form = document.getElementsByTagName("form")[0]
   assert_equals(form.radio.item(-1), null)
   assert_array_equals([0, 1, 2].map(function(i) {
     return form.radio.item(i).value
@@ -217,16 +222,22 @@ test(function() {
   var input1 = document.getElementsByName("d")[0]
   assert_equals(input1.localName, "input")
   assert_equals(input1.getAttribute("form"), "c")
 
   var input2 = document.getElementsByName("d")[1]
   assert_equals(input2.localName, "input")
   assert_equals(input2.getAttribute("form"), "c")
 
+  var desc = Object.getOwnPropertyDescriptor(form, "d");
+  assert_equals(desc.value, form.d);
+  assert_false(desc.writable);
+  assert_true(desc.configurable);
+  assert_false(desc.enumerable);
+
   assert_true(form.d instanceof NodeList, "form.d should be a NodeList")
   assert_array_equals(form.d, [input1, input2])
 }, "The form attribute should be taken into account for named getters (multiple elements)")
 
 test(function() {
   var f = document.body.appendChild(document.createElement("form"))
   f.id = "f"
   var g = f.appendChild(document.createElement("form"))
--- a/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/indeterminate.html
+++ b/testing/web-platform/tests/html/semantics/selectors/pseudo-classes/indeterminate.html
@@ -19,17 +19,17 @@
 
 <script>
   testSelectorIdsMatch(":indeterminate", ["radio2", "radio3", "radio4", "radio5", "progress1"], "':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute");
 
   document.getElementById("radio2").setAttribute("checked", "checked");
   testSelectorIdsMatch(":indeterminate", ["radio4", "radio5", "progress1"], "dynamically check a radio input in a radio button group");
 
   document.getElementById("radio4").click();
-  testSelectorIdsMatch(":indeterminate", ["checkbox1", "progress2"], "click on radio4 which is in the indeterminate state");
+  testSelectorIdsMatch(":indeterminate", ["progress1"], "click on radio4 which is in the indeterminate state");
 
   document.getElementById("progress1").setAttribute("value", "20");
   testSelectorIdsMatch(":indeterminate", [], "adding a value to progress1 should put it in a determinate state");
 
   document.getElementById("progress2").removeAttribute("value");
   testSelectorIdsMatch(":indeterminate", ["progress2"], "removing progress2's value should put it in an indeterminate state");
 
   document.getElementById("checkbox1").indeterminate = true; // set checkbox1 in the indeterminate state
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -99,18 +99,18 @@ const LOGGER_ID_BASE = "addons.webextens
 const UUID_MAP_PREF = "extensions.webextensions.uuids";
 const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall";
 const LEAVE_UUID_PREF = "extensions.webextensions.keepUuidOnUninstall";
 
 const COMMENT_REGEXP = new RegExp(String.raw`
     ^
     (
       (?:
-        [^"] |
-        " (?:[^"\\] | \\.)* "
+        [^"\n] |
+        " (?:[^"\\\n] | \\.)* "
       )*?
     )
 
     //.*
   `.replace(/\s+/g, ""), "gm");
 
 var ExtensionContext, GlobalManager;
 
--- a/toolkit/components/extensions/NativeMessaging.jsm
+++ b/toolkit/components/extensions/NativeMessaging.jsm
@@ -372,52 +372,55 @@ this.NativeApp = class extends EventEmit
   }
 
   // Called from Context when the extension is shut down.
   close() {
     this._cleanup();
   }
 
   portAPI() {
-    let api = {
+    let port = {
       name: this.name,
 
       disconnect: () => {
         if (this._isDisconnected) {
           throw new this.context.cloneScope.Error("Attempt to disconnect an already disconnected port");
         }
         this._cleanup();
       },
 
       postMessage: msg => {
         this.send(msg);
       },
 
       onDisconnect: new ExtensionUtils.SingletonEventManager(this.context, "native.onDisconnect", fire => {
         let listener = what => {
-          this.context.runSafe(fire);
+          this.context.runSafeWithoutClone(fire, port);
         };
         this.on("disconnect", listener);
         return () => {
           this.off("disconnect", listener);
         };
       }).api(),
 
       onMessage: new ExtensionUtils.SingletonEventManager(this.context, "native.onMessage", fire => {
         let listener = (what, msg) => {
-          this.context.runSafe(fire, msg);
+          msg = Cu.cloneInto(msg, this.context.cloneScope);
+          this.context.runSafeWithoutClone(fire, msg, port);
         };
         this.on("message", listener);
         return () => {
           this.off("message", listener);
         };
       }).api(),
     };
 
-    return Cu.cloneInto(api, this.context.cloneScope, {cloneFunctions: true});
+    port = Cu.cloneInto(port, this.context.cloneScope, {cloneFunctions: true});
+
+    return port;
   }
 
   sendMessage(msg) {
     let responsePromise = new Promise((resolve, reject) => {
       this.on("message", (what, msg) => { resolve(msg); });
       this.on("disconnect", (what, err) => { reject(err); });
     });
 
--- a/toolkit/components/extensions/Schemas.jsm
+++ b/toolkit/components/extensions/Schemas.jsm
@@ -543,16 +543,79 @@ class Entry {
    */
   inject(apiImpl, path, name, dest, context) {
   }
 }
 
 // Corresponds either to a type declared in the "types" section of the
 // schema or else to any type object used throughout the schema.
 class Type extends Entry {
+  /**
+   * @property {Array<string>} EXTRA_PROPERTIES
+   *        An array of extra properties which may be present for
+   *        schemas of this type.
+   */
+  static get EXTRA_PROPERTIES() {
+    return ["description", "deprecated", "preprocess", "restrictions"];
+  }
+
+  /**
+   * Parses the given schema object and returns an instance of this
+   * class which corresponds to its properties.
+   *
+   * @param {object} schema
+   *        A JSON schema object which corresponds to a definition of
+   *        this type.
+   * @param {Array<string>} path
+   *        The path to this schema object from the root schema,
+   *        corresponding to the property names and array indices
+   *        traversed during parsing in order to arrive at this schema
+   *        object.
+   * @param {Array<string>} [extraProperties]
+   *        An array of extra property names which are valid for this
+   *        schema in the current context.
+   * @returns {Type}
+   *        An instance of this type which corresponds to the given
+   *        schema object.
+   * @static
+   */
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    return new this(schema);
+  }
+
+  /**
+   * Checks that all of the properties present in the given schema
+   * object are valid properties for this type, and throws if invalid.
+   *
+   * @param {object} schema
+   *        A JSON schema object.
+   * @param {Array<string>} path
+   *        The path to this schema object from the root schema,
+   *        corresponding to the property names and array indices
+   *        traversed during parsing in order to arrive at this schema
+   *        object.
+   * @param {Array<string>} [extra]
+   *        An array of extra property names which are valid for this
+   *        schema in the current context.
+   * @throws {Error}
+   *        An error describing the first invalid property found in the
+   *        schema object.
+   */
+  static checkSchemaProperties(schema, path, extra = []) {
+    let allowedSet = new Set([...this.EXTRA_PROPERTIES, ...extra]);
+
+    for (let prop of Object.keys(schema)) {
+      if (!allowedSet.has(prop)) {
+        throw new Error(`Internal error: Namespace ${path.join(".")} has invalid type property "${prop}" in type "${schema.id || JSON.stringify(schema)}"`);
+      }
+    }
+  }
+
   // Takes a value, checks that it has the correct type, and returns a
   // "normalized" version of the value. The normalized version will
   // include "nulls" in place of omitted optional properties. The
   // result of this function is either {error: "Some type error"} or
   // {value: <normalized-value>}.
   normalize(value, context) {
     return context.error("invalid type");
   }
@@ -595,16 +658,27 @@ class AnyType extends Type {
 
   checkBaseType(baseType) {
     return true;
   }
 }
 
 // An untagged union type.
 class ChoiceType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["choices", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let choices = schema.choices.map(t => Schemas.parseSchema(t, path));
+    return new this(schema, choices);
+  }
+
   constructor(schema, choices) {
     super(schema);
     this.choices = choices;
   }
 
   extend(type) {
     this.choices.push(...type.choices);
 
@@ -643,16 +717,31 @@ class ChoiceType extends Type {
 
   checkBaseType(baseType) {
     return this.choices.some(t => t.checkBaseType(baseType));
   }
 }
 
 // This is a reference to another type--essentially a typedef.
 class RefType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["$ref", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let ref = schema.$ref;
+    let ns = path[0];
+    if (ref.includes(".")) {
+      [ns, ref] = ref.split(".");
+    }
+    return new this(schema, ns, ref);
+  }
+
   // For a reference to a type named T declared in namespace NS,
   // namespaceName will be NS and reference will be T.
   constructor(schema, namespaceName, reference) {
     super(schema);
     this.namespaceName = namespaceName;
     this.reference = reference;
   }
 
@@ -671,16 +760,60 @@ class RefType extends Type {
   }
 
   checkBaseType(baseType) {
     return this.targetType.checkBaseType(baseType);
   }
 }
 
 class StringType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["enum", "minLength", "maxLength", "pattern", "format",
+            ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let enumeration = schema.enum || null;
+    if (enumeration) {
+      // The "enum" property is either a list of strings that are
+      // valid values or else a list of {name, description} objects,
+      // where the .name values are the valid values.
+      enumeration = enumeration.map(e => {
+        if (typeof(e) == "object") {
+          return e.name;
+        }
+        return e;
+      });
+    }
+
+    let pattern = null;
+    if (schema.pattern) {
+      try {
+        pattern = parsePattern(schema.pattern);
+      } catch (e) {
+        throw new Error(`Internal error: Invalid pattern ${JSON.stringify(schema.pattern)}`);
+      }
+    }
+
+    let format = null;
+    if (schema.format) {
+      if (!(schema.format in FORMATS)) {
+        throw new Error(`Internal error: Invalid string format ${schema.format}`);
+      }
+      format = FORMATS[schema.format];
+    }
+    return new this(schema, enumeration,
+                    schema.minLength || 0,
+                    schema.maxLength || Infinity,
+                    pattern,
+                    format);
+  }
+
   constructor(schema, enumeration, minLength, maxLength, pattern, format) {
     super(schema);
     this.enumeration = enumeration;
     this.minLength = minLength;
     this.maxLength = maxLength;
     this.pattern = pattern;
     this.format = format;
   }
@@ -738,17 +871,74 @@ class StringType extends Type {
       for (let e of this.enumeration) {
         let key = e.toUpperCase();
         obj[key] = e;
       }
     }
   }
 }
 
+let SubModuleType;
 class ObjectType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["properties", "patternProperties", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    if ("functions" in schema) {
+      return SubModuleType.parseSchema(schema, path, extraProperties);
+    }
+
+    if (!("$extend" in schema)) {
+      // Only allow extending "properties" and "patternProperties".
+      extraProperties = ["additionalProperties", "isInstanceOf", ...extraProperties];
+    }
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let parseProperty = (schema, extraProps = []) => {
+      return {
+        type: Schemas.parseSchema(schema, path,
+                                  ["unsupported", "onError", "permissions", ...extraProps]),
+        optional: schema.optional || false,
+        unsupported: schema.unsupported || false,
+        onError: schema.onError || null,
+      };
+    };
+
+    // Parse explicit "properties" object.
+    let properties = Object.create(null);
+    for (let propName of Object.keys(schema.properties || {})) {
+      properties[propName] = parseProperty(schema.properties[propName], ["optional"]);
+    }
+
+    // Parse regexp properties from "patternProperties" object.
+    let patternProperties = [];
+    for (let propName of Object.keys(schema.patternProperties || {})) {
+      let pattern;
+      try {
+        pattern = parsePattern(propName);
+      } catch (e) {
+        throw new Error(`Internal error: Invalid property pattern ${JSON.stringify(propName)}`);
+      }
+
+      patternProperties.push({
+        pattern,
+        type: parseProperty(schema.patternProperties[propName]),
+      });
+    }
+
+    // Parse "additionalProperties" schema.
+    let additionalProperties = null;
+    if (schema.additionalProperties) {
+      additionalProperties = Schemas.parseSchema(schema.additionalProperties, path);
+    }
+
+    return new this(schema, properties, additionalProperties, patternProperties, schema.isInstanceOf || null);
+  }
+
   constructor(schema, properties, additionalProperties, patternProperties, isInstanceOf) {
     super(schema);
     this.properties = properties;
     this.additionalProperties = additionalProperties;
     this.patternProperties = patternProperties;
     this.isInstanceOf = isInstanceOf;
   }
 
@@ -764,160 +954,193 @@ class ObjectType extends Type {
 
     return this;
   }
 
   checkBaseType(baseType) {
     return baseType == "object";
   }
 
-  // FIXME: Bug 1265371 - Refactor normalize and parseType in Schemas.jsm to reduce complexity
-  normalize(value, context) { // eslint-disable-line complexity
-    let v = this.normalizeBase("object", value, context);
-    if (v.error) {
-      return v;
-    }
-    value = v.value;
-
-    if (this.isInstanceOf) {
-      if (Object.keys(this.properties).length ||
-          this.patternProperties.length ||
-          !(this.additionalProperties instanceof AnyType)) {
-        throw new Error("InternalError: isInstanceOf can only be used with objects that are otherwise unrestricted");
-      }
-
-      if (!instanceOf(value, this.isInstanceOf)) {
-        return context.error(`Object must be an instance of ${this.isInstanceOf}`,
-                             `be an instance of ${this.isInstanceOf}`);
-      }
-
-      // This is kind of a hack, but we can't normalize things that
-      // aren't JSON, so we just return them.
-      return {value};
-    }
-
+  /**
+   * Extracts the enumerable properties of the given object, including
+   * function properties which would normally be omitted by X-ray
+   * wrappers.
+   *
+   * @param {object} value
+   * @param {Context} context
+   *        The current parse context.
+   * @returns {object}
+   *        An object with an `error` or `value` property.
+   */
+  extractProperties(value, context) {
     // |value| should be a JS Xray wrapping an object in the
     // extension compartment. This works well except when we need to
     // access callable properties on |value| since JS Xrays don't
     // support those. To work around the problem, we verify that
     // |value| is a plain JS object (i.e., not anything scary like a
     // Proxy). Then we copy the properties out of it into a normal
     // object using a waiver wrapper.
 
     let klass = Cu.getClassName(value, true);
     if (klass != "Object") {
-      return context.error(`Expected a plain JavaScript object, got a ${klass}`,
-                           `be a plain JavaScript object`);
+      throw context.error(`Expected a plain JavaScript object, got a ${klass}`,
+                          `be a plain JavaScript object`);
     }
 
     let properties = Object.create(null);
-    {
-      // |waived| is scoped locally to avoid accessing it when we
-      // don't mean to.
-      let waived = Cu.waiveXrays(value);
-      for (let prop of Object.getOwnPropertyNames(waived)) {
-        let desc = Object.getOwnPropertyDescriptor(waived, prop);
-        if (desc.get || desc.set) {
-          return context.error("Objects cannot have getters or setters on properties",
-                               "contain no getter or setter properties");
-        }
-        if (!desc.enumerable) {
-          // Chrome ignores non-enumerable properties.
-          continue;
-        }
+
+    let waived = Cu.waiveXrays(value);
+    for (let prop of Object.getOwnPropertyNames(waived)) {
+      let desc = Object.getOwnPropertyDescriptor(waived, prop);
+      if (desc.get || desc.set) {
+        throw context.error("Objects cannot have getters or setters on properties",
+                            "contain no getter or setter properties");
+      }
+      // Chrome ignores non-enumerable properties.
+      if (desc.enumerable) {
         properties[prop] = Cu.unwaiveXrays(desc.value);
       }
     }
 
-    let remainingProps = new Set(Object.keys(properties));
+    return properties;
+  }
+
+  checkProperty(context, prop, propType, result, properties, remainingProps) {
+    let {type, optional, unsupported, onError} = propType;
+    let error = null;
+
+    if (unsupported) {
+      if (prop in properties) {
+        error = context.error(`Property "${prop}" is unsupported by Firefox`,
+                              `not contain an unsupported "${prop}" property`);
+      }
+    } else if (prop in properties) {
+      if (optional && (properties[prop] === null || properties[prop] === undefined)) {
+        result[prop] = null;
+      } else {
+        let r = context.withPath(prop, () => type.normalize(properties[prop], context));
+        if (r.error) {
+          error = r;
+        } else {
+          result[prop] = r.value;
+          properties[prop] = r.value;
+        }
+      }
+      remainingProps.delete(prop);
+    } else if (!optional) {
+      error = context.error(`Property "${prop}" is required`,
+                            `contain the required "${prop}" property`);
+    } else {
+      result[prop] = null;
+    }
+
+    if (error) {
+      if (onError == "warn") {
+        context.logError(error.error);
+      } else if (onError != "ignore") {
+        throw error;
+      }
+
+      result[prop] = null;
+    }
+  }
 
-    let checkProperty = (prop, propType, result) => {
-      let {type, optional, unsupported} = propType;
-      if (unsupported) {
-        if (prop in properties) {
-          return context.error(`Property "${prop}" is unsupported by Firefox`,
-                               `not contain an unsupported "${prop}" property`);
+  normalize(value, context) {
+    try {
+      let v = this.normalizeBase("object", value, context);
+      if (v.error) {
+        return v;
+      }
+      value = v.value;
+
+      if (this.isInstanceOf) {
+        if (Object.keys(this.properties).length ||
+            this.patternProperties.length ||
+            !(this.additionalProperties instanceof AnyType)) {
+          throw new Error("InternalError: isInstanceOf can only be used with objects that are otherwise unrestricted");
+        }
+
+        if (!instanceOf(value, this.isInstanceOf)) {
+          return context.error(`Object must be an instance of ${this.isInstanceOf}`,
+                               `be an instance of ${this.isInstanceOf}`);
         }
-      } else if (prop in properties) {
-        if (optional && (properties[prop] === null || properties[prop] === undefined)) {
-          result[prop] = null;
-        } else {
+
+        // This is kind of a hack, but we can't normalize things that
+        // aren't JSON, so we just return them.
+        return {value};
+      }
+
+      let properties = this.extractProperties(value, context);
+      let remainingProps = new Set(Object.keys(properties));
+
+      let result = {};
+      for (let prop of Object.keys(this.properties)) {
+        this.checkProperty(context, prop, this.properties[prop], result,
+                           properties, remainingProps);
+      }
+
+      for (let prop of Object.keys(properties)) {
+        for (let {pattern, type} of this.patternProperties) {
+          if (pattern.test(prop)) {
+            this.checkProperty(context, prop, type, result,
+                               properties, remainingProps);
+          }
+        }
+      }
+
+      if (this.additionalProperties) {
+        for (let prop of remainingProps) {
+          let type = this.additionalProperties;
           let r = context.withPath(prop, () => type.normalize(properties[prop], context));
           if (r.error) {
             return r;
           }
           result[prop] = r.value;
-          properties[prop] = r.value;
         }
-        remainingProps.delete(prop);
-      } else if (!optional) {
-        return context.error(`Property "${prop}" is required`,
-                             `contain the required "${prop}" property`);
-      } else {
-        result[prop] = null;
+      } else if (remainingProps.size == 1) {
+        return context.error(`Unexpected property "${[...remainingProps]}"`,
+                             `not contain an unexpected "${[...remainingProps]}" property`);
+      } else if (remainingProps.size) {
+        let props = [...remainingProps].sort().join(", ");
+        return context.error(`Unexpected properties: ${props}`,
+                             `not contain the unexpected properties [${props}]`);
       }
-    };
-
-    let result = {};
-    for (let prop of Object.keys(this.properties)) {
-      let error = checkProperty(prop, this.properties[prop], result);
-      if (error) {
-        let {onError} = this.properties[prop];
-        if (onError == "warn") {
-          context.logError(error.error);
-        } else if (onError != "ignore") {
-          return error;
-        }
-
-        result[prop] = null;
-        remainingProps.delete(prop);
-      }
-    }
 
-    for (let prop of Object.keys(properties)) {
-      for (let {pattern, type} of this.patternProperties) {
-        if (pattern.test(prop)) {
-          let error = checkProperty(prop, type, result);
-          if (error) {
-            return error;
-          }
-        }
+      return {value: result};
+    } catch (e) {
+      if (e.error) {
+        return e;
       }
+      throw e;
     }
-
-    if (this.additionalProperties) {
-      for (let prop of remainingProps) {
-        let type = this.additionalProperties;
-        let r = context.withPath(prop, () => type.normalize(properties[prop], context));
-        if (r.error) {
-          return r;
-        }
-        result[prop] = r.value;
-      }
-    } else if (remainingProps.size == 1) {
-      return context.error(`Unexpected property "${[...remainingProps]}"`,
-                           `not contain an unexpected "${[...remainingProps]}" property`);
-    } else if (remainingProps.size) {
-      let props = [...remainingProps].sort().join(", ");
-      return context.error(`Unexpected properties: ${props}`,
-                           `not contain the unexpected properties [${props}]`);
-    }
-
-    return {value: result};
   }
 }
 
 // This type is just a placeholder to be referred to by
 // SubModuleProperty. No value is ever expected to have this type.
-class SubModuleType extends Type {
+SubModuleType = class SubModuleType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["functions", "events", "properties", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    // The path we pass in here is only used for error messages.
+    path = [...path, schema.id];
+    let functions = schema.functions.map(fun => Schemas.parseFunction(path, fun));
+
+    return new this(functions);
+  }
+
   constructor(functions) {
     super();
     this.functions = functions;
   }
-}
+};
 
 class NumberType extends Type {
   normalize(value, context) {
     let r = this.normalizeBase("number", value, context);
     if (r.error) {
       return r;
     }
 
@@ -930,16 +1153,26 @@ class NumberType extends Type {
   }
 
   checkBaseType(baseType) {
     return baseType == "number" || baseType == "integer";
   }
 }
 
 class IntegerType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["minimum", "maximum", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    return new this(schema, schema.minimum || -Infinity, schema.maximum || Infinity);
+  }
+
   constructor(schema, minimum, maximum) {
     super(schema);
     this.minimum = minimum;
     this.maximum = maximum;
   }
 
   normalize(value, context) {
     let r = this.normalizeBase("integer", value, context);
@@ -977,16 +1210,28 @@ class BooleanType extends Type {
   }
 
   checkBaseType(baseType) {
     return baseType == "boolean";
   }
 }
 
 class ArrayType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["items", "minItems", "maxItems", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let items = Schemas.parseSchema(schema.items, path);
+
+    return new this(schema, items, schema.minItems || 0, schema.maxItems || Infinity);
+  }
+
   constructor(schema, itemType, minItems, maxItems) {
     super(schema);
     this.itemType = itemType;
     this.minItems = minItems;
     this.maxItems = maxItems;
   }
 
   normalize(value, context) {
@@ -1019,16 +1264,56 @@ class ArrayType extends Type {
   }
 
   checkBaseType(baseType) {
     return baseType == "array";
   }
 }
 
 class FunctionType extends Type {
+  static get EXTRA_PROPERTIES() {
+    return ["parameters", "async", "returns", ...super.EXTRA_PROPERTIES];
+  }
+
+  static parseSchema(schema, path, extraProperties = []) {
+    this.checkSchemaProperties(schema, path, extraProperties);
+
+    let isAsync = !!schema.async;
+    let parameters = null;
+    if ("parameters" in schema) {
+      parameters = [];
+      for (let param of schema.parameters) {
+        // Callbacks default to optional for now, because of promise
+        // handling.
+        let isCallback = isAsync && param.name == schema.async;
+
+        parameters.push({
+          type: Schemas.parseSchema(param, path, ["name", "optional"]),
+          name: param.name,
+          optional: param.optional == null ? isCallback : param.optional,
+        });
+      }
+    }
+
+    let hasAsyncCallback = false;
+    if (isAsync) {
+      if (parameters && parameters.length && parameters[parameters.length - 1].name == schema.async) {
+        hasAsyncCallback = true;
+      }
+      if (schema.returns) {
+        throw new Error("Internal error: Async functions must not have return values.");
+      }
+      if (schema.allowAmbiguousOptionalArguments && !hasAsyncCallback) {
+        throw new Error("Internal error: Async functions with ambiguous arguments must declare the callback as the last parameter");
+      }
+    }
+
+    return new this(schema, parameters, isAsync, hasAsyncCallback);
+  }
+
   constructor(schema, parameters, isAsync, hasAsyncCallback) {
     super(schema);
     this.parameters = parameters;
     this.isAsync = isAsync;
     this.hasAsyncCallback = hasAsyncCallback;
   }
 
   normalize(value, context) {
@@ -1338,16 +1623,27 @@ class Event extends CallEntry {
 
     let obj = Cu.createObjectIn(dest, {defineAs: name});
     Cu.exportFunction(addStub, obj, {defineAs: "addListener"});
     Cu.exportFunction(removeStub, obj, {defineAs: "removeListener"});
     Cu.exportFunction(hasStub, obj, {defineAs: "hasListener"});
   }
 }
 
+const TYPES = Object.freeze(Object.assign(Object.create(null), {
+  any: AnyType,
+  array: ArrayType,
+  boolean: BooleanType,
+  function: FunctionType,
+  integer: IntegerType,
+  number: NumberType,
+  object: ObjectType,
+  string: StringType,
+}));
+
 this.Schemas = {
   initialized: false,
 
   // Maps a schema URL to the JSON contained in that schema file. This
   // is useful for sending the JSON across processes.
   schemaJSON: new Map(),
 
   // Map[<schema-name> -> Map[<symbol-name> -> Entry]]
@@ -1361,234 +1657,73 @@ this.Schemas = {
       ns.permissions = null;
       ns.restrictions = null;
       ns.defeaultRestrictions = null;
       this.namespaces.set(namespaceName, ns);
     }
     ns.set(symbol, value);
   },
 
-  // FIXME: Bug 1265371 - Refactor normalize and parseType in Schemas.jsm to reduce complexity
-  parseType(path, type, extraProperties = []) { // eslint-disable-line complexity
+  parseSchema(schema, path, extraProperties = []) {
     let allowedProperties = new Set(extraProperties);
 
-    // Do some simple validation of our own schemas.
-    function checkTypeProperties(...extra) {
-      let allowedSet = new Set([...allowedProperties, ...extra, "description", "deprecated", "preprocess", "restrictions"]);
-      for (let prop of Object.keys(type)) {
-        if (!allowedSet.has(prop)) {
-          throw new Error(`Internal error: Namespace ${path.join(".")} has invalid type property "${prop}" in type "${type.id || JSON.stringify(type)}"`);
-        }
-      }
+    if ("choices" in schema) {
+      return ChoiceType.parseSchema(schema, path, allowedProperties);
+    } else if ("$ref" in schema) {
+      return RefType.parseSchema(schema, path, allowedProperties);
     }
 
-    if ("choices" in type) {
-      checkTypeProperties("choices");
-
-      let choices = type.choices.map(t => this.parseType(path, t));
-      return new ChoiceType(type, choices);
-    } else if ("$ref" in type) {
-      checkTypeProperties("$ref");
-      let ref = type.$ref;
-      let ns = path[0];
-      if (ref.includes(".")) {
-        [ns, ref] = ref.split(".");
-      }
-      return new RefType(type, ns, ref);
-    }
-
-    if (!("type" in type)) {
-      throw new Error(`Unexpected value for type: ${JSON.stringify(type)}`);
+    if (!("type" in schema)) {
+      throw new Error(`Unexpected value for type: ${JSON.stringify(schema)}`);
     }
 
     allowedProperties.add("type");
 
-    // Otherwise it's a normal type...
-    if (type.type == "string") {
-      checkTypeProperties("enum", "minLength", "maxLength", "pattern", "format");
-
-      let enumeration = type.enum || null;
-      if (enumeration) {
-        // The "enum" property is either a list of strings that are
-        // valid values or else a list of {name, description} objects,
-        // where the .name values are the valid values.
-        enumeration = enumeration.map(e => {
-          if (typeof(e) == "object") {
-            return e.name;
-          }
-          return e;
-        });
-      }
-
-      let pattern = null;
-      if (type.pattern) {
-        try {
-          pattern = parsePattern(type.pattern);
-        } catch (e) {
-          throw new Error(`Internal error: Invalid pattern ${JSON.stringify(type.pattern)}`);
-        }
-      }
-
-      let format = null;
-      if (type.format) {
-        if (!(type.format in FORMATS)) {
-          throw new Error(`Internal error: Invalid string format ${type.format}`);
-        }
-        format = FORMATS[type.format];
-      }
-      return new StringType(type, enumeration,
-                            type.minLength || 0,
-                            type.maxLength || Infinity,
-                            pattern,
-                            format);
-    } else if (type.type == "object" && "functions" in type) {
-      // NOTE: "events" and "properties" are currently ignored, because they are used
-      // in the DevTools schema files, but they are not currently used by anything in the
-      // initial set of supported DevTools APIs. See Bug 1290901 for rationale.
-      // Introducing a complete support of "events" and "properties" in the SubModuleType
-      // will be re-evaluated as part of Bug 1293298 and Bug 1293301.
-
-      checkTypeProperties("functions", "events", "properties");
-
-      // The path we pass in here is only used for error messages.
-      let functions = type.functions.map(fun => this.parseFunction(path.concat(type.id), fun));
-
-      return new SubModuleType(functions);
-    } else if (type.type == "object") {
-      let parseProperty = (type, extraProps = []) => {
-        return {
-          type: this.parseType(path, type,
-                               ["unsupported", "onError", "permissions", ...extraProps]),
-          optional: type.optional || false,
-          unsupported: type.unsupported || false,
-          onError: type.onError || null,
-        };
-      };
-
-      let properties = Object.create(null);
-      for (let propName of Object.keys(type.properties || {})) {
-        properties[propName] = parseProperty(type.properties[propName], ["optional"]);
-      }
-
-      let patternProperties = [];
-      for (let propName of Object.keys(type.patternProperties || {})) {
-        let pattern;
-        try {
-          pattern = parsePattern(propName);
-        } catch (e) {
-          throw new Error(`Internal error: Invalid property pattern ${JSON.stringify(propName)}`);
-        }
-
-        patternProperties.push({
-          pattern,
-          type: parseProperty(type.patternProperties[propName]),
-        });
-      }
-
-      let additionalProperties = null;
-      if (type.additionalProperties) {
-        additionalProperties = this.parseType(path, type.additionalProperties);
-      }
-
-      if ("$extend" in type) {
-        // Only allow extending "properties" and "patternProperties".
-        checkTypeProperties("properties", "patternProperties");
-      } else {
-        checkTypeProperties("properties", "additionalProperties", "patternProperties", "isInstanceOf");
-      }
-      return new ObjectType(type, properties, additionalProperties, patternProperties, type.isInstanceOf || null);
-    } else if (type.type == "array") {
-      checkTypeProperties("items", "minItems", "maxItems");
-      return new ArrayType(type, this.parseType(path, type.items),
-                           type.minItems || 0, type.maxItems || Infinity);
-    } else if (type.type == "number") {
-      checkTypeProperties();
-      return new NumberType(type);
-    } else if (type.type == "integer") {
-      checkTypeProperties("minimum", "maximum");
-      return new IntegerType(type, type.minimum || -Infinity, type.maximum || Infinity);
-    } else if (type.type == "boolean") {
-      checkTypeProperties();
-      return new BooleanType(type);
-    } else if (type.type == "function") {
-      let isAsync = !!type.async;
-      let parameters = null;
-      if ("parameters" in type) {
-        parameters = [];
-        for (let param of type.parameters) {
-          // Callbacks default to optional for now, because of promise
-          // handling.
-          let isCallback = isAsync && param.name == type.async;
-
-          parameters.push({
-            type: this.parseType(path, param, ["name", "optional"]),
-            name: param.name,
-            optional: param.optional == null ? isCallback : param.optional,
-          });
-        }
-      }
-
-      let hasAsyncCallback = false;
-      if (isAsync) {
-        if (parameters && parameters.length && parameters[parameters.length - 1].name == type.async) {
-          hasAsyncCallback = true;
-        }
-        if (type.returns) {
-          throw new Error("Internal error: Async functions must not have return values.");
-        }
-        if (type.allowAmbiguousOptionalArguments && !hasAsyncCallback) {
-          throw new Error("Internal error: Async functions with ambiguous arguments must declare the callback as the last parameter");
-        }
-      }
-
-      checkTypeProperties("parameters", "async", "returns");
-      return new FunctionType(type, parameters, isAsync, hasAsyncCallback);
-    } else if (type.type == "any") {
-      // Need to see what minimum and maximum are supposed to do here.
-      checkTypeProperties("minimum", "maximum");
-      return new AnyType(type);
+    let type = TYPES[schema.type];
+    if (!type) {
+      throw new Error(`Unexpected type ${schema.type}`);
     }
-    throw new Error(`Unexpected type ${type.type}`);
+    return type.parseSchema(schema, path, allowedProperties);
   },
 
   parseFunction(path, fun) {
     let f = new FunctionEntry(fun, path, fun.name,
-                              this.parseType(path, fun,
-                                             ["name", "unsupported", "returns",
-                                              "permissions",
-                                              "allowAmbiguousOptionalArguments"]),
+                              this.parseSchema(fun, path,
+                                               ["name", "unsupported", "returns",
+                                                "permissions",
+                                                "allowAmbiguousOptionalArguments"]),
                               fun.unsupported || false,
                               fun.allowAmbiguousOptionalArguments || false,
                               fun.returns || null,
                               fun.permissions || null);
     return f;
   },
 
   loadType(namespaceName, type) {
     if ("$extend" in type) {
       this.extendType(namespaceName, type);
     } else {
-      this.register(namespaceName, type.id, this.parseType([namespaceName], type, ["id"]));
+      this.register(namespaceName, type.id, this.parseSchema(type, [namespaceName], ["id"]));
     }
   },
 
   extendType(namespaceName, type) {
     let ns = Schemas.namespaces.get(namespaceName);
     let targetType = ns && ns.get(type.$extend);
 
     // Only allow extending object and choices types for now.
     if (targetType instanceof ObjectType) {
       type.type = "object";
     } else if (!targetType) {
       throw new Error(`Internal error: Attempt to extend a nonexistant type ${type.$extend}`);
     } else if (!(targetType instanceof ChoiceType)) {
       throw new Error(`Internal error: Attempt to extend a non-extensible type ${type.$extend}`);
     }
 
-    let parsed = this.parseType([namespaceName], type, ["$extend"]);
+    let parsed = this.parseSchema(type, [namespaceName], ["$extend"]);
     if (parsed.constructor !== targetType.constructor) {
       throw new Error(`Internal error: Bad attempt to extend ${type.$extend}`);
     }
 
     targetType.extend(parsed);
   },
 
   loadProperty(namespaceName, name, prop) {
@@ -1597,45 +1732,45 @@ this.Schemas = {
         this.register(namespaceName, name, new SubModuleProperty(prop, name, namespaceName, prop.$ref,
                                                                  prop.properties || {}));
       }
     } else if ("value" in prop) {
       this.register(namespaceName, name, new ValueProperty(prop, name, prop.value));
     } else {
       // We ignore the "optional" attribute on properties since we
       // don't inject anything here anyway.
-      let type = this.parseType([namespaceName], prop, ["optional", "writable"]);
+      let type = this.parseSchema(prop, [namespaceName], ["optional", "writable"]);
       this.register(namespaceName, name, new TypeProperty(prop, namespaceName, name, type, prop.writable || false));
     }
   },
 
   loadFunction(namespaceName, fun) {
     let f = this.parseFunction([namespaceName], fun);
     this.register(namespaceName, fun.name, f);
   },
 
   loadEvent(namespaceName, event) {
     let extras = event.extraParameters || [];
     extras = extras.map(param => {
       return {
-        type: this.parseType([namespaceName], param, ["name", "optional"]),
+        type: this.parseSchema(param, [namespaceName], ["name", "optional"]),
         name: param.name,
         optional: param.optional || false,
       };
     });
 
     // We ignore these properties for now.
     /* eslint-disable no-unused-vars */
     let returns = event.returns;
     let filters = event.filters;
     /* eslint-enable no-unused-vars */
 
-    let type = this.parseType([namespaceName], event,
-                              ["name", "unsupported", "permissions",
-                               "extraParameters", "returns", "filters"]);
+    let type = this.parseSchema(event, [namespaceName],
+                                ["name", "unsupported", "permissions",
+                                 "extraParameters", "returns", "filters"]);
 
     let e = new Event(event, [namespaceName], event.name, type, extras,
                       event.unsupported || false,
                       event.permissions || null);
     this.register(namespaceName, event.name, e);
   },
 
   init() {
@@ -1678,23 +1813,23 @@ this.Schemas = {
   parseSchemas() {
     Object.defineProperty(this, "namespaces", {
       enumerable: true,
       configurable: true,
       value: new Map(),
     });
 
     for (let json of this.schemaJSON.values()) {
-      this.parseSchema(json);
+      this.loadSchema(json);
     }
 
     return this.namespaces;
   },
 
-  parseSchema(json) {
+  loadSchema(json) {
     for (let namespace of json) {
       let name = namespace.namespace;
 
       let types = namespace.types || [];
       for (let type of types) {
         this.loadType(name, type);
       }
 
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
@@ -211,19 +211,24 @@ add_task(function* test_sendNativeMessag
 
   yield extension.unload();
 });
 
 // Test calling Port.disconnect()
 add_task(function* test_disconnect() {
   function background() {
     let port = browser.runtime.connectNative("echo");
-    port.onMessage.addListener(msg => {
+    port.onMessage.addListener((msg, msgPort) => {
+      browser.test.assertEq(port, msgPort, "onMessage handler should receive the port as the second argument");
       browser.test.sendMessage("message", msg);
     });
+    port.onDisconnect.addListener(msgPort => {
+      browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the second argument");
+      browser.test.sendMessage("disconnected");
+    });
     browser.test.onMessage.addListener((what, payload) => {
       if (what == "send") {
         if (payload._json) {
           let json = payload._json;
           payload.toJSON = () => json;
           delete payload._json;
         }
         port.postMessage(payload);
@@ -259,16 +264,18 @@ add_task(function* test_disconnect() {
 
   let procCount = yield getSubprocessCount();
   equal(procCount, 1, "subprocess is running");
 
   extension.sendMessage("disconnect");
   response = yield extension.awaitMessage("disconnect-result");
   equal(response.success, true, "disconnect succeeded");
 
+  yield extension.awaitMessage("disconnected");
+
   do_print("waiting for subprocess to exit");
   yield waitForSubprocessExit();
   procCount = yield getSubprocessCount();
   equal(procCount, 0, "subprocess is no longer running");
 
   extension.sendMessage("disconnect");
   response = yield extension.awaitMessage("disconnect-result");
   equal(response.success, false, "second call to disconnect failed");
--- a/toolkit/components/url-classifier/HashStore.cpp
+++ b/toolkit/components/url-classifier/HashStore.cpp
@@ -546,17 +546,19 @@ Merge(ChunkSet* aStoreChunks,
         return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Chunks can be empty, but we should still report we have them
   // to make the chunkranges continuous.
   aStoreChunks->Merge(aUpdateChunks);
 
-  aStorePrefixes->AppendElements(adds, fallible);
+  if (!aStorePrefixes->AppendElements(adds, fallible))
+    return NS_ERROR_OUT_OF_MEMORY;
+
   EntrySort(*aStorePrefixes);
 
   return NS_OK;
 }
 
 nsresult
 HashStore::ApplyUpdate(TableUpdate &aUpdate)
 {
--- a/toolkit/content/tests/chrome/bug304188_window.xul
+++ b/toolkit/content/tests/chrome/bug304188_window.xul
@@ -74,17 +74,17 @@ find-menu appears in editor element whic
 
       ok(gFindBar.hidden,
          "Findfield should have stayed hidden after entering editor test");
     }
 
     function* enterStringIntoEditor(aString) {
       for (let i = 0; i < aString.length; i++) {
         yield ContentTask.spawn(gBrowser, { charCode: aString.charCodeAt(i) }, function* (args) {
-          let event = content.document.createEvent("KeyEvents");
+          let event = content.document.createEvent("KeyboardEvent");
           event.initKeyEvent("keypress", true, true, null, false, false,
                              false, false, 0, args.charCode);
           content.document.body.dispatchEvent(event);
         });
       }
     }
   ]]></script>
 
--- a/toolkit/content/tests/chrome/bug331215_window.xul
+++ b/toolkit/content/tests/chrome/bug331215_window.xul
@@ -73,17 +73,17 @@
       yield enterStringIntoFindField("a");
       ok(gFindBar._findField.getAttribute("status") != "notfound",
          "Findfield status attribute should not have been 'notfound'" +
          " after entering latest");
     }
 
     function* enterStringIntoFindField(aString) {
       for (let i = 0; i < aString.length; i++) {      
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         let promise = new Promise(resolve => {
           let listener = {
             onFindResult: function() {
               gFindBar.browser.finder.removeResultListener(listener);
               resolve();
             }
           };
           gFindBar.browser.finder.addResultListener(listener);
--- a/toolkit/content/tests/chrome/bug360437_window.xul
+++ b/toolkit/content/tests/chrome/bug360437_window.xul
@@ -100,17 +100,17 @@
         };
         gFindBar.browser.finder.addResultListener(listener);
       });
     }
 
     function promiseEnterStringIntoFindField(str) {
       let promise = promiseFindResult(str);
       for (let i = 0; i < str.length; i++) {
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, str.charCodeAt(i));
         gFindBar._findField.inputField.dispatchEvent(event);
       }
       return promise;
     }
   ]]></script>
   <textbox id="textbox"/>
--- a/toolkit/content/tests/chrome/bug429723_window.xul
+++ b/toolkit/content/tests/chrome/bug429723_window.xul
@@ -33,17 +33,17 @@
         gBrowser.addEventListener("pageshow", onPageShow, false);
         gBrowser.loadURI("data:text/html,<h2 id='h2'>mozilla</h2>");
       }
       setTimeout(_delayedOnLoad, 1000);
     }
 
     function enterStringIntoFindField(aString) {
       for (var i=0; i < aString.length; i++) {
-        var event = document.createEvent("KeyEvents");
+        var event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, aString.charCodeAt(i));
         gFindBar._findField.inputField.dispatchEvent(event);
       }
     }
 
     function onPageShow() {
       gBrowser.removeEventListener("pageshow", onPageShow, false);
@@ -59,17 +59,17 @@
       enterStringIntoFindField(searchStr);
 
       // Highlight search term
       var highlight = gFindBar.getElement("highlight");
       if (!highlight.checked)
         highlight.click();
 
       // Delete search term
-      var event = document.createEvent("KeyEvents");
+      var event = document.createEvent("KeyboardEvent");
       event.initKeyEvent("keypress", true, true, null, false, false,
                          false, false, KeyEvent.DOM_VK_BACK_SPACE, 0);
       gFindBar._findField.inputField.dispatchEvent(event);
 
       var notRed = !findField.hasAttribute("status") || 
                    (findField.getAttribute("status") != "notfound");
       ok(notRed, "Find Bar textbox is correct colour");
       finish();
--- a/toolkit/content/tests/chrome/findbar_entireword_window.xul
+++ b/toolkit/content/tests/chrome/findbar_entireword_window.xul
@@ -149,17 +149,17 @@
       yield testQuickfind(suite.testQuickfind);
     }
 
     var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) {
       for (let promise, i = 0; i < str.length; i++) {
         if (waitForResult) {
           promise = promiseFindResult();
         }
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, str.charCodeAt(i));
         gFindBar._findField.inputField.dispatchEvent(event);
         if (waitForResult) {
           yield promise;
         }
       }
     });
@@ -243,17 +243,17 @@
       yield* testIterator(tests);
 
       gFindBar.close();
     }
 
     function* testQuickfind(tests) {
       yield ContentTask.spawn(gBrowser, null, function* () {
         let document = content.document;
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, "/".charCodeAt(0));
         document.documentElement.dispatchEvent(event);
       });
 
       ok(!gFindBar.hidden, "testQuickfind: failed to open findbar");
       ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
         "testQuickfind: find field is not focused");
--- a/toolkit/content/tests/chrome/findbar_events_window.xul
+++ b/toolkit/content/tests/chrome/findbar_events_window.xul
@@ -106,17 +106,17 @@
     }
 
     function* testFind() {
       info("Testing normal find.");
       let query = "t";
       let promise = once(gFindBar, "find");
 
       // Put some text in the find box.
-      let event = document.createEvent("KeyEvents");
+      let event = document.createEvent("KeyboardEvent");
       event.initKeyEvent("keypress", true, true, null, false, false,
                          false, false, 0, query.charCodeAt(0));
       gFindBar._findField.inputField.dispatchEvent(event);
 
       let e = yield promise;
       ok(e.detail.query === query, "find event query should match '" + query + "'");
       // Since we're preventing the default make sure nothing was selected.
       yield checkSelection();
--- a/toolkit/content/tests/chrome/findbar_window.xul
+++ b/toolkit/content/tests/chrome/findbar_window.xul
@@ -253,17 +253,17 @@
       });
     }
 
     var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) {
       for (let promise, i = 0; i < str.length; i++) {
         if (waitForResult) {
           promise = promiseFindResult();
         }
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, str.charCodeAt(i));
         gFindBar._findField.inputField.dispatchEvent(event);
         if (waitForResult) {
           yield promise;
         }
       }
     });
@@ -400,17 +400,17 @@
       });
     }
 
     function* testQuickFindLink() {
       yield clearFocus();
 
       yield ContentTask.spawn(gBrowser, null, function* () {
         let document = content.document;
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, "'".charCodeAt(0));
         document.documentElement.dispatchEvent(event);
       });
 
       ok(!gFindBar.hidden, "testQuickFindLink: failed to open findbar");
       ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
          "testQuickFindLink: find field is not focused");
@@ -482,17 +482,17 @@
       ok(!highlightButton.checked, "testFindWithHighlight: Highlight All should be unchecked.");
     }
 
     function* testQuickFindText() {
       yield clearFocus();
 
       yield ContentTask.spawn(gBrowser, null, function* () {
         let document = content.document;
-        let event = document.createEvent("KeyEvents");
+        let event = document.createEvent("KeyboardEvent");
         event.initKeyEvent("keypress", true, true, null, false, false,
                            false, false, 0, "/".charCodeAt(0));
         document.documentElement.dispatchEvent(event);
       });
 
       ok(!gFindBar.hidden, "testQuickFindText: failed to open findbar");
       ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
         "testQuickFindText: find field is not focused");
--- a/toolkit/content/tests/chrome/window_browser_drop.xul
+++ b/toolkit/content/tests/chrome/window_browser_drop.xul
@@ -45,17 +45,17 @@ function doDropAndStopLoad(browser, data
         }
       },
       QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
     };
     wp.addProgressListener(progressListener, wp.NOTIFY_STATE_WINDOW);
 
     let dataTransfer = new content.DataTransfer("dragstart", false);
     dataTransfer.mozSetDataAt(data.type, data.data, 0);
-    let event = content.document.createEvent("DragEvents");
+    let event = content.document.createEvent("DragEvent");
     event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
                         false, false, false, false, 0, null, dataTransfer);
     content.document.body.dispatchEvent(event);
     let nameGetter = {};
     try {
       Services.droppedLinkHandler.dropLink(event, nameGetter, true);
       nameReturned = nameGetter.value;
     } catch (ex) {
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -782,17 +782,17 @@
 
       <method name="_dispatchKeypressEvent">
         <parameter name="aTarget"/>
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (!aTarget)
             return;
 
-          let event = document.createEvent("KeyEvents");
+          let event = document.createEvent("KeyboardEvent");
           event.initKeyEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable,
                              aEvent.view, aEvent.ctrlKey, aEvent.altKey,
                              aEvent.shiftKey, aEvent.metaKey, aEvent.keyCode,
                              aEvent.charCode);
           aTarget.dispatchEvent(event);
         ]]></body>
       </method>
 
--- a/toolkit/modules/tests/browser/browser_FinderHighlighter.js
+++ b/toolkit/modules/tests/browser/browser_FinderHighlighter.js
@@ -41,17 +41,17 @@ function promiseFindResult(findbar, str 
     };
     findbar.browser.finder.addResultListener(listener);
   });
 }
 
 function promiseEnterStringIntoFindField(findbar, str) {
   let promise = promiseFindResult(findbar, str);
   for (let i = 0; i < str.length; i++) {
-    let event = document.createEvent("KeyEvents");
+    let event = document.createEvent("KeyboardEvent");
     event.initKeyEvent("keypress", true, true, null, false, false,
                        false, false, 0, str.charCodeAt(i));
     findbar._findField.inputField.dispatchEvent(event);
   }
   return promise;
 }
 
 function promiseTestHighlighterOutput(browser, word, expectedResult, extraTest = () => {}) {
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -117,16 +117,18 @@ const MAX_TIMEOUT_RUNS = 20000;
 // Time in seconds the helper application should sleep before exiting. The
 // helper can also be made to exit by writing |finish| to its input file.
 const HELPER_SLEEP_TIMEOUT = 180;
 
 // Maximum number of milliseconds the process that is launched can run before
 // the test will try to kill it.
 const APP_TIMER_TIMEOUT = 120000;
 
+const FILE_IN_USE_TIMEOUT_MS = 1000;
+
 const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1";
 
 const LOG_FUNCTION = do_print;
 
 const gHTTPHandlerPath = "updates.xml";
 
 // This default value will be overridden when using the http server.
 var gURLData = URL_HOST + "/";
@@ -1618,35 +1620,55 @@ function copyTestUpdaterForRunUsingUpdat
     updater.append("Contents");
     updater.append("MacOS");
     updater.append("org.mozilla.updater");
   }
   return updater;
 }
 
 /**
- * Logs the contents of an update log.
+ * Logs the contents of an update log and for maintenance service tests this
+ * will log the contents of the latest maintenanceservice.log.
  *
  * @param   aLogLeafName
- *          The leaf name of the log.
+ *          The leaf name of the update log.
  */
 function logUpdateLog(aLogLeafName) {
   let updateLog = getUpdateLog(aLogLeafName);
   if (updateLog.exists()) {
     // xpcshell tests won't display the entire contents so log each line.
     let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n");
     updateLogContents = replaceLogPaths(updateLogContents);
     let aryLogContents = updateLogContents.split("\n");
     logTestInfo("contents of " + updateLog.path + ":");
     aryLogContents.forEach(function RU_LC_FE(aLine) {
       logTestInfo(aLine);
     });
   } else {
     logTestInfo("update log doesn't exist, path: " + updateLog.path);
   }
+
+  if (IS_SERVICE_TEST) {
+    let serviceLog = getMaintSvcDir();
+    serviceLog.append("logs");
+    serviceLog.append("maintenanceservice.log");
+    if (serviceLog.exists()) {
+      // xpcshell tests won't display the entire contents so log each line.
+      let serviceLogContents = readFileBytes(serviceLog).replace(/\r\n/g, "\n");
+      serviceLogContents = replaceLogPaths(serviceLogContents);
+      let aryLogContents = serviceLogContents.split("\n");
+      logTestInfo("contents of " + serviceLog.path + ":");
+      aryLogContents.forEach(function RU_LC_FE(aLine) {
+        logTestInfo(aLine);
+      });
+    } else {
+      logTestInfo("maintenance service log doesn't exist, path: " +
+                  serviceLog.path);
+    }
+  }
 }
 
 /**
  * Launches the updater binary or the service to apply an update for updater
  * tests. For non-service tests runUpdateUsingUpdater will be called and for
  * service tests runUpdateUsingService will be called.
  *
  * @param   aExpectedStatus
@@ -1899,17 +1921,26 @@ function stageUpdate() {
  * present after staging and update for updater tests and then calls
  * stageUpdateFinished.
  *
  * @param   aUpdateState
  *          The update state received by the observer notification.
  */
 function checkUpdateStagedState(aUpdateState) {
   if (IS_WIN) {
-    waitForApplicationStop(FILE_UPDATER_BIN);
+    if (IS_SERVICE_TEST) {
+      waitForServiceStop(false);
+    } else {
+      let updater = getApplyDirFile(FILE_UPDATER_BIN, true);
+      if (isFileInUse(updater)) {
+        do_timeout(FILE_IN_USE_TIMEOUT_MS,
+                   checkUpdateStagedState.bind(null, aUpdateState));
+        return;
+      }
+    }
   }
 
   Assert.equal(aUpdateState, STATE_AFTER_STAGE,
                "the notified state" + MSG_SHOULD_EQUAL);
 
   if (!gStagingRemovedUpdate) {
     Assert.equal(readStatusState(), STATE_AFTER_STAGE,
                  "the status file state" + MSG_SHOULD_EQUAL);
@@ -2330,34 +2361,16 @@ function waitForApplicationStop(aApplica
   let args = ["wait-for-application-exit", aApplication, "120"];
   let exitValue = runTestHelperSync(args);
   Assert.equal(exitValue, 0,
                "the process should have stopped, process name: " +
                aApplication);
 }
 
 /**
- * Checks if an application is running.
- *
- * @param   aApplication
- *          The application binary name to check if it is running.
- */
-function isProcessRunning(aApplication) {
-  if (!IS_WIN) {
-    do_throw("Windows only function called by a different platform!");
-  }
-
-  debugDump("checking if " + aApplication + " is running");
-  // Use the helper bin to ensure the application is stopped. If not stopped,
-  // then wait for it to stop (at most 120 seconds).
-  let args = ["is-process-running", aApplication];
-  let exitValue = runTestHelperSync(args);
-  return exitValue;
-}
-/**
  * Helper function for updater tests for launching the updater using the
  * maintenance service to apply a mar file. When complete runUpdateFinished
  * will be called.
  *
  * @param   aExpectedStatus
  *          The expected value of update.status when the test finishes.
  * @param   aSwitchApp
  *          If true the update should switch the application with an updated
@@ -2385,25 +2398,18 @@ function runUpdateUsingService(aExpected
   function readServiceLogFile() {
     let file = getMaintSvcDir();
     file.append("logs");
     file.append("maintenanceservice.log");
     return readFile(file);
   }
 
   function checkServiceUpdateFinished() {
-    if (isProcessRunning(FILE_MAINTENANCE_SERVICE_BIN)) {
-      do_execute_soon(checkServiceUpdateFinished);
-      return;
-    }
-
-    if (isProcessRunning(FILE_UPDATER_BIN)) {
-      do_execute_soon(checkServiceUpdateFinished);
-      return;
-    }
+    waitForApplicationStop(FILE_MAINTENANCE_SERVICE_BIN);
+    waitForApplicationStop(FILE_UPDATER_BIN);
 
     // Wait for the expected status
     let status;
     try {
       status = readStatusFile();
     } catch (e) {
       do_execute_soon(checkServiceUpdateFinished);
       return;
@@ -3484,53 +3490,75 @@ function checkCallbackServiceLog() {
     do_execute_soon(checkCallbackServiceLog);
     return;
   }
   Assert.ok(true, "the callback service log contents" + MSG_SHOULD_EQUAL);
 
   waitForFilesInUse();
 }
 
-// Waits until files that are in use that break tests are no longer in use and
-// then calls doTestFinish to end the test.
+/**
+ * Helper function to check if a file is in use on Windows by making a copy of
+ * a file and attempting to delete the original file. If the deletion is
+ * successful the copy of the original file is renamed to the original file's
+ * name and if the deletion is not successful the copy of the original file is
+ * deleted.
+ *
+ * @param   aFile
+ *          An nsIFile for the file to be checked if it is in use.
+ * @return  true if the file can't be deleted and false otherwise.
+ */
+function isFileInUse(aFile) {
+  if (!IS_WIN) {
+    do_throw("Windows only function called by a different platform!");
+  }
+
+  if (!aFile.exists()) {
+    debugDump("file does not exist, path: " + aFile.path);
+    return false;
+  }
+
+  let fileBak = aFile.parent;
+  fileBak.append(aFile.leafName + ".bak");
+  try {
+    if (fileBak.exists()) {
+      fileBak.remove(false);
+    }
+    aFile.copyTo(aFile.parent, fileBak.leafName);
+    aFile.remove(false);
+    fileBak.moveTo(aFile.parent, aFile.leafName);
+    debugDump("file is not in use, path: " + aFile.path);
+    return false;
+  } catch (e) {
+    debugDump("file in use, path: " + aFile.path + ", exception: " + e);
+    try {
+      if (fileBak.exists()) {
+        fileBak.remove(false);
+      }
+    } catch (e) {
+      logTestInfo("unable to remove backup file, path: " +
+                  fileBak.path + ", exception: " + e);
+    }
+  }
+  return true;
+}
+
+/**
+ * Waits until files that are in use that break tests are no longer in use and
+ * then calls doTestFinish to end the test.
+ */
 function waitForFilesInUse() {
   if (IS_WIN) {
-    let appBin = getApplyDirFile(FILE_APP_BIN, true);
-    let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true);
-    let helper = getApplyDirFile("uninstall/helper.exe", true);
-    let updater = getApplyDirFile(FILE_UPDATER_BIN, true);
-    let files = [appBin, updater, maintSvcInstaller, helper];
-
-    for (let i = 0; i < files.length; ++i) {
-      let file = files[i];
-      let fileBak = file.parent.clone();
-      if (file.exists()) {
-        fileBak.append(file.leafName + ".bak");
-        try {
-          if (fileBak.exists()) {
-            fileBak.remove(false);
-          }
-          file.copyTo(fileBak.parent, fileBak.leafName);
-          file.remove(false);
-          fileBak.moveTo(file.parent, file.leafName);
-          debugDump("file is not in use, path: " + file.path);
-        } catch (e) {
-          debugDump("will try again to remove file in use, path: " +
-                    file.path + ", exception: " + e);
-          try {
-            if (fileBak.exists()) {
-              fileBak.remove(false);
-            }
-          } catch (e) {
-            logTestInfo("unable to remove backup file, path: " +
-                        fileBak.path + ", exception: " + e);
-          }
-          do_execute_soon(waitForFilesInUse);
-          return;
-        }
+    let fileNames = [FILE_APP_BIN, FILE_UPDATER_BIN,
+                     FILE_MAINTENANCE_SERVICE_INSTALLER_BIN];
+    for (let i = 0; i < fileNames.length; ++i) {
+      let file = getApplyDirFile(fileNames[i], true);
+      if (isFileInUse(file)) {
+        do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForFilesInUse);
+        return;
       }
     }
   }
 
   debugDump("calling doTestFinish");
   doTestFinish();
 }
 
@@ -3964,17 +3992,17 @@ function runUpdateUsingApp(aExpectedStat
       }
       Assert.equal(gProcess.exitValue, 0,
                    "the application process exit value should be 0");
       Assert.equal(aTopic, "process-finished",
                    "the application process observer topic should be " +
                    "process-finished");
 
       if (IS_SERVICE_TEST) {
-        waitForServiceStop();
+        waitForServiceStop(false);
       }
 
       do_execute_soon(afterAppExits);
     },
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
   };
 
   function afterAppExits() {
@@ -4058,23 +4086,25 @@ const gAppTimerCallback = {
 
 /**
  * The update-staged observer for the call to nsIUpdateProcessor:processUpdate.
  */
 const gUpdateStagedObserver = {
   observe: function(aSubject, aTopic, aData) {
     debugDump("observe called with topic: " + aTopic + ", data: " + aData);
     if (aTopic == "update-staged") {
+      Services.obs.removeObserver(gUpdateStagedObserver, "update-staged");
       // The environment is reset after the update-staged observer topic because
       // processUpdate in nsIUpdateProcessor uses a new thread and clearing the
       // environment immediately after calling processUpdate can clear the
       // environment before the updater is launched.
       resetEnvironment();
-      Services.obs.removeObserver(gUpdateStagedObserver, "update-staged");
-      checkUpdateStagedState(aData);
+      // Use do_execute_soon to prevent any failures from propagating to the
+      // update service.
+      do_execute_soon(checkUpdateStagedState.bind(null, aData));
     }
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
 };
 
 /**
  * Sets the environment that will be used by the application process when it is
  * launched.
--- a/widget/android/ThumbnailHelper.h
+++ b/widget/android/ThumbnailHelper.h
@@ -131,35 +131,30 @@ class ThumbnailHelper final
         nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
         RefPtr<nsPresContext> presContext;
 
         if (!docShell || NS_FAILED(docShell->GetPresContext(
                 getter_AddRefs(presContext))) || !presContext) {
             return nullptr;
         }
 
-        MOZ_ASSERT(gfxPlatform::GetPlatform()->
-                           SupportsAzureContentForType(BackendType::CAIRO),
-                   "Need BackendType::CAIRO support");
-
         uint8_t* const data = static_cast<uint8_t*>(aData->Address());
         if (!data) {
             return nullptr;
         }
 
         const bool is24bit = !AndroidBridge::Bridge() ||
                 AndroidBridge::Bridge()->GetScreenDepth() == 24;
         const uint32_t stride = aThumbWidth * (is24bit ? 4 : 2);
 
-        RefPtr<DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
-                BackendType::CAIRO,
+        RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForData(
                 data,
                 IntSize(aThumbWidth, aThumbHeight),
                 stride,
-                is24bit ? SurfaceFormat::B8G8R8X8
+                is24bit ? SurfaceFormat::B8G8R8A8
                         : SurfaceFormat::R5G6B5_UINT16);
 
         if (!dt || !dt->IsValid()) {
             return nullptr;
         }
 
         nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
         RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);