Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Wed, 25 Apr 2018 12:36:04 +0300
changeset 469045 a83a4ef50f6ca754ec451320dfefbffa707bad1a
parent 469013 e786f1edbbefa7dadbb2e0ba5b7939f2bf4f1273 (current diff)
parent 469044 f9b99c0aa7fc4f061fe52332bb9bbcbb769ad2d9 (diff)
child 469046 7f6a582f00bfb5d0acb8d8bf7f8c79ca37c99b65
child 469053 8505d047afa7564b0b97ff83a2768af443c7c9ef
child 469157 6696fd50114a8c105771f1e87e0b76cbf5761c26
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
a83a4ef50f6c / 61.0a1 / 20180425100122 / files
nightly linux64
a83a4ef50f6c / 61.0a1 / 20180425100122 / files
nightly mac
a83a4ef50f6c / 61.0a1 / 20180425100122 / files
nightly win32
a83a4ef50f6c / 61.0a1 / 20180425100122 / files
nightly win64
a83a4ef50f6c / 61.0a1 / 20180425100122 / 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 mozilla-central. a=merge
accessible/jsat/AccessFu.css
ipc/chromium/src/base/pickle.cc
ipc/glue/Faulty.cpp
ipc/glue/Faulty.h
testing/mozharness/configs/multi_locale/date_android-armv6.json
testing/mozharness/configs/multi_locale/date_android-x86.json
testing/mozharness/configs/multi_locale/date_android.json
testing/mozharness/configs/single_locale/date.py
testing/mozharness/configs/single_locale/date_android-api-16.py
testing/mozharness/configs/single_locale/dev-mozilla-beta_devedition.py
toolkit/components/extensions/ExtensionCommon.jsm
toolkit/components/extensions/parent/ext-backgroundPage.js
toolkit/components/extensions/parent/ext-toolkit.js
toolkit/components/extensions/parent/ext-webRequest.js
toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
toolkit/modules/addons/WebRequest.jsm
--- a/.cron.yml
+++ b/.cron.yml
@@ -7,72 +7,66 @@
 jobs:
     - name: nightly-desktop
       job:
           type: decision-task
           treeherder-symbol: Nd
           target-tasks-method: nightly_desktop
       run-on-projects:
           - mozilla-central
-          - date
       when:
           by-project:
               # Match buildbot starts for now
               date: [{hour: 15, minute: 0}]
               mozilla-central: [{hour: 10, minute: 0}, {hour: 22, minute: 0}]
               # No default
 
     - name: nightly-desktop-linux
       job:
           type: decision-task
           treeherder-symbol: Nd-Ln
           target-tasks-method: nightly_linux
       run-on-projects:
           - mozilla-central
-          - date
       when: []  # never (hook only)
 
     - name: nightly-desktop-osx
       job:
           type: decision-task
           treeherder-symbol: Nd-OSX
           target-tasks-method: nightly_macosx
       run-on-projects:
           - mozilla-central
-          - date
       when: []  # never (hook only)
 
     - name: nightly-desktop-win32
       job:
           type: decision-task
           treeherder-symbol: Nd-win32
           target-tasks-method: nightly_win32
       run-on-projects:
           - mozilla-central
-          - date
       when: []  # never (hook only)
 
     - name: nightly-desktop-win64
       job:
           type: decision-task
           treeherder-symbol: Nd-win64
           target-tasks-method: nightly_win64
       run-on-projects:
           - mozilla-central
-          - date
       when: []  # never (hook only)
 
     - name: nightly-android
       job:
           type: decision-task
           treeherder-symbol: Na
           target-tasks-method: nightly_fennec
       run-on-projects:
           - mozilla-central
-          - date
       when:
           by-project:
               # Match buildbot starts for now
               date: [{hour: 15, minute: 0}]
               mozilla-central: [{hour: 10, minute: 0}]
               # No default
 
     - name: nightly-mochitest-valgrind
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2321,16 +2321,17 @@ dependencies = [
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.57.2",
 ]
deleted file mode 100644
--- a/accessible/jsat/AccessFu.css
+++ /dev/null
@@ -1,59 +0,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/. */
-
-#virtual-cursor-box {
-  position: fixed;
-  border: 1px solid orange;
-  pointer-events: none;
-  display: none;
-  border-radius: 2px;
-  box-shadow: 1px 1px 1px #444;
-  display: none;
-  z-index: 10;
-}
-
-#virtual-cursor-box.show {
-  display: block;
-}
-
-#virtual-cursor-box > div {
-  border-radius: 1px;
-  box-shadow: inset 1px 1px 1px #444;
-  display: block;
-  box-sizing: border-box;
-  width: 100%;
-  height: 100%;
-  pointer-events: none;
-}
-
-#announce-box {
-  position: fixed;
-  width: 7.5em;
-  height: 5em;
-  top: calc(100% - 50% - 2.5em);
-  left: calc(100% - 50% - 3.75em);
-  pointer-events: none;
-  display: table;
-  font-size: 28pt;
-  font-weight: 700;
-  color: orange;
-  background-color: black;
-  border-radius: 0.25em;
-}
-
-#announce-box:not(.showing) {
-  opacity: 0.0;
-  -moz-transition: opacity 0.4s linear;
-}
-
-#announce-box.showing {
-  opacity: 1.0;
-  -moz-transition: opacity 0.2s linear;
-}
-
-#announce-box * {
-  text-align: center;
-  display: table-cell;
-  vertical-align: middle;
-}
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -3,16 +3,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["AccessFu"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
+ChromeUtils.defineModuleGetter(this, "Rect",
+                               "resource://gre/modules/Geometry.jsm");
 
 if (Utils.MozBuildApp === "mobile/android") {
   ChromeUtils.import("resource://gre/modules/Messaging.jsm");
 }
 
 const GECKOVIEW_MESSAGE = {
   ACTIVATE: "GeckoView:AccessibilityActivate",
   VIEW_FOCUSED: "GeckoView:AccessibilityViewFocused",
@@ -73,29 +75,20 @@ var AccessFu = {
     ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
     ChromeUtils.import("resource://gre/modules/accessibility/Presentation.jsm");
 
     for (let mm of Utils.AllMessageManagers) {
       this._addMessageListeners(mm);
       this._loadFrameScript(mm);
     }
 
-    // Add stylesheet
-    let stylesheetURL = "chrome://global/content/accessibility/AccessFu.css";
-    let stylesheet = Utils.win.document.createProcessingInstruction(
-      "xml-stylesheet", `href="${stylesheetURL}" type="text/css"`);
-    Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
-    this.stylesheet = Cu.getWeakReference(stylesheet);
-
     // Check for output notification
     this._notifyOutputPref =
       new PrefCache("accessibility.accessfu.notify_output");
 
-    Output.start();
-
     if (Utils.MozBuildApp === "mobile/android") {
       Utils.win.WindowEventDispatcher.registerListener(this,
         Object.values(GECKOVIEW_MESSAGE));
     }
 
     Services.obs.addObserver(this, "remote-browser-shown");
     Services.obs.addObserver(this, "inprocess-browser-shown");
     Utils.win.addEventListener("TabOpen", this);
@@ -115,25 +108,21 @@ var AccessFu = {
    */
   _disable: function _disable() {
     if (!this._enabled) {
       return;
     }
 
     this._enabled = false;
 
-    Utils.win.document.removeChild(this.stylesheet.get());
-
     for (let mm of Utils.AllMessageManagers) {
       mm.sendAsyncMessage("AccessFu:Stop");
       this._removeMessageListeners(mm);
     }
 
-    Output.stop();
-
     Utils.win.removeEventListener("TabOpen", this);
     Utils.win.removeEventListener("TabClose", this);
     Utils.win.removeEventListener("TabSelect", this);
 
     Services.obs.removeObserver(this, "remote-browser-shown");
     Services.obs.removeObserver(this, "inprocess-browser-shown");
 
     if (Utils.MozBuildApp === "mobile/android") {
@@ -172,30 +161,30 @@ var AccessFu = {
         break;
       case "AccessFu:DoScroll":
         this.Input.doScroll(aMessage.json);
         break;
     }
   },
 
   _output: function _output(aPresentationData, aBrowser) {
-    if (!Utils.isAliveAndVisible(
-      Utils.AccService.getAccessibleFor(aBrowser))) {
+    if (!aPresentationData || typeof aPresentationData == "string") {
+      // Either no android events to send or a string used for testing only.
       return;
     }
-    for (let presenter of aPresentationData) {
-      if (!presenter) {
-        continue;
-      }
+
+    if (!Utils.isAliveAndVisible(Utils.AccService.getAccessibleFor(aBrowser))) {
+      return;
+    }
 
-      try {
-        Output[presenter.type](presenter.details, aBrowser);
-      } catch (x) {
-        Logger.logException(x);
-      }
+    for (let evt of aPresentationData) {
+      Utils.win.WindowEventDispatcher.sendRequest({
+        ...evt,
+        type: "GeckoView:AccessibilityEvent"
+      });
     }
 
     if (this._notifyOutputPref.value) {
       Services.obs.notifyObservers(null, "accessibility-output",
                                    JSON.stringify(aPresentationData));
     }
   },
 
@@ -365,184 +354,16 @@ var AccessFu = {
       let dpr = win.devicePixelRatio;
 
       bounds = bounds.scale(1 / dpr, 1 / dpr);
       bounds = bounds.translate(-win.mozInnerScreenX, -win.mozInnerScreenY);
       return bounds.expandToIntegers();
     }
 };
 
-var Output = {
-  brailleState: {
-    startOffset: 0,
-    endOffset: 0,
-    text: "",
-    selectionStart: 0,
-    selectionEnd: 0,
-
-    init: function init(aOutput) {
-      if (aOutput && "output" in aOutput) {
-        this.startOffset = aOutput.startOffset;
-        this.endOffset = aOutput.endOffset;
-        // We need to append a space at the end so that the routing key
-        // corresponding to the end of the output (i.e. the space) can be hit to
-        // move the caret there.
-        this.text = aOutput.output + " ";
-        this.selectionStart = typeof aOutput.selectionStart === "number" ?
-                              aOutput.selectionStart : this.selectionStart;
-        this.selectionEnd = typeof aOutput.selectionEnd === "number" ?
-                            aOutput.selectionEnd : this.selectionEnd;
-
-        return { text: this.text,
-                 selectionStart: this.selectionStart,
-                 selectionEnd: this.selectionEnd };
-      }
-
-      return null;
-    },
-
-    adjustText: function adjustText(aText) {
-      let newBraille = [];
-      let braille = {};
-
-      let prefix = this.text.substring(0, this.startOffset).trim();
-      if (prefix) {
-        prefix += " ";
-        newBraille.push(prefix);
-      }
-
-      newBraille.push(aText);
-
-      let suffix = this.text.substring(this.endOffset).trim();
-      if (suffix) {
-        suffix = " " + suffix;
-        newBraille.push(suffix);
-      }
-
-      this.startOffset = braille.startOffset = prefix.length;
-      this.text = braille.text = newBraille.join("") + " ";
-      this.endOffset = braille.endOffset = braille.text.length - suffix.length;
-      braille.selectionStart = this.selectionStart;
-      braille.selectionEnd = this.selectionEnd;
-
-      return braille;
-    },
-
-    adjustSelection: function adjustSelection(aSelection) {
-      let braille = {};
-
-      braille.startOffset = this.startOffset;
-      braille.endOffset = this.endOffset;
-      braille.text = this.text;
-      this.selectionStart = braille.selectionStart =
-        aSelection.selectionStart + this.startOffset;
-      this.selectionEnd = braille.selectionEnd =
-        aSelection.selectionEnd + this.startOffset;
-
-      return braille;
-    }
-  },
-
-  start: function start() {
-    ChromeUtils.import("resource://gre/modules/Geometry.jsm");
-  },
-
-  stop: function stop() {
-    if (this.highlightBox) {
-      let highlightBox = this.highlightBox.get();
-      if (highlightBox) {
-        highlightBox.remove();
-      }
-      delete this.highlightBox;
-    }
-  },
-
-  B2G: function B2G(aDetails) {
-    Utils.dispatchChromeEvent("accessibility-output", aDetails);
-  },
-
-  Visual: function Visual(aDetail, aBrowser) {
-    switch (aDetail.eventType) {
-      case "viewport-change":
-      case "vc-change":
-      {
-        let highlightBox = null;
-        if (!this.highlightBox) {
-          let doc = Utils.win.document;
-          // Add highlight box
-          highlightBox = Utils.win.document.
-            createElementNS("http://www.w3.org/1999/xhtml", "div");
-          let parent = doc.body || doc.documentElement;
-          parent.appendChild(highlightBox);
-          highlightBox.id = "virtual-cursor-box";
-
-          // Add highlight inset for inner shadow
-          highlightBox.appendChild(
-            doc.createElementNS("http://www.w3.org/1999/xhtml", "div"));
-
-          this.highlightBox = Cu.getWeakReference(highlightBox);
-        } else {
-          highlightBox = this.highlightBox.get();
-        }
-
-        let padding = aDetail.padding;
-        let r = AccessFu.screenToClientBounds(aDetail.bounds);
-
-        // First hide it to avoid flickering when changing the style.
-        highlightBox.classList.remove("show");
-        highlightBox.style.top = (r.top - padding) + "px";
-        highlightBox.style.left = (r.left - padding) + "px";
-        highlightBox.style.width = (r.width + padding * 2) + "px";
-        highlightBox.style.height = (r.height + padding * 2) + "px";
-        highlightBox.classList.add("show");
-
-        break;
-      }
-      case "tabstate-change":
-      {
-        let highlightBox = this.highlightBox ? this.highlightBox.get() : null;
-        if (highlightBox) {
-          highlightBox.classList.remove("show");
-        }
-        break;
-      }
-    }
-  },
-
-  Android: function Android(aDetails, aBrowser) {
-    const ANDROID_VIEW_TEXT_CHANGED = 0x10;
-    const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
-
-    for (let androidEvent of aDetails) {
-      androidEvent.type = "GeckoView:AccessibilityEvent";
-
-      switch (androidEvent.eventType) {
-        case ANDROID_VIEW_TEXT_CHANGED:
-          androidEvent.brailleOutput = this.brailleState.adjustText(
-            androidEvent.text);
-          break;
-        case ANDROID_VIEW_TEXT_SELECTION_CHANGED:
-          androidEvent.brailleOutput = this.brailleState.adjustSelection(
-            androidEvent.brailleOutput);
-          break;
-        default:
-          androidEvent.brailleOutput = this.brailleState.init(
-            androidEvent.brailleOutput);
-          break;
-      }
-
-      Utils.win.WindowEventDispatcher.sendRequest(androidEvent);
-    }
-  },
-
-  Braille: function Braille(aDetails) {
-    Logger.debug("Braille output: " + aDetails.output);
-  }
-};
-
 var Input = {
   editState: {},
 
   moveToPoint: function moveToPoint(aRule, aX, aY) {
     // XXX: Bug 1013408 - There is no alignment between the chrome window's
     // viewport size and the content viewport size in Android. This makes
     // sending mouse events beyond its bounds impossible.
     if (Utils.MozBuildApp === "mobile/android") {
@@ -587,18 +408,17 @@ var Input = {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     let type = this.editState.editing ? "AccessFu:MoveCaret" :
                                         "AccessFu:MoveByGranularity";
     mm.sendAsyncMessage(type, aDetails);
   },
 
   activateCurrent: function activateCurrent(aData, aActivateIfKey = false) {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
-    let offset = aData && typeof aData.keyIndex === "number" ?
-                 aData.keyIndex - Output.brailleState.startOffset : -1;
+    let offset = 0;
 
     mm.sendAsyncMessage("AccessFu:Activate",
                         {offset, activateIfKey: aActivateIfKey});
   },
 
   setEditState: function setEditState(aEditState) {
     Logger.debug(() => { return ["setEditState", JSON.stringify(aEditState)]; });
     this.editState = aEditState;
--- a/accessible/jsat/Constants.jsm
+++ b/accessible/jsat/Constants.jsm
@@ -1,12 +1,28 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var EXPORTED_SYMBOLS = ["Roles", "Events", "Relations",
-                        "Filters", "States", "Prefilters"];
+                        "Filters", "States", "Prefilters", "AndroidEvents"];
+
+const AndroidEvents = {
+  ANDROID_VIEW_CLICKED: 0x01,
+  ANDROID_VIEW_LONG_CLICKED: 0x02,
+  ANDROID_VIEW_SELECTED: 0x04,
+  ANDROID_VIEW_FOCUSED: 0x08,
+  ANDROID_VIEW_TEXT_CHANGED: 0x10,
+  ANDROID_WINDOW_STATE_CHANGED: 0x20,
+  ANDROID_VIEW_HOVER_ENTER: 0x80,
+  ANDROID_VIEW_HOVER_EXIT: 0x100,
+  ANDROID_VIEW_SCROLLED: 0x1000,
+  ANDROID_VIEW_TEXT_SELECTION_CHANGED: 0x2000,
+  ANDROID_ANNOUNCEMENT: 0x4000,
+  ANDROID_VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
+  ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000,
+};
 
 function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) {
   let offset = aPrefix.length;
   for (var name in aObject) {
     if (name.indexOf(aPrefix) === 0) {
       aMap[name.slice(offset)] = aModifier ?
         aModifier(aObject[name]) : aObject[name];
     }
--- a/accessible/jsat/OutputGenerator.jsm
+++ b/accessible/jsat/OutputGenerator.jsm
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* exported UtteranceGenerator, BrailleGenerator */
+/* exported UtteranceGenerator */
 
 "use strict";
 
 const INCLUDE_DESC = 0x01;
 const INCLUDE_NAME = 0x02;
 const INCLUDE_VALUE = 0x04;
 const NAME_FROM_SUBTREE_RULE = 0x10;
 const IGNORE_EXPLICIT_NAME = 0x20;
@@ -21,17 +21,17 @@ ChromeUtils.defineModuleGetter(this, "Pr
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "Logger", // jshint ignore:line
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
   "resource://gre/modules/accessibility/Constants.jsm");
 
-var EXPORTED_SYMBOLS = ["UtteranceGenerator", "BrailleGenerator"]; // jshint ignore:line
+var EXPORTED_SYMBOLS = ["UtteranceGenerator"]; // jshint ignore:line
 
 var OutputGenerator = {
 
   defaultOutputOrder: OUTPUT_DESC_LAST,
 
   /**
    * Generates output for a PivotContext.
    * @param {PivotContext} aContext object that generates and caches
@@ -833,169 +833,8 @@ var UtteranceGenerator = {  // jshint ig
       });
 
       this._addName(utterance, aAccessible, aFlags);
       this._addLandmark(utterance, aAccessible);
 
       return utterance;
     }
 };
-
-var BrailleGenerator = {  // jshint ignore:line
-  __proto__: OutputGenerator, // jshint ignore:line
-
-  genForContext: function genForContext(aContext) {
-    let output = OutputGenerator.genForContext.apply(this, arguments);
-
-    let acc = aContext.accessible;
-
-    // add the static text indicating a list item; do this for both listitems or
-    // direct first children of listitems, because these are both common
-    // browsing scenarios
-    let addListitemIndicator = function addListitemIndicator(indicator = "*") {
-      output.unshift(indicator);
-    };
-
-    if (acc.indexInParent === 1 &&
-        acc.parent.role == Roles.LISTITEM &&
-        acc.previousSibling.role == Roles.STATICTEXT) {
-      if (acc.parent.parent && acc.parent.parent.DOMNode &&
-          acc.parent.parent.DOMNode.nodeName == "UL") {
-        addListitemIndicator();
-      } else {
-        addListitemIndicator(acc.previousSibling.name.trim());
-      }
-    } else if (acc.role == Roles.LISTITEM && acc.firstChild &&
-               acc.firstChild.role == Roles.STATICTEXT) {
-      if (acc.parent.DOMNode.nodeName == "UL") {
-        addListitemIndicator();
-      } else {
-        addListitemIndicator(acc.firstChild.name.trim());
-      }
-    }
-
-    return output;
-  },
-
-  objectOutputFunctions: {
-
-    __proto__: OutputGenerator.objectOutputFunctions, // jshint ignore:line
-
-    defaultFunc: function defaultFunc() {
-      return this.objectOutputFunctions._generateBaseOutput.apply(
-        this, arguments);
-    },
-
-    listitem: function listitem(aAccessible, aRoleStr, aState, aFlags) {
-      let braille = [];
-
-      this._addName(braille, aAccessible, aFlags);
-      this._addLandmark(braille, aAccessible);
-
-      return braille;
-    },
-
-    cell: function cell(aAccessible, aRoleStr, aState, aFlags, aContext) {
-      let braille = [];
-      let cell = aContext.getCellInfo(aAccessible);
-      if (cell) {
-        let addHeaders = function addHeaders(aBraille, aHeaders) {
-          if (aHeaders.length > 0) {
-            aBraille.push.apply(aBraille, aHeaders);
-          }
-        };
-
-        braille.push({
-          string: this._getOutputName("cellInfo"),
-          args: [cell.columnIndex + 1, cell.rowIndex + 1]
-        });
-
-        addHeaders(braille, cell.columnHeaders);
-        addHeaders(braille, cell.rowHeaders);
-      }
-
-      this._addName(braille, aAccessible, aFlags);
-      this._addLandmark(braille, aAccessible);
-      return braille;
-    },
-
-    columnheader: function columnheader() {
-      return this.objectOutputFunctions.cell.apply(this, arguments);
-    },
-
-    rowheader: function rowheader() {
-      return this.objectOutputFunctions.cell.apply(this, arguments);
-    },
-
-    statictext: function statictext(aAccessible) {
-      // Since we customize the list bullet's output, we add the static
-      // text from the first node in each listitem, so skip it here.
-      if (Utils.isListItemDecorator(aAccessible)) {
-        return [];
-      }
-
-      return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
-    },
-
-    _useStateNotRole:
-      function _useStateNotRole(aAccessible, aRoleStr, aState, aFlags) {
-        let braille = [];
-        this._addState(braille, aState, aRoleStr);
-        this._addName(braille, aAccessible, aFlags);
-        this._addLandmark(braille, aAccessible);
-
-        return braille;
-      },
-
-    switch: function braille_generator_object_output_functions_switch() {
-      return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
-    },
-
-    checkbutton: function checkbutton() {
-      return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
-    },
-
-    radiobutton: function radiobutton() {
-      return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
-    },
-
-    togglebutton: function togglebutton() {
-      return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
-    }
-  },
-
-  _getContextStart: function _getContextStart(aContext) {
-    if (aContext.accessible.parent.role == Roles.LINK) {
-      return [aContext.accessible.parent];
-    }
-
-    return [];
-  },
-
-  _getOutputName: function _getOutputName(aName) {
-    return OutputGenerator._getOutputName(aName) + "Abbr";
-  },
-
-  _addRole: function _addRole(aBraille, aAccessible, aRoleStr) {
-    if (this.mathmlRolesSet.has(aAccessible.role)) {
-      this._addMathRoles(aBraille, aAccessible, aRoleStr);
-    } else {
-      aBraille.push({string: this._getOutputName(aRoleStr)});
-    }
-  },
-
-  _addState: function _addState(aBraille, aState, aRoleStr) {
-    if (aState.contains(States.CHECKABLE)) {
-      aBraille.push({
-        string: aState.contains(States.CHECKED) ?
-          this._getOutputName("stateChecked") :
-          this._getOutputName("stateUnchecked")
-      });
-    }
-    if (aRoleStr === "toggle button") {
-      aBraille.push({
-        string: aState.contains(States.PRESSED) ?
-          this._getOutputName("statePressed") :
-          this._getOutputName("stateUnpressed")
-      });
-    }
-  }
-};
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -8,756 +8,301 @@
 
 ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "Logger", // jshint ignore:line
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "PivotContext", // jshint ignore:line
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "UtteranceGenerator", // jshint ignore:line
   "resource://gre/modules/accessibility/OutputGenerator.jsm");
-ChromeUtils.defineModuleGetter(this, "BrailleGenerator", // jshint ignore:line
-  "resource://gre/modules/accessibility/OutputGenerator.jsm");
 ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
   "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
   "resource://gre/modules/accessibility/Constants.jsm");
+ChromeUtils.defineModuleGetter(this, "AndroidEvents", // jshint ignore:line
+  "resource://gre/modules/accessibility/Constants.jsm");
 
 var EXPORTED_SYMBOLS = ["Presentation"]; // jshint ignore:line
 
-/**
- * The interface for all presenter classes. A presenter could be, for example,
- * a speech output module, or a visual cursor indicator.
- */
-function Presenter() {}
-
-Presenter.prototype = {
-  /**
-   * The type of presenter. Used for matching it with the appropriate output method.
-   */
-  type: "Base",
+class AndroidPresentor {
+  constructor() {
+    this.type = "Android";
+    this.displayedAccessibles = new WeakMap();
+  }
 
   /**
    * The virtual cursor's position changed.
    * @param {PivotContext} aContext the context object for the new pivot
    *   position.
    * @param {int} aReason the reason for the pivot change.
    *   See nsIAccessiblePivot.
    * @param {bool} aIsFromUserInput the pivot change was invoked by the user
    */
-  pivotChanged: function pivotChanged(aContext, aReason, aIsFromUserInput) {}, // jshint ignore:line
-
-  /**
-   * An object's action has been invoked.
-   * @param {nsIAccessible} aObject the object that has been invoked.
-   * @param {string} aActionName the name of the action.
-   */
-  actionInvoked: function actionInvoked(aObject, aActionName) {}, // jshint ignore:line
-
-  /**
-   * Text has changed, either by the user or by the system. TODO.
-   */
-  textChanged: function textChanged(aAccessible, aIsInserted, aStartOffset, // jshint ignore:line
-                                    aLength, aText, aModifiedText) {}, // jshint ignore:line
-
-  /**
-   * Text selection has changed. TODO.
-   */
-  textSelectionChanged: function textSelectionChanged(
-    aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {}, // jshint ignore:line
-
-  /**
-   * Selection has changed. TODO.
-   * @param {nsIAccessible} aObject the object that has been selected.
-   */
-  selectionChanged: function selectionChanged(aObject) {}, // jshint ignore:line
-
-  /**
-   * Name has changed.
-   * @param {nsIAccessible} aAccessible the object whose value has changed.
-   */
-  nameChanged: function nameChanged(aAccessible) {}, // jshint ignore: line
-
-  /**
-   * Value has changed.
-   * @param {nsIAccessible} aAccessible the object whose value has changed.
-   */
-  valueChanged: function valueChanged(aAccessible) {}, // jshint ignore:line
-
-  /**
-   * The tab, or the tab's document state has changed.
-   * @param {nsIAccessible} aDocObj the tab document accessible that has had its
-   *    state changed, or null if the tab has no associated document yet.
-   * @param {string} aPageState the state name for the tab, valid states are:
-   *    'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
-   */
-  tabStateChanged: function tabStateChanged(aDocObj, aPageState) {}, // jshint ignore:line
-
-  /**
-   * The current tab has changed.
-   * @param {PivotContext} aDocContext context object for tab's
-   *   document.
-   * @param {PivotContext} aVCContext context object for tab's current
-   *   virtual cursor position.
-   */
-  tabSelected: function tabSelected(aDocContext, aVCContext) {}, // jshint ignore:line
-
-  /**
-   * The viewport has changed, either a scroll, pan, zoom, or
-   *    landscape/portrait toggle.
-   * @param {Window} aWindow window of viewport that changed.
-   * @param {PivotContext} aCurrentContext context of last pivot change.
-   */
-  viewportChanged: function viewportChanged(aWindow, aCurrentContext) {}, // jshint ignore:line
-
-  /**
-   * We have entered or left text editing mode.
-   */
-  editingModeChanged: function editingModeChanged(aIsEditing) {}, // jshint ignore:line
-
-  /**
-   * Announce something. Typically an app state change.
-   */
-  announce: function announce(aAnnouncement) {}, // jshint ignore:line
-
-
-  /**
-   * User tried to move cursor forward or backward with no success.
-   * @param {string} aMoveMethod move method that was used (eg. 'moveNext').
-   */
-  noMove: function noMove(aMoveMethod) {},
-
-  /**
-   * Announce a live region.
-   * @param  {PivotContext} aContext context object for an accessible.
-   * @param  {boolean} aIsPolite A politeness level for a live region.
-   * @param  {boolean} aIsHide An indicator of hide/remove event.
-   * @param  {string} aModifiedText Optional modified text.
-   */
-  liveRegion: function liveRegionShown(aContext, aIsPolite, aIsHide, // jshint ignore:line
-    aModifiedText) {} // jshint ignore:line
-};
-
-/**
- * Visual presenter. Draws a box around the virtual cursor's position.
- */
-function VisualPresenter() {}
-
-VisualPresenter.prototype = Object.create(Presenter.prototype);
-
-VisualPresenter.prototype.type = "Visual";
-
-/**
- * The padding in pixels between the object and the highlight border.
- */
-VisualPresenter.prototype.BORDER_PADDING = 2;
-
-VisualPresenter.prototype.viewportChanged =
-  function VisualPresenter_viewportChanged(aWindow, aCurrentContext) {
-    if (!aCurrentContext) {
-      return null;
-    }
-
-    let currentAcc = aCurrentContext.accessibleForBounds;
-    let start = aCurrentContext.startOffset;
-    let end = aCurrentContext.endOffset;
-    if (Utils.isAliveAndVisible(currentAcc)) {
-      let bounds = (start === -1 && end === -1) ? Utils.getBounds(currentAcc) :
-                   Utils.getTextBounds(currentAcc, start, end);
-
-      return {
-        type: this.type,
-        details: {
-          eventType: "viewport-change",
-          bounds,
-          padding: this.BORDER_PADDING
-        }
-      };
-    }
-
-    return null;
-  };
-
-VisualPresenter.prototype.pivotChanged =
-  function VisualPresenter_pivotChanged(aContext) {
-    if (!aContext.accessible) {
-      // XXX: Don't hide because another vc may be using the highlight.
-      return null;
-    }
-
-    try {
-      aContext.accessibleForBounds.scrollTo(
-        Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
-
-      let bounds = (aContext.startOffset === -1 && aContext.endOffset === -1) ?
-            aContext.bounds : Utils.getTextBounds(aContext.accessibleForBounds,
-                                                  aContext.startOffset,
-                                                  aContext.endOffset);
-
-      return {
-        type: this.type,
-        details: {
-          eventType: "vc-change",
-          bounds,
-          padding: this.BORDER_PADDING
-        }
-      };
-    } catch (e) {
-      Logger.logException(e, "Failed to get bounds");
-      return null;
-    }
-  };
-
-VisualPresenter.prototype.tabSelected =
-  function VisualPresenter_tabSelected(aDocContext, aVCContext) {
-    return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
-  };
-
-VisualPresenter.prototype.tabStateChanged =
-  function VisualPresenter_tabStateChanged(aDocObj, aPageState) {
-    if (aPageState == "newdoc") {
-      return {type: this.type, details: {eventType: "tabstate-change"}};
-    }
-
-    return null;
-  };
-
-/**
- * Android presenter. Fires Android a11y events.
- */
-function AndroidPresenter() {}
-
-AndroidPresenter.prototype = Object.create(Presenter.prototype);
-
-AndroidPresenter.prototype.type = "Android";
-
-// Android AccessibilityEvent type constants.
-AndroidPresenter.prototype.ANDROID_VIEW_CLICKED = 0x01;
-AndroidPresenter.prototype.ANDROID_VIEW_LONG_CLICKED = 0x02;
-AndroidPresenter.prototype.ANDROID_VIEW_SELECTED = 0x04;
-AndroidPresenter.prototype.ANDROID_VIEW_FOCUSED = 0x08;
-AndroidPresenter.prototype.ANDROID_VIEW_TEXT_CHANGED = 0x10;
-AndroidPresenter.prototype.ANDROID_WINDOW_STATE_CHANGED = 0x20;
-AndroidPresenter.prototype.ANDROID_VIEW_HOVER_ENTER = 0x80;
-AndroidPresenter.prototype.ANDROID_VIEW_HOVER_EXIT = 0x100;
-AndroidPresenter.prototype.ANDROID_VIEW_SCROLLED = 0x1000;
-AndroidPresenter.prototype.ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
-AndroidPresenter.prototype.ANDROID_ANNOUNCEMENT = 0x4000;
-AndroidPresenter.prototype.ANDROID_VIEW_ACCESSIBILITY_FOCUSED = 0x8000;
-AndroidPresenter.prototype.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY =
-  0x20000;
-
-AndroidPresenter.prototype.pivotChanged =
-  function AndroidPresenter_pivotChanged(aContext, aReason) {
-    if (!aContext.accessible) {
+  pivotChanged(aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
+    let context = new PivotContext(
+      aPosition, aOldPosition, aStartOffset, aEndOffset);
+    if (!context.accessible) {
       return null;
     }
 
     let androidEvents = [];
 
     let isExploreByTouch = (aReason == Ci.nsIAccessiblePivot.REASON_POINT &&
                             Utils.AndroidSdkVersion >= 14);
     let focusEventType = (Utils.AndroidSdkVersion >= 16) ?
-      this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED :
-      this.ANDROID_VIEW_FOCUSED;
+      AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED :
+      AndroidEvents.ANDROID_VIEW_FOCUSED;
 
     if (isExploreByTouch) {
       // This isn't really used by TalkBack so this is a half-hearted attempt
       // for now.
-      androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
-    }
-
-    let brailleOutput = {};
-    if (Utils.AndroidSdkVersion >= 16) {
-      if (!this._braillePresenter) {
-        this._braillePresenter = new BraillePresenter();
-      }
-      brailleOutput = this._braillePresenter.pivotChanged(aContext, aReason).
-                         details;
+      androidEvents.push({eventType: AndroidEvents.ANDROID_VIEW_HOVER_EXIT, text: []});
     }
 
     if (aReason === Ci.nsIAccessiblePivot.REASON_TEXT) {
       if (Utils.AndroidSdkVersion >= 16) {
-        let adjustedText = aContext.textAndAdjustedOffsets;
+        let adjustedText = context.textAndAdjustedOffsets;
 
         androidEvents.push({
-          eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+          eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
           text: [adjustedText.text],
           fromIndex: adjustedText.startOffset,
           toIndex: adjustedText.endOffset
         });
       }
     } else {
-      let state = Utils.getState(aContext.accessible);
+      let state = Utils.getState(context.accessible);
       androidEvents.push({eventType: (isExploreByTouch) ?
-                           this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
+                           AndroidEvents.ANDROID_VIEW_HOVER_ENTER : focusEventType,
                          text: Utils.localize(UtteranceGenerator.genForContext(
-                           aContext)),
-                         bounds: aContext.bounds,
-                         clickable: aContext.accessible.actionCount > 0,
+                           context)),
+                         bounds: context.bounds,
+                         clickable: context.accessible.actionCount > 0,
                          checkable: state.contains(States.CHECKABLE),
-                         checked: state.contains(States.CHECKED),
-                         brailleOutput});
+                         checked: state.contains(States.CHECKED)});
     }
 
+    try {
+      context.accessibleForBounds.scrollTo(
+        Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
+    } catch (e) {}
 
-    return {
-      type: this.type,
-      details: androidEvents
-    };
-  };
+    if (context.accessible) {
+      this.displayedAccessibles.set(context.accessible.document.window, context);
+    }
+
+    return androidEvents;
+  }
 
-AndroidPresenter.prototype.actionInvoked =
-  function AndroidPresenter_actionInvoked(aObject, aActionName) {
+  /**
+   * An object's action has been invoked.
+   * @param {nsIAccessible} aObject the object that has been invoked.
+   * @param {string} aActionName the name of the action.
+   */
+  actionInvoked(aObject, aActionName) {
     let state = Utils.getState(aObject);
 
     // Checkable objects use TalkBack's text derived from the event state,
     // so we don't populate the text here.
     let text = null;
     if (!state.contains(States.CHECKABLE)) {
       text = Utils.localize(UtteranceGenerator.genForAction(aObject,
         aActionName));
     }
 
-    return {
-      type: this.type,
-      details: [{
-        eventType: this.ANDROID_VIEW_CLICKED,
-        text,
-        checked: state.contains(States.CHECKED)
-      }]
-    };
-  };
+    return [{
+      eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
+      text,
+      checked: state.contains(States.CHECKED)
+    }];
+  }
 
-AndroidPresenter.prototype.tabSelected =
-  function AndroidPresenter_tabSelected(aDocContext, aVCContext) {
-    // Send a pivot change message with the full context utterance for this doc.
-    return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
-  };
-
-AndroidPresenter.prototype.tabStateChanged =
-  function AndroidPresenter_tabStateChanged(aDocObj, aPageState) {
-    return this.announce(
-      UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
-  };
-
-AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
-  aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
-    let eventDetails = {
-      eventType: this.ANDROID_VIEW_TEXT_CHANGED,
+  /**
+   * Text has changed, either by the user or by the system. TODO.
+   */
+  textChanged(aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
+    let androidEvent = {
+      eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED,
       text: [aText],
       fromIndex: aStart,
       removedCount: 0,
       addedCount: 0
     };
 
     if (aIsInserted) {
-      eventDetails.addedCount = aLength;
-      eventDetails.beforeText =
+      androidEvent.addedCount = aLength;
+      androidEvent.beforeText =
         aText.substring(0, aStart) + aText.substring(aStart + aLength);
     } else {
-      eventDetails.removedCount = aLength;
-      eventDetails.beforeText =
+      androidEvent.removedCount = aLength;
+      androidEvent.beforeText =
         aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
     }
 
-    return {type: this.type, details: [eventDetails]};
-  };
+    return [androidEvent];
+  }
 
-AndroidPresenter.prototype.textSelectionChanged =
-  function AndroidPresenter_textSelectionChanged(aText, aStart, aEnd, aOldStart,
-                                                 aOldEnd, aIsFromUserInput) {
+  /**
+   * Text selection has changed. TODO.
+   */
+  textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {
     let androidEvents = [];
 
     if (Utils.AndroidSdkVersion >= 14 && !aIsFromUserInput) {
-      if (!this._braillePresenter) {
-        this._braillePresenter = new BraillePresenter();
-      }
-      let brailleOutput = this._braillePresenter.textSelectionChanged(
-        aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput).details;
-
       androidEvents.push({
-        eventType: this.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
+        eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
         text: [aText],
         fromIndex: aStart,
         toIndex: aEnd,
-        itemCount: aText.length,
-        brailleOutput
+        itemCount: aText.length
       });
     }
 
     if (Utils.AndroidSdkVersion >= 16 && aIsFromUserInput) {
       let [from, to] = aOldStart < aStart ?
         [aOldStart, aStart] : [aStart, aOldStart];
       androidEvents.push({
-        eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+        eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
         text: [aText],
         fromIndex: from,
         toIndex: to
       });
     }
 
-    return {
-      type: this.type,
-      details: androidEvents
-    };
-  };
+    return androidEvents;
+  }
+
+  /**
+   * Selection has changed.
+   * XXX: Implement android event?
+   * @param {nsIAccessible} aObject the object that has been selected.
+   */
+  selectionChanged(aObject) {
+    return "todo.selection-changed";
+  }
+
+  /**
+   * Name has changed.
+   * XXX: Implement android event?
+   * @param {nsIAccessible} aAccessible the object whose value has changed.
+   */
+  nameChanged(aAccessible) {
+    return "todo.name-changed";
+  }
+
+  /**
+   * Value has changed.
+   * XXX: Implement android event?
+   * @param {nsIAccessible} aAccessible the object whose value has changed.
+   */
+  valueChanged(aAccessible) {
+    return "todo.value-changed";
+  }
 
-AndroidPresenter.prototype.viewportChanged =
-  function AndroidPresenter_viewportChanged(aWindow, aCurrentContext) {
+  /**
+   * The tab, or the tab's document state has changed.
+   * @param {nsIAccessible} aDocObj the tab document accessible that has had its
+   *    state changed, or null if the tab has no associated document yet.
+   * @param {string} aPageState the state name for the tab, valid states are:
+   *    'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
+   */
+  tabStateChanged(aDocObj, aPageState) {
+    return this.announce(
+      UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
+  }
+
+  /**
+   * The current tab has changed.
+   * @param {PivotContext} aDocContext context object for tab's
+   *   document.
+   * @param {PivotContext} aVCContext context object for tab's current
+   *   virtual cursor position.
+   */
+  tabSelected(aDocContext, aVCContext) {
+    return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
+  }
+
+  /**
+   * The viewport has changed, either a scroll, pan, zoom, or
+   *    landscape/portrait toggle.
+   * @param {Window} aWindow window of viewport that changed.
+   */
+  viewportChanged(aWindow) {
+    let currentContext = this.displayedAccessibles.get(aWindow);
+
     if (Utils.AndroidSdkVersion < 14) {
       return null;
     }
 
     let events = [{
-      eventType: this.ANDROID_VIEW_SCROLLED,
+      eventType: AndroidEvents.ANDROID_VIEW_SCROLLED,
       text: [],
       scrollX: aWindow.scrollX,
       scrollY: aWindow.scrollY,
       maxScrollX: aWindow.scrollMaxX,
       maxScrollY: aWindow.scrollMaxY
     }];
 
-    if (Utils.AndroidSdkVersion >= 16 && aCurrentContext) {
-      let currentAcc = aCurrentContext.accessibleForBounds;
+    if (Utils.AndroidSdkVersion >= 16 && currentContext) {
+      let currentAcc = currentContext.accessibleForBounds;
       if (Utils.isAliveAndVisible(currentAcc)) {
         events.push({
-          eventType: this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
+          eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
           bounds: Utils.getBounds(currentAcc)
         });
       }
     }
 
-    return {
-      type: this.type,
-      details: events
-    };
-  };
-
-AndroidPresenter.prototype.editingModeChanged =
-  function AndroidPresenter_editingModeChanged(aIsEditing) {
-    return this.announce(UtteranceGenerator.genForEditingMode(aIsEditing));
-  };
-
-AndroidPresenter.prototype.announce =
-  function AndroidPresenter_announce(aAnnouncement) {
-    let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
-    return {
-      type: this.type,
-      details: [{
-        eventType: (Utils.AndroidSdkVersion >= 16) ?
-          this.ANDROID_ANNOUNCEMENT : this.ANDROID_VIEW_TEXT_CHANGED,
-        text: [localizedAnnouncement],
-        addedCount: localizedAnnouncement.length,
-        removedCount: 0,
-        fromIndex: 0
-      }]
-    };
-  };
-
-AndroidPresenter.prototype.liveRegion =
-  function AndroidPresenter_liveRegion(aContext, aIsPolite,
-    aIsHide, aModifiedText) {
-    return this.announce(
-      UtteranceGenerator.genForLiveRegion(aContext, aIsHide, aModifiedText));
-  };
+    return events;
+  }
 
-AndroidPresenter.prototype.noMove =
-  function AndroidPresenter_noMove(aMoveMethod) {
-    return {
-      type: this.type,
-      details: [
-      { eventType: this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
-        exitView: aMoveMethod,
-        text: [""]
-      }]
-    };
-  };
-
-/**
- * A B2G presenter for Gaia.
- */
-function B2GPresenter() {}
-
-B2GPresenter.prototype = Object.create(Presenter.prototype);
-
-B2GPresenter.prototype.type = "B2G";
-
-B2GPresenter.prototype.keyboardEchoSetting =
-  new PrefCache("accessibility.accessfu.keyboard_echo");
-B2GPresenter.prototype.NO_ECHO = 0;
-B2GPresenter.prototype.CHARACTER_ECHO = 1;
-B2GPresenter.prototype.WORD_ECHO = 2;
-B2GPresenter.prototype.CHARACTER_AND_WORD_ECHO = 3;
-
-/**
- * A pattern used for haptic feedback.
- * @type {Array}
- */
-B2GPresenter.prototype.PIVOT_CHANGE_HAPTIC_PATTERN = [40];
-
-/**
- * Pivot move reasons.
- * @type {Array}
- */
-B2GPresenter.prototype.pivotChangedReasons = ["none", "next", "prev", "first",
-                                              "last", "text", "point"];
-
-B2GPresenter.prototype.pivotChanged =
-  function B2GPresenter_pivotChanged(aContext, aReason, aIsUserInput) {
-    if (!aContext.accessible) {
-      return null;
-    }
+  /**
+   * We have entered or left text editing mode.
+   */
+  editingModeChanged(aIsEditing) {
+    return this.announce(UtteranceGenerator.genForEditingMode(aIsEditing));
+  }
 
-    return {
-      type: this.type,
-      details: {
-        eventType: "vc-change",
-        data: UtteranceGenerator.genForContext(aContext),
-        options: {
-          pattern: this.PIVOT_CHANGE_HAPTIC_PATTERN,
-          isKey: Utils.isActivatableOnFingerUp(aContext.accessible),
-          reason: this.pivotChangedReasons[aReason],
-          isUserInput: aIsUserInput,
-          hints: aContext.interactionHints
-        }
-      }
-    };
-  };
-
-B2GPresenter.prototype.nameChanged =
-  function B2GPresenter_nameChanged(aAccessible, aIsPolite = true) {
-    return {
-      type: this.type,
-      details: {
-        eventType: "name-change",
-        data: aAccessible.name,
-        options: {enqueue: aIsPolite}
-      }
-    };
-  };
-
-B2GPresenter.prototype.valueChanged =
-  function B2GPresenter_valueChanged(aAccessible, aIsPolite = true) {
-
-    // the editable value changes are handled in the text changed presenter
-    if (Utils.getState(aAccessible).contains(States.EDITABLE)) {
-      return null;
-    }
+  /**
+   * Announce something. Typically an app state change.
+   */
+  announce(aAnnouncement) {
+    let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
+    return [{
+      eventType: (Utils.AndroidSdkVersion >= 16) ?
+        AndroidEvents.ANDROID_ANNOUNCEMENT :
+        AndroidEvents.ANDROID_VIEW_TEXT_CHANGED,
+      text: [localizedAnnouncement],
+      addedCount: localizedAnnouncement.length,
+      removedCount: 0,
+      fromIndex: 0
+    }];
+  }
 
-    return {
-      type: this.type,
-      details: {
-        eventType: "value-change",
-        data: aAccessible.value,
-        options: {enqueue: aIsPolite}
-      }
-    };
-  };
-
-B2GPresenter.prototype.textChanged = function B2GPresenter_textChanged(
-  aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
-    let echoSetting = this.keyboardEchoSetting.value;
-    let text = "";
-
-    if (echoSetting == this.CHARACTER_ECHO ||
-        echoSetting == this.CHARACTER_AND_WORD_ECHO) {
-      text = aModifiedText;
-    }
-
-    // add word if word boundary is added
-    if ((echoSetting == this.WORD_ECHO ||
-        echoSetting == this.CHARACTER_AND_WORD_ECHO) &&
-        aIsInserted && aLength === 1) {
-      let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
-      let startBefore = {}, endBefore = {};
-      let startAfter = {}, endAfter = {};
-      accText.getTextBeforeOffset(aStart,
-        Ci.nsIAccessibleText.BOUNDARY_WORD_END, startBefore, endBefore);
-      let maybeWord = accText.getTextBeforeOffset(aStart + 1,
-        Ci.nsIAccessibleText.BOUNDARY_WORD_END, startAfter, endAfter);
-      if (endBefore.value !== endAfter.value) {
-        text += maybeWord;
-      }
-    }
-
-    return {
-      type: this.type,
-      details: {
-        eventType: "text-change",
-        data: text
-      }
-    };
-
-  };
 
-B2GPresenter.prototype.actionInvoked =
-  function B2GPresenter_actionInvoked(aObject, aActionName) {
-    return {
-      type: this.type,
-      details: {
-        eventType: "action",
-        data: UtteranceGenerator.genForAction(aObject, aActionName)
-      }
-    };
-  };
-
-B2GPresenter.prototype.liveRegion = function B2GPresenter_liveRegion(aContext,
-  aIsPolite, aIsHide, aModifiedText) {
-    return {
-      type: this.type,
-      details: {
-        eventType: "liveregion-change",
-        data: UtteranceGenerator.genForLiveRegion(aContext, aIsHide,
-          aModifiedText),
-        options: {enqueue: aIsPolite}
-      }
-    };
-  };
-
-B2GPresenter.prototype.announce =
-  function B2GPresenter_announce(aAnnouncement) {
-    return {
-      type: this.type,
-      details: {
-        eventType: "announcement",
-        data: aAnnouncement
-      }
-    };
-  };
-
-B2GPresenter.prototype.noMove =
-  function B2GPresenter_noMove(aMoveMethod) {
-    return {
-      type: this.type,
-      details: {
-        eventType: "no-move",
-        data: aMoveMethod
-      }
-    };
-  };
-
-/**
- * A braille presenter
- */
-function BraillePresenter() {}
-
-BraillePresenter.prototype = Object.create(Presenter.prototype);
-
-BraillePresenter.prototype.type = "Braille";
-
-BraillePresenter.prototype.pivotChanged =
-  function BraillePresenter_pivotChanged(aContext) {
-    if (!aContext.accessible) {
-      return null;
-    }
-
-    return {
-      type: this.type,
-      details: {
-        output: Utils.localize(BrailleGenerator.genForContext(aContext)).join(
-          " "),
-        selectionStart: 0,
-        selectionEnd: 0
-      }
-    };
-  };
-
-BraillePresenter.prototype.textSelectionChanged =
-  function BraillePresenter_textSelectionChanged(aText, aStart, aEnd) {
-    return {
-      type: this.type,
-      details: {
-        selectionStart: aStart,
-        selectionEnd: aEnd
-      }
-    };
-  };
+  /**
+   * User tried to move cursor forward or backward with no success.
+   * @param {string} aMoveMethod move method that was used (eg. 'moveNext').
+   */
+  noMove(aMoveMethod) {
+    return [{
+      eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
+      exitView: aMoveMethod,
+      text: [""]
+    }];
+  }
 
-var Presentation = { // jshint ignore:line
-  get presenters() {
-    delete this.presenters;
-    let presenterMap = {
-      "mobile/android": [VisualPresenter, AndroidPresenter],
-      "b2g": [VisualPresenter, B2GPresenter],
-      "browser": [VisualPresenter, B2GPresenter, AndroidPresenter]
-    };
-    this.presenters = presenterMap[Utils.MozBuildApp].map(P => new P());
-    return this.presenters;
-  },
-
-  get displayedAccessibles() {
-    delete this.displayedAccessibles;
-    this.displayedAccessibles = new WeakMap();
-    return this.displayedAccessibles;
-  },
-
-  pivotChanged: function Presentation_pivotChanged(
-    aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
-    let context = new PivotContext(
-      aPosition, aOldPosition, aStartOffset, aEndOffset);
-    if (context.accessible) {
-      this.displayedAccessibles.set(context.accessible.document.window, context);
-    }
-
-    return this.presenters.map(p => p.pivotChanged(context, aReason, aIsUserInput));
-  },
-
-  actionInvoked: function Presentation_actionInvoked(aObject, aActionName) {
-    return this.presenters.map(p => p.actionInvoked(aObject, aActionName));
-  },
-
-  textChanged: function Presentation_textChanged(aAccessible, aIsInserted,
-                                    aStartOffset, aLength, aText,
-                                    aModifiedText) {
-    return this.presenters.map(p => p.textChanged(aAccessible, aIsInserted,
-                                                  aStartOffset, aLength,
-                                                  aText, aModifiedText));
-  },
+  /**
+   * Announce a live region.
+   * @param  {PivotContext} aContext context object for an accessible.
+   * @param  {boolean} aIsPolite A politeness level for a live region.
+   * @param  {boolean} aIsHide An indicator of hide/remove event.
+   * @param  {string} aModifiedText Optional modified text.
+   */
+  liveRegion(aAccessible, aIsPolite, aIsHide, aModifiedText) {
+    let context = !aModifiedText ?
+      new PivotContext(aAccessible, null, -1, -1, true, !!aIsHide) : null;
+    return this.announce(
+      UtteranceGenerator.genForLiveRegion(context, aIsHide, aModifiedText));
+  }
+}
 
-  textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
-                                                      aOldStart, aOldEnd,
-                                                      aIsFromUserInput) {
-    return this.presenters.map(p => p.textSelectionChanged(aText, aStart, aEnd,
-                                                           aOldStart, aOldEnd,
-                                                           aIsFromUserInput));
-  },
-
-  nameChanged: function nameChanged(aAccessible) {
-    return this.presenters.map(p => p.nameChanged(aAccessible));
-  },
-
-  valueChanged: function valueChanged(aAccessible) {
-    return this.presenters.map(p => p.valueChanged(aAccessible));
-  },
-
-  tabStateChanged: function Presentation_tabStateChanged(aDocObj, aPageState) {
-    return this.presenters.map(p => p.tabStateChanged(aDocObj, aPageState));
-  },
-
-  viewportChanged: function Presentation_viewportChanged(aWindow) {
-    let context = this.displayedAccessibles.get(aWindow);
-    return this.presenters.map(p => p.viewportChanged(aWindow, context));
-  },
-
-  editingModeChanged: function Presentation_editingModeChanged(aIsEditing) {
-    return this.presenters.map(p => p.editingModeChanged(aIsEditing));
-  },
-
-  announce: function Presentation_announce(aAnnouncement) {
-    // XXX: Typically each presenter uses the UtteranceGenerator,
-    // but there really isn't a point here.
-    return this.presenters.map(p => p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)));
-  },
-
-  noMove: function Presentation_noMove(aMoveMethod) {
-    return this.presenters.map(p => p.noMove(aMoveMethod));
-  },
-
-  liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide,
-    aModifiedText) {
-    let context;
-    if (!aModifiedText) {
-      context = new PivotContext(aAccessible, null, -1, -1, true, !!aIsHide);
-    }
-    return this.presenters.map(p => p.liveRegion(context, aIsPolite, aIsHide,
-                                                 aModifiedText));
-  }
-};
+const Presentation = new AndroidPresentor();
--- a/accessible/jsat/jar.mn
+++ b/accessible/jsat/jar.mn
@@ -1,7 +1,6 @@
 # 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/.
 
 toolkit.jar:
-    content/global/accessibility/AccessFu.css (AccessFu.css)
     content/global/accessibility/content-script.js (content-script.js)
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -12,16 +12,17 @@ var gTestFuncs = [];
 /**
   * A global Iterator for the array of test functions.
   */
 var gIterator;
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.import("resource://gre/modules/accessibility/EventManager.jsm");
+ChromeUtils.import("resource://gre/modules/accessibility/Constants.jsm");
 
 var AccessFuTest = {
 
   addFunc: function AccessFuTest_addFunc(aFunc) {
     if (aFunc) {
       gTestFuncs.push(aFunc);
     }
   },
@@ -56,22 +57,23 @@ var AccessFuTest = {
       function listenAndUnregister() {
         Services.console.unregisterListener(this);
         aListenerFunc();
       });
   },
 
   _addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) {
     var listener = function listener(aSubject, aTopic, aData) {
-      var data = JSON.parse(aData)[1];
+      var data = JSON.parse(aData);
       // Ignore non-relevant outputs.
-      if (!data) {
+      if (!data || (data[0] && data[0].text && data[0].text[0] == "new tab")) {
         return;
       }
-      isDeeply(data.details, aWaitForData, "Data is correct");
+
+      isDeeply(data, aWaitForData, "Data is correct (" + aData + ")");
       aListener.apply(listener);
     };
     Services.obs.addObserver(listener, "accessibility-output");
     return listener;
   },
 
   on: function AccessFuTest_on(aWaitForData, aListener) {
     return this._addObserver(aWaitForData, aListener);
@@ -285,17 +287,17 @@ AccessFuContentTest.prototype = {
   receiveMessage(aMessage) {
     var expected = this.expected[0];
 
     if (!expected) {
       return;
     }
 
     var actionsString = typeof this.currentAction === "function" ?
-      this.currentAction.name + "()" : JSON.stringify(this.currentAction);
+      this.currentAction.toString() : JSON.stringify(this.currentAction);
 
     if (typeof expected === "string") {
       ok(true, "Got " + expected + " after " + actionsString);
       this.pump();
     } else if (expected.ignore && !expected.ignore(aMessage)) {
       expected.is(aMessage.json, "after " + actionsString +
         " (" + this.actionNum + ")");
       expected.is_correct_focus();
@@ -467,16 +469,20 @@ function ExpectedMessage(aName, aOptions
   this.json = {};
 }
 
 ExpectedMessage.prototype.lazyCompare = function(aReceived, aExpected, aInfo) {
   if (aExpected && !aReceived) {
     return [false, "Expected something but got nothing -- " + aInfo];
   }
 
+  if (typeof aReceived === "string" || typeof aExpected === "string") {
+    return [aReceived == aExpected, `String comparison: Got '${aReceived}.', expected: ${aExpected} -- ${aInfo}`];
+  }
+
   var matches = true;
   var delta = [];
   for (var attr in aExpected) {
     var expected = aExpected[attr];
     var received = aReceived[attr];
     if (typeof expected === "object") {
       var [childMatches, childDelta] = this.lazyCompare(received, expected);
       if (!childMatches) {
@@ -512,208 +518,152 @@ ExpectedMessage.prototype.is_correct_foc
     [ doc.activeElement, doc.querySelector(this.options.focused),
       "Correct element is focused: " + this.options.focused + " -- " + aInfo ]);
 };
 
 ExpectedMessage.prototype.ignore = function(aMessage) {
   return aMessage.name !== this.name;
 };
 
-function ExpectedPresent(aB2g, aAndroid, aOptions) {
+function ExpectedPresent(aAndroidEvents, aOptions) {
   ExpectedMessage.call(this, "AccessFu:Present", aOptions);
-  if (aB2g) {
-    this.json.b2g = aB2g;
-  }
-
-  if (aAndroid) {
-    this.json.android = aAndroid;
-  }
+  this.expectedEvents = aAndroidEvents;
 }
 
 ExpectedPresent.prototype = Object.create(ExpectedMessage.prototype);
 
 ExpectedPresent.prototype.is = function(aReceived, aInfo) {
-  var received = this.extract_presenters(aReceived);
-
-  for (var presenter of ["b2g", "android"]) {
-    if (!this.options["no_" + presenter]) {
-      var todo = this.options.todo || this.options[presenter + "_todo"];
-      SimpleTest[todo ? "todo" : "ok"].apply(
-        SimpleTest, this.lazyCompare(received[presenter],
-          this.json[presenter], aInfo + " (" + presenter + ")"));
-    }
-  }
-};
-
-ExpectedPresent.prototype.extract_presenters = function(aReceived) {
-  var received = { count: 0 };
-  for (var presenter of aReceived) {
-    if (presenter) {
-      received[presenter.type.toLowerCase()] = presenter.details;
-      received.count++;
+  if (typeof this.expectedEvents == "string") {
+    // This is an event we have yet to implement, do a simple string comparison.
+    if (this.expectedEvents == aReceived) {
+      SimpleTest.todo(false, `${aInfo} (${aReceived})`);
+      return;
     }
   }
 
-  return received;
+  SimpleTest[this.options.todo ? "todo" : "ok"].apply(SimpleTest,
+    this.lazyCompare(aReceived, this.expectedEvents, aInfo + " aReceived: " +
+      JSON.stringify(aReceived) + " evt: " + JSON.stringify(this.expectedEvents)));
 };
 
 ExpectedPresent.prototype.ignore = function(aMessage) {
-  if (ExpectedMessage.prototype.ignore.call(this, aMessage)) {
+  if (!aMessage.json || ExpectedMessage.prototype.ignore.call(this, aMessage)) {
     return true;
   }
 
-  var received = this.extract_presenters(aMessage.json);
-  return received.count === 0 ||
-    (received.visual && received.visual.eventType === "viewport-change") ||
-    (received.android &&
-      received.android[0].eventType === AndroidEvent.VIEW_SCROLLED);
+  let firstEvent = (aMessage.json || [])[0];
+
+  return firstEvent && firstEvent.eventType === AndroidEvents.ANDROID_VIEW_SCROLLED;
 };
 
 function ExpectedCursorChange(aSpeech, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "vc-change",
-    data: aSpeech
-  }, [{
+  ExpectedPresent.call(this, [{
     eventType: 0x8000, // VIEW_ACCESSIBILITY_FOCUSED
   }], aOptions);
 }
 
 ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype);
 
 function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "vc-change",
-    data: aSpeech
-  }, [{
-    eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
     fromIndex: aStartOffset,
     toIndex: aEndOffset
   }], aOptions);
 
   // bug 980509
   this.options.b2g_todo = true;
 }
 
 ExpectedCursorTextChange.prototype =
   Object.create(ExpectedCursorChange.prototype);
 
 function ExpectedClickAction(aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "action",
-    data: [{ string: "clickAction" }]
-  }, [{
-    eventType: AndroidEvent.VIEW_CLICKED
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_CLICKED
   }], aOptions);
 }
 
 ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype);
 
 function ExpectedCheckAction(aChecked, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "action",
-    data: [{ string: aChecked ? "checkAction" : "uncheckAction" }]
-  }, [{
-    eventType: AndroidEvent.VIEW_CLICKED,
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
     checked: aChecked
   }], aOptions);
 }
 
 ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype);
 
 function ExpectedSwitchAction(aSwitched, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "action",
-    data: [{ string: aSwitched ? "onAction" : "offAction" }]
-  }, [{
-    eventType: AndroidEvent.VIEW_CLICKED,
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
     checked: aSwitched
   }], aOptions);
 }
 
 ExpectedSwitchAction.prototype = Object.create(ExpectedPresent.prototype);
 
+// XXX: Implement Android event?
 function ExpectedNameChange(aName, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "name-change",
-    data: aName
-  }, null, aOptions);
+  ExpectedPresent.call(this, "todo.name-changed", aOptions);
 }
 
 ExpectedNameChange.prototype = Object.create(ExpectedPresent.prototype);
 
+// XXX: Implement Android event?
 function ExpectedValueChange(aValue, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "value-change",
-    data: aValue
-  }, null, aOptions);
+  ExpectedPresent.call(this, "todo.value-changed", aOptions);
 }
 
 ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype);
 
+// XXX: Implement Android event?
 function ExpectedTextChanged(aValue, aOptions) {
-  ExpectedPresent.call(this, {
-    eventType: "text-change",
-    data: aValue
-  }, null, aOptions);
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED
+  }], aOptions);
 }
 
 ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype);
 
 function ExpectedEditState(aEditState, aOptions) {
   ExpectedMessage.call(this, "AccessFu:Input", aOptions);
   this.json = aEditState;
 }
 
 ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype);
 
 function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) {
-  ExpectedPresent.call(this, null, [{
-    eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED,
-    brailleOutput: {
-     selectionStart: aStart,
-     selectionEnd: aEnd
-   }}], aOptions);
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
+  }], aOptions);
 }
 
 ExpectedTextSelectionChanged.prototype =
   Object.create(ExpectedPresent.prototype);
 
 function ExpectedTextCaretChanged(aFrom, aTo, aOptions) {
-  ExpectedPresent.call(this, null, [{
-    eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
     fromIndex: aFrom,
     toIndex: aTo
   }], aOptions);
 }
 
 ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype);
 
 function ExpectedAnnouncement(aAnnouncement, aOptions) {
-  ExpectedPresent.call(this, null, [{
-    eventType: AndroidEvent.ANNOUNCEMENT,
+  ExpectedPresent.call(this, [{
+    eventType: AndroidEvents.ANDROID_ANNOUNCEMENT,
     text: [ aAnnouncement],
     addedCount: aAnnouncement.length
   }], aOptions);
 }
 
 ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype);
 
+// XXX: Implement Android event?
 function ExpectedNoMove(aOptions) {
-  ExpectedPresent.call(this, {eventType: "no-move" }, null, aOptions);
+  ExpectedPresent.call(this, null, aOptions);
 }
 
 ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype);
-
-var AndroidEvent = {
-  VIEW_CLICKED: 0x01,
-  VIEW_LONG_CLICKED: 0x02,
-  VIEW_SELECTED: 0x04,
-  VIEW_FOCUSED: 0x08,
-  VIEW_TEXT_CHANGED: 0x10,
-  WINDOW_STATE_CHANGED: 0x20,
-  VIEW_HOVER_ENTER: 0x80,
-  VIEW_HOVER_EXIT: 0x100,
-  VIEW_SCROLLED: 0x1000,
-  VIEW_TEXT_SELECTION_CHANGED: 0x2000,
-  ANNOUNCEMENT: 0x4000,
-  VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
-  VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000
-};
--- a/accessible/tests/mochitest/jsat/output.js
+++ b/accessible/tests/mochitest/jsat/output.js
@@ -79,30 +79,25 @@ function testObjectOutput(aAccOrElmOrID,
  * Test object and context output for an accessible.
  *
  * @param expected {Array} expected output.
  * @param aAccOrElmOrID    identifier to get an accessible to test.
  * @param aOldAccOrElmOrID optional identifier to get an accessible relative to
  *                         the |aAccOrElmOrID|.
  * @param aOutputKind      the type of output
  */
-function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) {
-  var generator;
-  if (aOutputKind === 1) {
-    generator = UtteranceGenerator;
-  } else {
-    generator = BrailleGenerator;
-  }
-  testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator);
+function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
+  testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID,
+    UtteranceGenerator);
   // Just need to test object output for individual
   // accOrElmOrID.
   if (aOldAccOrElmOrID) {
     return;
   }
-  testObjectOutput(aAccOrElmOrID, generator);
+  testObjectOutput(aAccOrElmOrID, UtteranceGenerator);
 }
 
 function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
   var accessible = getAccessible(aAccOrElmOrID);
   var oldAccessible = aOldAccOrElmOrID !== null ?
   getAccessible(aOldAccOrElmOrID || "root") : null;
   var context = new PivotContext(accessible, oldAccessible);
   var hints = context.interactionHints;
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -42,42 +42,42 @@
             { focused: "iframe" })],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["many option", {"string": "stateNotChecked"},
             {"string": "checkbutton"}, {"string": "listStart"},
             {"string": "list"}, {"string": "listItemsCount", "count": 1}])],
 
           // check checkbox
           [ContentMessages.activateCurrent(),
-           new ExpectedClickAction({ no_android: true }),
+           new ExpectedClickAction(),
            new ExpectedCheckAction(true)],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["much range", {"string": "label"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["much range", "5", {"string": "slider"}])],
           [ContentMessages.moveOrAdjustUp(), new ExpectedValueChange("6")],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Home", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["apple", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Light", {"string": "stateOff"}, {"string": "switch"}])],
           // switch on
           [ContentMessages.activateCurrent(),
-           new ExpectedClickAction({ no_android: true }),
+           new ExpectedClickAction(),
            new ExpectedSwitchAction(true)],
            [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["slider", "0", {"string": "slider"}])],
 
           // Simple traversal backward
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["Light", {"string": "stateOn"}, {"string": "switch"}])],
           // switch off
           [ContentMessages.activateCurrent(),
-           new ExpectedClickAction({ no_android: true }),
+           new ExpectedClickAction(),
            new ExpectedSwitchAction(false)],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["apple", {"string": "pushbutton"}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["Home", {"string": "pushbutton"}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["such app", "much range", "6", {"string": "slider"}])],
           [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange("5")],
@@ -86,17 +86,17 @@
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["much range", {"string": "label"}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["many option", {"string": "stateChecked"},
             {"string": "checkbutton"}, {"string": "listStart"},
             {"string": "list"}, {"string": "listItemsCount", "count": 1}])],
           // uncheck checkbox
           [ContentMessages.activateCurrent(),
-           new ExpectedClickAction({ no_android: true }),
+           new ExpectedClickAction(),
            new ExpectedCheckAction(false)],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["wow", {"string": "headingLevel", "args": [1]}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["Phone status bar"])],
 
@@ -105,17 +105,17 @@
           // Moving to the absolute last item from an embedded document
           // fails. Bug 972035.
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(
             ["such app", "wow", {"string": "headingLevel", "args": [1]}])],
           // Move from an inner frame to the last element in the parent doc
           [ContentMessages.simpleMoveLast,
             new ExpectedCursorChange(
-              ["slider", "0", {"string": "slider"}], { b2g_todo: true })],
+              ["slider", "0", {"string": "slider"}])],
 
           [ContentMessages.clearCursor, "AccessFu:CursorCleared"],
 
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Traversal Rule test document", "Phone status bar"])],
           [ContentMessages.moveOrAdjustDown("FormElement"),
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.moveOrAdjustDown("FormElement"),
@@ -148,17 +148,17 @@
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["such app", "wow", {"string": "headingLevel", "args": [1]}])],
           [ContentMessages.simpleMoveNext, new ExpectedCursorChange(
             ["many option", {"string": "stateNotChecked"},
              {"string": "checkbutton"}, {"string": "listStart"},
              {"string": "list"}, {"string": "listItemsCount", "count": 1}])],
           [ContentMessages.simpleMoveFirst,
-            new ExpectedCursorChange(["Phone status bar"], { b2g_todo: true })],
+            new ExpectedCursorChange(["Phone status bar"])],
 
           // Reset cursors
           [ContentMessages.clearCursor, "AccessFu:CursorCleared"],
 
           // Current virtual cursor's position's name changes
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Traversal Rule test document", "Phone status bar"])],
           [ContentMessages.focusSelector("button#fruit", false),
--- a/accessible/tests/mochitest/jsat/test_content_text.html
+++ b/accessible/tests/mochitest/jsat/test_content_text.html
@@ -55,17 +55,17 @@
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["You're a good guy, mon frere. " +
               "That means brother in French. " +
               "I don't know how I know that. " +
               "I took four years of Spanish."])],
           // XXX: Word boundary should be past the apostraphe.
           [ContentMessages.moveNextBy("word"),
            new ExpectedCursorTextChange("You're", 0, 6,
-             { android_todo: true /* Bug 980512 */})],
+             { todo: true /* Bug 980512 */})],
 
           // Editable text tests.
           [ContentMessages.focusSelector("textarea"),
            new ExpectedAnnouncement("editing"),
            new ExpectedEditState({
             editing: true,
             multiline: true,
             atStart: true,
@@ -160,17 +160,17 @@
             editing: true,
             multiline: false,
             atStart: true,
             atEnd: true
            },
            { focused: "input[type=text]" }),
            new ExpectedTextSelectionChanged(0, 0,
              // Bug 1455749: Fix granularity control in text entries.
-             { android_todo: true }
+             { todo: true }
            )],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(
             [ "So we don't get dessert?", {string: "label"} ]),
            new ExpectedAnnouncement("navigating"),
            new ExpectedEditState({
             editing: false,
             multiline: false,
@@ -189,84 +189,101 @@
            new ExpectedCursorChange([{string: "entry"}]),
            new ExpectedTextSelectionChanged(0, 0)
           ],
           [function() {
              SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 3]]}, typeKey("a")());
            },
            new ExpectedTextChanged("a"),
            new ExpectedTextSelectionChanged(1, 1),
+           new ExpectedValueChange(),
           ],
           [typeKey("b"),
            new ExpectedTextChanged("b"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(2, 2),
           ],
           [typeKey("c"),
            new ExpectedTextChanged("c"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(3, 3),
           ],
           [typeKey("d"),
            new ExpectedTextChanged("d"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(4, 4),
           ],
           [typeKey(" "),
            new ExpectedTextChanged(" abcd"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(5, 5),
           ],
           [typeKey("e"),
            new ExpectedTextChanged("e"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(6, 6),
           ],
           [function() {
              SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 2]]}, typeKey("a")());
            },
            new ExpectedTextChanged(""),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(7, 7),
           ],
           [typeKey("d"),
            new ExpectedTextChanged(""),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(8, 8),
           ],
           [typeKey(" "),
            new ExpectedTextChanged(" ead"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(9, 9),
           ],
           [function() {
              SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 1]]}, typeKey("f")());
            },
            new ExpectedTextChanged("f"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(10, 10),
           ],
           [typeKey("g"),
            new ExpectedTextChanged("g"),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(11, 11),
           ],
           [typeKey(" "),
            new ExpectedTextChanged(" "),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(12, 12),
           ],
           [function() {
              SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 0]]}, typeKey("f")());
            },
            new ExpectedTextChanged(""),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(13, 13),
           ],
           [typeKey("g"),
            new ExpectedTextChanged(""),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(14, 14),
           ],
           [typeKey(" "),
            new ExpectedTextChanged(""),
+           new ExpectedValueChange(),
            new ExpectedTextSelectionChanged(15, 15),
           ],
         ]);
 
       const KEYBOARD_ECHO_SETTING = "accessibility.accessfu.keyboard_echo";
       function typeKey(key) {
-        return function() { synthesizeKey(key, {}, currentTabWindow()); };
+        let func = function() { synthesizeKey(key, {}, currentTabWindow()); };
+        func.toString = () => `typeKey('${key}')`;
+        return func;
       }
 
       addA11yLoadEvent(function() {
         textTest.start(function() {
           closeBrowserWindow();
           SimpleTest.finish();
         });
       }, doc.defaultView);
--- a/accessible/tests/mochitest/jsat/test_explicit_names.html
+++ b/accessible/tests/mochitest/jsat/test_explicit_names.html
@@ -109,17 +109,17 @@
           {"string": "link"}, "Apples", {"string": "link"}, "Bananas",
           {"string": "link"}, "Peaches", {"string": "listEnd"},
           {"string": "link"}, "Plums"]
       }];
 
       SpecialPowers.pushPrefEnv({"set": [[PREF_UTTERANCE_ORDER, 0]]}, function() {
         // Test various explicit names vs the utterance generated from subtrees.
         tests.forEach(function run(test) {
-          testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
+          testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID);
         });
         SimpleTest.finish();
       });
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
--- a/accessible/tests/mochitest/jsat/test_landmarks.html
+++ b/accessible/tests/mochitest/jsat/test_landmarks.html
@@ -121,19 +121,17 @@
       // Test outputs (utterance and braille) for landmarks.
       function testOutputOrder(aOutputOrder) {
         return function() {
           SpecialPowers.pushPrefEnv({
             "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]]
           }, function() {
             tests.forEach(function run(test) {
               testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 1);
-              testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 0);
+                test.oldAccOrElmOrID);
             });
             AccessFuTest.nextTest();
           });
         };
       }
 
       AccessFuTest.addFunc(testOutputOrder(0));
       AccessFuTest.addFunc(testOutputOrder(1));
--- a/accessible/tests/mochitest/jsat/test_live_regions.html
+++ b/accessible/tests/mochitest/jsat/test_live_regions.html
@@ -7,17 +7,16 @@
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="./jsatcommon.js"></script>
   <script type="application/javascript">
-
     function startAccessFu() {
       AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
       AccessFu._enable();
     }
 
     function stopAccessFu() {
       AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
       AccessFu._disable();
@@ -52,281 +51,353 @@
       udpate(id, text, "textContent");
     }
 
     function updateHTML(id, text) {
       udpate(id, text, "innerHTML");
     }
 
     var tests = [{
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_hide1", "to_hide2", "to_hide3", "to_hide4"].forEach(id => hide(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_hide_descendant1", "to_hide_descendant2",
          "to_hide_descendant3", "to_hide_descendant4"].forEach(id => hide(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_show1", "to_show2", "to_show3", "to_show4"].forEach(id => show(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_show_descendant1", "to_show_descendant2",
          "to_show_descendant3", "to_show_descendant4"].forEach(id => show(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_hide5", "to_hide6", "to_hide7", "to_hide8", "to_hide9"].forEach(id => ariaHide(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_hide_descendant5", "to_hide_descendant6",
          "to_hide_descendant7", "to_hide_descendant8"].forEach(id => ariaHide(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_show5", "to_show6", "to_show7", "to_show8", "to_show9"].forEach(id => ariaShow(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         ["to_show_descendant5", "to_show_descendant6",
          "to_show_descendant7", "to_show_descendant8"].forEach(id => ariaShow(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         hide("to_hide_live_assertive");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "I will be hidden"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden I will be hidden"],
+        "addedCount": "hidden I will be hidden".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         ariaHide("to_hide_live_assertive2");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         ["to_show_live_off", "to_show_live_assertive"].forEach(id => show(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I will be shown"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I will be shown"],
+        "addedCount": "I will be shown".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         ["to_show_live_off2", "to_show_live_assertive2"].forEach(id => ariaShow(id));
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Text Added"],
+        "addedCount": "Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateText("text_add", "Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Text Added"],
+        "addedCount": "Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateHTML("text_add", "Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "Text Removed"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden Text Removed"],
+        "addedCount": "hidden Text Removed".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         updateText("text_remove", "");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Descendant Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Descendant Text Added"],
+        "addedCount": "Descendant Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateText("text_add_descendant", "Descendant Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Descendant Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Descendant Text Added"],
+        "addedCount": "Descendant Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateHTML("text_add_descendant", "Descendant Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "Descendant Text Removed"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden Descendant Text Removed"],
+        "addedCount": "hidden Descendant Text Removed".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         updateText("text_remove_descendant", "");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Descendant Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Descendant Text Added"],
+        "addedCount": "Descendant Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateText("text_add_descendant2", "Descendant Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["Descendant Text Added"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["Descendant Text Added"],
+        "addedCount": "Descendant Text Added".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateHTML("text_add_descendant2", "Descendant Text Added");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": [{"string": "hidden"}, "Descendant Text Removed"],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["hidden Descendant Text Removed"],
+        "addedCount": "hidden Descendant Text Removed".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         updateText("text_remove_descendant2", "");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I am replaced", {"string": "main"}],
-        "options": {
-          "enqueue": true
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I am replaced main"],
+        "addedCount": "I am replaced main".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": true
+        // }
+      }],
       action: function action() {
         var child = document.getElementById("to_replace");
         child.setAttribute("role", "main");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I am a replaced text"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I am a replaced text"],
+        "addedCount": "I am a replaced text".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateText("to_replace_text", "I am a replaced text");
       }
     }, {
-      expected: {
-        "eventType": "liveregion-change",
-        "data": ["I am a replaced text"],
-        "options": {
-          "enqueue": false
-        }
-      },
+      expected: [{
+        "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
+        "text": ["I am a replaced text"],
+        "addedCount": "I am a replaced text".length,
+        "removedCount": 0,
+        "fromIndex": 0,
+        // "options": {
+        //   "enqueue": false
+        // }
+      }],
       action: function action() {
         updateHTML("to_replace_text", "I am a replaced text");
       }
     }];
 
     function doTest() {
       AccessFuTest.addFunc(startAccessFu);
       tests.forEach(function addTest(test) {
--- a/accessible/tests/mochitest/jsat/test_output.html
+++ b/accessible/tests/mochitest/jsat/test_output.html
@@ -502,19 +502,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         // Test all possible utterance order preference values.
         function testOutputOrder(aOutputOrder) {
           return function() {
             SpecialPowers.pushPrefEnv({
               "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]]
             }, function() {
               tests.forEach(function run(test) {
                 testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
-                  test.oldAccOrElmOrID, 1);
-                testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
-                  test.oldAccOrElmOrID, 0);
+                  test.oldAccOrElmOrID);
               });
               AccessFuTest.nextTest();
             });
           };
         }
 
         AccessFuTest.addFunc(testOutputOrder(0));
         AccessFuTest.addFunc(testOutputOrder(1));
--- a/accessible/tests/mochitest/jsat/test_output_mathml.html
+++ b/accessible/tests/mochitest/jsat/test_output_mathml.html
@@ -171,19 +171,17 @@
       // Test all possible utterance order preference values.
       function testOutputOrder(aOutputOrder) {
         return function() {
           SpecialPowers.pushPrefEnv({
             "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]]
           }, function() {
             tests.forEach(function run(test) {
               testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 1);
-              testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 0);
+                test.oldAccOrElmOrID);
             });
             AccessFuTest.nextTest();
           });
         };
       }
 
       AccessFuTest.addFunc(testOutputOrder(0));
       AccessFuTest.addFunc(testOutputOrder(1));
--- a/accessible/tests/mochitest/jsat/test_tables.html
+++ b/accessible/tests/mochitest/jsat/test_tables.html
@@ -478,19 +478,17 @@
       // headers and cells.
       function testOutputOrder(aOutputOrder) {
         return function() {
           SpecialPowers.pushPrefEnv({
             "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]]
           }, function() {
             tests.forEach(function run(test) {
               testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 1);
-              testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
-                test.oldAccOrElmOrID, 0);
+                test.oldAccOrElmOrID);
             });
             AccessFuTest.nextTest();
           });
         };
       }
 
       AccessFuTest.addFunc(testOutputOrder(0));
       AccessFuTest.addFunc(testOutputOrder(1));
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -7346,37 +7346,20 @@ nsGlobalWindowInner::GetAttentionWithCyc
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 
   if (widget) {
     aError = widget->GetAttention(aCycleCount);
   }
 }
 
 void
-nsGlobalWindowInner::BeginWindowMove(Event& aMouseDownEvent, Element* aPanel,
+nsGlobalWindowInner::BeginWindowMove(Event& aMouseDownEvent,
                                      ErrorResult& aError)
 {
-  nsCOMPtr<nsIWidget> widget;
-
-  // if a panel was supplied, use its widget instead.
-#ifdef MOZ_XUL
-  if (aPanel) {
-    nsIFrame* frame = aPanel->GetPrimaryFrame();
-    if (!frame || !frame->IsMenuPopupFrame()) {
-      return;
-    }
-
-    widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
-  }
-  else {
-#endif
-    widget = GetMainWidget();
-#ifdef MOZ_XUL
-  }
-#endif
+  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 
   if (!widget) {
     return;
   }
 
   WidgetMouseEvent* mouseEvent =
     aMouseDownEvent.WidgetEventPtr()->AsMouseEvent();
   if (!mouseEvent || mouseEvent->mClass != eMouseEventClass) {
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -938,17 +938,16 @@ public:
   void Maximize();
   void Minimize();
   void Restore();
   void NotifyDefaultButtonLoaded(mozilla::dom::Element& aDefaultButton,
                                  mozilla::ErrorResult& aError);
   mozilla::dom::ChromeMessageBroadcaster* MessageManager();
   mozilla::dom::ChromeMessageBroadcaster* GetGroupMessageManager(const nsAString& aGroup);
   void BeginWindowMove(mozilla::dom::Event& aMouseDownEvent,
-                       mozilla::dom::Element* aPanel,
                        mozilla::ErrorResult& aError);
 
   already_AddRefed<mozilla::dom::Promise>
   PromiseDocumentFlushed(mozilla::dom::PromiseDocumentFlushedCallback& aCallback,
                          mozilla::ErrorResult& aError);
 
   void DidRefresh() override;
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -68,17 +68,17 @@ using namespace mozilla::ipc;
 struct IDBObjectStore::StructuredCloneWriteInfo
 {
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsTArray<StructuredCloneFile> mFiles;
   IDBDatabase* mDatabase;
   uint64_t mOffsetToKeyProp;
 
   explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
-    : mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
+    : mCloneBuffer(JS::StructuredCloneScope::DifferentProcess, nullptr,
                    nullptr)
     , mDatabase(aDatabase)
     , mOffsetToKeyProp(0)
   {
     MOZ_ASSERT(aDatabase);
 
     MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
   }
@@ -1326,17 +1326,17 @@ IDBObjectStore::DeserializeValue(JSConte
     nullptr,
     nullptr,
     nullptr
   };
 
   // FIXME: Consider to use StructuredCloneHolder here and in other
   //        deserializing methods.
   if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
-                              JS::StructuredCloneScope::SameProcessSameThread,
+                              JS::StructuredCloneScope::DifferentProcess,
                               aValue, &callbacks, &aCloneReadInfo)) {
     return false;
   }
 
   return true;
 }
 
 namespace {
@@ -1499,17 +1499,17 @@ private:
       nullptr,
       nullptr,
       nullptr,
       nullptr
     };
 
     if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
                                 JS_STRUCTURED_CLONE_VERSION,
-                                JS::StructuredCloneScope::SameProcessSameThread,
+                                JS::StructuredCloneScope::DifferentProcess,
                                 aValue, &callbacks, &mCloneReadInfo)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     return NS_OK;
   }
 
   void
@@ -1613,17 +1613,17 @@ private:
       nullptr,
       nullptr,
       nullptr,
       nullptr
     };
 
     if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
                                 JS_STRUCTURED_CLONE_VERSION,
-                                JS::StructuredCloneScope::SameProcessSameThread,
+                                JS::StructuredCloneScope::DifferentProcess,
                                 aValue, &callbacks, &mCloneReadInfo)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     return NS_OK;
   }
 
   void
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -161,21 +161,25 @@ MediaStreamTrack::Destroy()
   }
   if (mPrincipalHandleListener) {
     if (GetOwnedStream()) {
       RemoveListener(mPrincipalHandleListener);
     }
     mPrincipalHandleListener->Forget();
     mPrincipalHandleListener = nullptr;
   }
-  for (auto l : mTrackListeners) {
-    RemoveListener(l);
+  // Remove all listeners -- avoid iterating over the list we're removing from
+  const nsTArray<RefPtr<MediaStreamTrackListener>> trackListeners(mTrackListeners);
+  for (auto listener : trackListeners) {
+    RemoveListener(listener);
   }
-  for (auto l : mDirectTrackListeners) {
-    RemoveDirectListener(l);
+  // Do the same as above for direct listeners
+  const nsTArray<RefPtr<DirectMediaStreamTrackListener>> directTrackListeners(mDirectTrackListeners);
+  for (auto listener : directTrackListeners) {
+    RemoveDirectListener(listener);
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
                                                 DOMEventTargetHelper)
   tmp->Destroy();
--- a/dom/plugins/ipc/FunctionBroker.h
+++ b/dom/plugins/ipc/FunctionBroker.h
@@ -1191,16 +1191,32 @@ struct ResponseHandler<functionId, Resul
   typedef Marshaler<CLIENT, SelfType> RspUnmarshaler;
 
   // Fixed parameters are not used in the response phase.
   template <int tupleIndex, typename VarParam>
   static void CopyFixedParam(VarParam& aParam) {}
 };
 
 /**
+ * Reference-counted monitor, used to synchronize communication between a
+ * thread using a brokered API and the FunctionDispatch thread.
+ */
+class FDMonitor : public Monitor
+{
+public:
+  FDMonitor() : Monitor("FunctionDispatchThread lock")
+  {}
+
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FDMonitor)
+
+private:
+  ~FDMonitor() {}
+};
+
+/**
  * Data for hooking a function that we automatically broker in a remote
  * process.
  */
 template <FunctionHookId functionId, typename FunctionType>
 class FunctionBroker;
 
 template <FunctionHookId functionId, typename ResultType, typename ... ParamTypes>
 class FunctionBroker<functionId, ResultType HOOK_CALL (ParamTypes...)> :
@@ -1266,33 +1282,32 @@ protected:
     return BrokerCallServer(aClientId, aInTuple, aOutTuple,
                              std::index_sequence_for<ParamTypes...>{});
   }
 
   bool BrokerCallClient(uint32_t& aWinError, ResultType& aResult, ParamTypes&... aParameters) const;
   bool PostToDispatchThread(uint32_t& aWinError, ResultType& aRet, ParamTypes&... aParameters) const;
 
   static void
-  PostToDispatchHelper(const SelfType* bmhi, Monitor* monitor, bool* notified,
+  PostToDispatchHelper(const SelfType* bmhi, RefPtr<FDMonitor> monitor, bool* notified,
                        bool* ok, uint32_t* winErr, ResultType* r, ParamTypes*... p)
   {
     // Note: p is also non-null... its just hard to assert that.
     MOZ_ASSERT(bmhi && monitor && notified && ok && winErr && r);
     MOZ_ASSERT(*notified == false);
     *ok = bmhi->BrokerCallClient(*winErr, *r, *p...);
 
-    // We need to grab the lock to make sure that Wait() has been
-    // called in PostToDispatchThread.  We need that since we wake it with
-    // Notify().
-    // We also need to keep the lock until _after_ Notify() has been called
-    // since, after we set notified to true, a spurious wakeup could lead
-    // the other thread to wake and proceed -- and one of its first acts would
-    // be to destroy the Monitor.
-    MonitorAutoLock lock(*monitor);
-    *notified = true;
+    {
+      // We need to grab the lock to make sure that Wait() has been
+      // called in PostToDispatchThread.  We need that since we wake it with
+      // Notify().
+      MonitorAutoLock lock(*monitor);
+      *notified = true;
+    }
+
     monitor->Notify();
   };
 
   template<typename ... VarParams>
   ResultType
   RunFunction(FunctionType* aFunction, base::ProcessId aClientId,
                 VarParams&... aParams) const
   {
@@ -1451,29 +1466,29 @@ PostToDispatchThread(uint32_t& aWinError
                      ParamTypes&... aParameters) const
 {
   MOZ_ASSERT(!FunctionBrokerChild::GetInstance()->IsDispatchThread());
   HOOK_LOG(LogLevel::Debug,
            ("Posting broker task '%s' to dispatch thread", FunctionHookInfoType::mFunctionName.Data()));
 
   // Run PostToDispatchHelper on the dispatch thread.  It will notify our
   // waiting monitor when it is done.
-  Monitor monitor("FunctionDispatchThread Lock");
-  MonitorAutoLock lock(monitor);
+  RefPtr<FDMonitor> monitor(new FDMonitor());
+  MonitorAutoLock lock(*monitor);
   bool success = false;
   bool notified = false;
   FunctionBrokerChild::GetInstance()->PostToDispatchThread(
     NewRunnableFunction("FunctionDispatchThreadRunnable", &PostToDispatchHelper,
-                        this, &monitor, &notified, &success, &aWinError, &aRet,
+                        this, monitor, &notified, &success, &aWinError, &aRet,
                         &aParameters...));
 
   // We wait to be notified, testing that notified was actually set to make
   // sure this isn't a spurious wakeup.
   while (!notified) {
-    monitor.Wait();
+    monitor->Wait();
   }
   return success;
 }
 
 void AddBrokeredFunctionHooks(FunctionHookArray& aHooks);
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/svg/DOMSVGNumber.cpp
+++ b/dom/svg/DOMSVGNumber.cpp
@@ -106,46 +106,16 @@ DOMSVGNumber::DOMSVGNumber(nsISupports* 
   , mParent(aParent)
   , mListIndex(0)
   , mAttrEnum(0)
   , mIsAnimValItem(false)
   , mValue(0.0f)
 {
 }
 
-/* static */ already_AddRefed<DOMSVGNumber>
-DOMSVGNumber::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& aRv)
-{
-  nsCOMPtr<nsPIDOMWindowInner> window =
-    do_QueryInterface(aGlobal.GetAsSupports());
-  if (!window) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-
-  RefPtr<DOMSVGNumber> number = new DOMSVGNumber(window);
-  return number.forget();
-}
-
-/* static */ already_AddRefed<DOMSVGNumber>
-DOMSVGNumber::Constructor(const dom::GlobalObject& aGlobal, float aValue,
-                          ErrorResult& aRv)
-{
-  nsCOMPtr<nsPIDOMWindowInner> window =
-    do_QueryInterface(aGlobal.GetAsSupports());
-  if (!window) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-
-  RefPtr<DOMSVGNumber> number = new DOMSVGNumber(window);
-  number->SetValue(aValue, aRv);
-  return number.forget();
-}
-
 float
 DOMSVGNumber::Value()
 {
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
   return HasOwner() ? InternalItem() : mValue;
 }
--- a/dom/svg/DOMSVGNumber.h
+++ b/dom/svg/DOMSVGNumber.h
@@ -121,22 +121,16 @@ public:
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  static already_AddRefed<DOMSVGNumber>
-  Constructor(const dom::GlobalObject& aGlobal, ErrorResult& aRv);
-
-  static already_AddRefed<DOMSVGNumber>
-  Constructor(const dom::GlobalObject& aGlobal, float aValue, ErrorResult& aRv);
-
   float Value();
 
   void SetValue(float aValue, ErrorResult& aRv);
 
 private:
 
   nsSVGElement* Element() {
     return mList->Element();
--- a/dom/webidl/SVGNumber.webidl
+++ b/dom/webidl/SVGNumber.webidl
@@ -5,14 +5,12 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-[Constructor,
- Constructor(float value)]
 interface SVGNumber {
   [SetterThrows]
   attribute float value;
 };
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -441,22 +441,20 @@ partial interface Window {
   ChromeMessageBroadcaster getGroupMessageManager(DOMString aGroup);
 
   /**
    * On some operating systems, we must allow the window manager to
    * handle window dragging. This function tells the window manager to
    * start dragging the window. This function will fail unless called
    * while the left mouse button is held down, callers must check this.
    *
-   * The optional panel argument should be set when moving a panel.
-   *
    * Throws NS_ERROR_NOT_IMPLEMENTED if the OS doesn't support this.
    */
   [Throws, Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
-  void beginWindowMove(Event mouseDownEvent, optional Element? panel = null);
+  void beginWindowMove(Event mouseDownEvent);
 
   /**
    * Calls the given function as soon as a style or layout flush for the
    * top-level document is not necessary, and returns a Promise which
    * resolves to the callback's return value after it executes.
    *
    * In the event that the window goes away before a flush can occur, the
    * callback will still be called and the Promise resolved as the window
--- a/dom/xslt/xslt/txFormatNumberFunctionCall.cpp
+++ b/dom/xslt/xslt/txFormatNumberFunctionCall.cpp
@@ -260,16 +260,22 @@ txFormatNumberFunctionCall::evaluate(txI
 
     /*
      * FINALLY we're done with the parsing
      * now build the result string
      */
 
     value = fabs(value) * multiplier;
 
+    // Make sure the multiplier didn't push value to infinity.
+    if (value == mozilla::PositiveInfinity<double>()) {
+        return aContext->recycler()->getStringResult(format->mInfinity,
+                                                     aResult);
+    }
+
     // Prefix
     nsAutoString res(prefix);
 
     int bufsize;
     if (value > 1)
         bufsize = (int)log10(value) + 30;
     else
         bufsize = 1 + 30;
--- a/gfx/angle/checkout/out/gen/angle/id/commit.h
+++ b/gfx/angle/checkout/out/gen/angle/id/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "27cef491162b"
+#define ANGLE_COMMIT_HASH "fcbca0e873c3"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2018-03-14 13:28:50 -0700"
+#define ANGLE_COMMIT_DATE "2018-04-20 16:07:35 -0700"
--- a/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
+++ b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
@@ -125,17 +125,17 @@ enum TBasicType
     EbtAddress,  // should be deprecated??
 
     EbtAtomicCounter,
 
     // end of list
     EbtLast
 };
 
-constexpr14 static const char *GetBasicMangledName(TBasicType t)
+constexpr const char *GetBasicMangledName(TBasicType t)
 {
     switch (t)
     {
         case EbtFloat:
             return "f";
         case EbtInt:
             return "i";
         case EbtUInt:
--- a/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
@@ -15,45 +15,43 @@
 #include "common/string_utils.h"
 #include "compiler/translator/Common.h"
 
 namespace sh
 {
 
 namespace
 {
-
-constexpr14 size_t constStrlen(const char *str)
+constexpr size_t constStrlen(const char *str)
 {
     if (str == nullptr)
     {
         return 0u;
     }
     size_t len = 0u;
     while (*(str + len) != '\0')
     {
         ++len;
     }
     return len;
 }
-
 }
 
 class ImmutableString
 {
   public:
     // The data pointer passed in must be one of:
     //  1. nullptr (only valid with length 0).
     //  2. a null-terminated static char array like a string literal.
     //  3. a null-terminated pool allocated char array. This can't be c_str() of a local TString,
     //     since when a TString goes out of scope it clears its first character.
+    explicit constexpr ImmutableString(const char *data) : mData(data), mLength(constStrlen(data))
+    {
+    }
 
-    template<size_t N>
-    explicit constexpr ImmutableString(const char (&data)[N]) : mData(data), mLength(N-1) {}
-    explicit constexpr14 ImmutableString(const char *(&data)) : mData(data), mLength(constStrlen(data)) {}
     constexpr ImmutableString(const char *data, size_t length) : mData(data), mLength(length) {}
 
     ImmutableString(const std::string &str)
         : mData(AllocatePoolCharArray(str.c_str(), str.size())), mLength(str.size())
     {
     }
 
     constexpr ImmutableString(const ImmutableString &) = default;
@@ -68,41 +66,41 @@ class ImmutableString
     constexpr bool empty() const { return mLength == 0; }
     bool beginsWith(const char *prefix) const { return angle::BeginsWith(data(), prefix); }
     constexpr bool beginsWith(const ImmutableString &prefix) const
     {
         return mLength >= prefix.length() && memcmp(data(), prefix.data(), prefix.length()) == 0;
     }
     bool contains(const char *substr) const { return strstr(data(), substr) != nullptr; }
 
-    constexpr14 bool operator==(const ImmutableString &b) const
+    constexpr bool operator==(const ImmutableString &b) const
     {
         if (mLength != b.mLength)
         {
             return false;
         }
         return memcmp(data(), b.data(), mLength) == 0;
     }
-    constexpr14 bool operator!=(const ImmutableString &b) const { return !(*this == b); }
-    constexpr14 bool operator==(const char *b) const
+    constexpr bool operator!=(const ImmutableString &b) const { return !(*this == b); }
+    constexpr bool operator==(const char *b) const
     {
         if (b == nullptr)
         {
             return empty();
         }
         return strcmp(data(), b) == 0;
     }
-    constexpr14 bool operator!=(const char *b) const { return !(*this == b); }
+    constexpr bool operator!=(const char *b) const { return !(*this == b); }
     bool operator==(const std::string &b) const
     {
         return mLength == b.length() && memcmp(data(), b.c_str(), mLength) == 0;
     }
     bool operator!=(const std::string &b) const { return !(*this == b); }
 
-    constexpr14 bool operator<(const ImmutableString &b) const
+    constexpr bool operator<(const ImmutableString &b) const
     {
         if (mLength < b.mLength)
         {
             return true;
         }
         if (mLength > b.mLength)
         {
             return false;
@@ -111,17 +109,17 @@ class ImmutableString
     }
 
     template <size_t hashBytes>
     struct FowlerNollVoHash
     {
         static const size_t kFnvOffsetBasis;
         static const size_t kFnvPrime;
 
-        constexpr14 size_t operator()(const ImmutableString &a) const
+        constexpr size_t operator()(const ImmutableString &a) const
         {
             const char *data = a.data();
             size_t hash      = kFnvOffsetBasis;
             while ((*data) != '\0')
             {
                 hash = hash ^ (*data);
                 hash = hash * kFnvPrime;
                 ++data;
--- a/gfx/angle/checkout/src/compiler/translator/StaticType.h
+++ b/gfx/angle/checkout/src/compiler/translator/StaticType.h
@@ -33,21 +33,21 @@ static constexpr size_t kStaticMangledNa
 // This simple struct is needed so that a char array can be returned by value.
 struct StaticMangledName
 {
     // If this array is too small, the compiler will produce errors.
     char name[kStaticMangledNameMaxLength + 1] = {};
 };
 
 // Generates a mangled name for a TType given its parameters.
-static constexpr14 StaticMangledName BuildStaticMangledName(TBasicType basicType,
-                                                     TPrecision precision,
-                                                     TQualifier qualifier,
-                                                     unsigned char primarySize,
-                                                     unsigned char secondarySize)
+constexpr StaticMangledName BuildStaticMangledName(TBasicType basicType,
+                                                   TPrecision precision,
+                                                   TQualifier qualifier,
+                                                   unsigned char primarySize,
+                                                   unsigned char secondarySize)
 {
     StaticMangledName name = {};
     // When this function is executed constexpr (should be always),
     // name.name[at] is guaranteed by the compiler to never go out of bounds.
     size_t at = 0;
 
     bool isMatrix = primarySize > 1 && secondarySize > 1;
     bool isVector = primarySize > 1 && secondarySize == 1;
@@ -77,52 +77,71 @@ static constexpr14 StaticMangledName Bui
     }
 
     name.name[at++] = ';';
 
     name.name[at] = '\0';
     return name;
 }
 
+// This "variable" contains the mangled names for every constexpr-generated TType.
+// If kMangledNameInstance<B, P, Q, PS, SS> is used anywhere (specifally
+// in kInstance, below), this is where the appropriate type will be stored.
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char primarySize,
+          unsigned char secondarySize>
+static constexpr StaticMangledName kMangledNameInstance =
+    BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
+
+//
+// Generation and static allocation of TType values.
+//
+
+// This "variable" contains every constexpr-generated TType.
+// If kInstance<B, P, Q, PS, SS> is used anywhere (specifally
+// in Get, below), this is where the appropriate type will be stored.
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char primarySize,
+          unsigned char secondarySize>
+static constexpr TType kInstance =
+    TType(basicType,
+          precision,
+          qualifier,
+          primarySize,
+          secondarySize,
+          kMangledNameInstance<basicType, precision, qualifier, primarySize, secondarySize>.name);
+
 }  // namespace Helpers
 
 //
 // Fully-qualified type lookup.
 //
 
 template <TBasicType basicType,
           TPrecision precision,
           TQualifier qualifier,
           unsigned char primarySize,
           unsigned char secondarySize>
-constexpr14 const TType *Get()
+constexpr const TType *Get()
 {
     static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds");
     static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds");
-
-    static constexpr14 const auto kMangledNameInstance =
-        Helpers::BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
-
-    static constexpr14 const TType kInstance =
-        TType(basicType,
-              precision,
-              qualifier,
-              primarySize,
-              secondarySize,
-              kMangledNameInstance.name);
-
-    return &kInstance;
+    return &Helpers::kInstance<basicType, precision, qualifier, primarySize, secondarySize>;
 }
 
 //
 // Overloads
 //
 
 template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1>
-constexpr14 const TType *GetBasic()
+constexpr const TType *GetBasic()
 {
     return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>();
 }
 
 template <TBasicType basicType,
           TQualifier qualifier,
           unsigned char primarySize   = 1,
           unsigned char secondarySize = 1>
@@ -136,17 +155,17 @@ const TType *GetQualified()
 namespace Helpers
 {
 
 // Helper which takes secondarySize statically but primarySize dynamically.
 template <TBasicType basicType,
           TPrecision precision,
           TQualifier qualifier,
           unsigned char secondarySize>
-constexpr14 const TType *GetForVecMatHelper(unsigned char primarySize)
+constexpr const TType *GetForVecMatHelper(unsigned char primarySize)
 {
     static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
                       basicType == EbtBool,
                   "unsupported basicType");
     switch (primarySize)
     {
         case 1:
             return Get<basicType, precision, qualifier, 1, secondarySize>();
@@ -162,17 +181,17 @@ constexpr14 const TType *GetForVecMatHel
     }
 }
 
 }  // namespace Helpers
 
 template <TBasicType basicType,
           TPrecision precision = EbpUndefined,
           TQualifier qualifier = EvqGlobal>
-constexpr14 const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1)
+constexpr const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1)
 {
     static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
                       basicType == EbtBool,
                   "unsupported basicType");
     switch (secondarySize)
     {
         case 1:
             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 1>(primarySize);
@@ -184,17 +203,17 @@ constexpr14 const TType *GetForVecMat(un
             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 4>(primarySize);
         default:
             UNREACHABLE();
             return GetBasic<EbtVoid>();
     }
 }
 
 template <TBasicType basicType, TPrecision precision = EbpUndefined>
-constexpr14 const TType *GetForVec(TQualifier qualifier, unsigned char size)
+constexpr const TType *GetForVec(TQualifier qualifier, unsigned char size)
 {
     switch (qualifier)
     {
         case EvqGlobal:
             return Helpers::GetForVecMatHelper<basicType, precision, EvqGlobal, 1>(size);
         case EvqOut:
             return Helpers::GetForVecMatHelper<basicType, precision, EvqOut, 1>(size);
         default:
--- a/gfx/angle/checkout/src/compiler/translator/Symbol.h
+++ b/gfx/angle/checkout/src/compiler/translator/Symbol.h
@@ -157,17 +157,17 @@ class TInterfaceBlock : public TSymbol, 
 };
 
 // Immutable version of TParameter.
 struct TConstParameter
 {
     POOL_ALLOCATOR_NEW_DELETE();
     TConstParameter() : name(""), type(nullptr) {}
     explicit TConstParameter(const ImmutableString &n) : name(n), type(nullptr) {}
-    constexpr14 explicit TConstParameter(const TType *t) : name(""), type(t) {}
+    constexpr explicit TConstParameter(const TType *t) : name(""), type(t) {}
     TConstParameter(const ImmutableString &n, const TType *t) : name(n), type(t) {}
 
     // Both constructor arguments must be const.
     TConstParameter(ImmutableString *n, TType *t)       = delete;
     TConstParameter(const ImmutableString *n, TType *t) = delete;
     TConstParameter(ImmutableString *n, const TType *t) = delete;
 
     const ImmutableString name;
--- a/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp
@@ -248,41 +248,41 @@ const TSymbol *TSymbolTable::findBuiltIn
 
         if (symbol)
             return symbol;
     }
 
     return nullptr;
 }
 
-constexpr14 bool IsGenType(const TType *type)
+constexpr bool IsGenType(const TType *type)
 {
     if (type)
     {
         TBasicType basicType = type->getBasicType();
         return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType ||
                basicType == EbtGenBType;
     }
 
     return false;
 }
 
-constexpr14 bool IsVecType(const TType *type)
+constexpr bool IsVecType(const TType *type)
 {
     if (type)
     {
         TBasicType basicType = type->getBasicType();
         return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec ||
                basicType == EbtBVec;
     }
 
     return false;
 }
 
-constexpr14 const TType *SpecificType(const TType *type, int size)
+constexpr const TType *SpecificType(const TType *type, int size)
 {
     ASSERT(size >= 1 && size <= 4);
 
     if (!type)
     {
         return nullptr;
     }
 
@@ -302,17 +302,17 @@ constexpr14 const TType *SpecificType(co
         case EbtGenBType:
             return StaticType::GetForVec<EbtBool>(type->getQualifier(),
                                                            static_cast<unsigned char>(size));
         default:
             return type;
     }
 }
 
-constexpr14 const TType *VectorType(const TType *type, int size)
+constexpr const TType *VectorType(const TType *type, int size)
 {
     ASSERT(size >= 2 && size <= 4);
 
     if (!type)
     {
         return nullptr;
     }
 
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
@@ -374,17 +374,18 @@ const gl::AttachmentList &FramebufferD3D
     }
 
     // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel
     // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel
     // shader. We add a dummy texture as render target in such case.
     if (mRenderer->getWorkarounds().addDummyTextureNoRenderTarget &&
         colorAttachmentsForRender.empty() && activeProgramOutputs.any())
     {
-        ASSERT(static_cast<size_t>(activeProgramOutputs.size()) <= 32);
+        static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32,
+                      "Size of active program outputs should less or equal than 32.");
         const GLuint activeProgramLocation = static_cast<GLuint>(
             gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits())));
 
         if (mDummyAttachment.isAttached() &&
             (mDummyAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation)
         {
             colorAttachmentsForRender.push_back(&mDummyAttachment);
         }
--- a/gfx/angle/cherries.log
+++ b/gfx/angle/cherries.log
@@ -1,61 +1,51 @@
-commit 27cef491162bfa5d5d69cf65758bd9b85033d339
+commit fcbca0e873c3222f13578a07294349c03ce44ab4
 Author: Dzmitry Malyshau <kvark@mozilla.com>
 Date:   Fri Mar 9 16:37:22 2018 -0500
 
     Update driver constants on program change. Comes with a new SamplerMetadataUpdateOnSetProgram test.
     
     This is a fix for a graphics problem we've been seeing for a while with WebRender+Angle on Nvidia/Windows. The sampler metadata doesn't get updated properly for some of the draw calls, since it's not invalidated on program change (this is what the CL is fixing). Extra entries get filled with garbage data because the constant buffer is updated with `MAP_WRITE_DISCARD`, and only those samplers are updated that the current program has. This may generally occur undetected, if not for our `textureSize` calls that appear to go the NV-specific Angle workaround path that ignores our `baseLevel = 0` and instead picks the one from the driver constants (which contains garbage), leading to either zeroes returned or even crashing the driver sometimes...
     
     BUG=angleproject:2399
     
     Change-Id: Ie2bef32184e2305c7255299933b899eb3fffb7ab
     Reviewed-on: https://chromium-review.googlesource.com/949412
     Reviewed-by: Jamie Madill <jmadill@chromium.org>
     Reviewed-by: Geoff Lang <geofflang@chromium.org>
     Commit-Queue: Geoff Lang <geofflang@chromium.org>
 
-commit 7edc21933ef15d10e5790e6bfb7f9fd62f13be58
+commit 17c34b476b3a941ee749165b6a360f8a3488960d
 Author: Frank Henigman <fjhenigman@chromium.org>
 Date:   Wed Feb 28 15:47:13 2018 -0500
 
     Add missing #include.
     
     Would not compile locally on Linux without adding #include <algorithm>.
     
     BUG=none
     
     Change-Id: I2f817faf681234c0e7eeeda0ad837e8285d9071a
     Reviewed-on: https://chromium-review.googlesource.com/941613
     Commit-Queue: Frank Henigman <fjhenigman@chromium.org>
     Reviewed-by: Jamie Madill <jmadill@chromium.org>
     Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
     Reviewed-by: Luc Ferron <lucferron@chromium.org>
 
-commit 1f7cc32a8d49ff3880660f32e3a4aca7bbc1f4e8
+commit eb0da26df7dc6cd45ee17455633bdec2efbaf322
 Author: Jeff Gilbert <jgilbert@mozilla.com>
 Date:   Thu Mar 1 17:08:35 2018 -0800
 
     Fix R11F_G11F_B10F/RGB/FLOAT SKIP_PIXELS=1 uploads.
     
     Bug: angleproject:2385
     
     Change-Id: I555000f23314441084895e275824d2eb48ba7041
 
-commit bdc28a041ea0090438790756ff63d8944f57d4cc
-Author: Jeff Gilbert <jgilbert@mozilla.com>
-Date:   Wed Feb 28 17:46:39 2018 -0800
-
-    Support c++11 non-relaxed-constexpr with constexpr14.
-    
-    BUG=angleproject:2384
-    
-    Change-Id: I0448aef7184c9060db016dee512b5fec29960f46
-
 commit 7d510ab511cd502220f81507189a2861958e22fd
 Author: Jeff Gilbert <jgilbert@mozilla.com>
 Date:   Mon Feb 26 16:30:06 2018 -0800
 
     Move constructors may not be marked explicit.
     
     BUG=angleproject:2383
     
--- a/gfx/angle/targets/angle_common/moz.build
+++ b/gfx/angle/targets/angle_common/moz.build
@@ -32,17 +32,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/angle_gpu_info_util/moz.build
+++ b/gfx/angle/targets/angle_gpu_info_util/moz.build
@@ -32,17 +32,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/angle_image_util/moz.build
+++ b/gfx/angle/targets/angle_image_util/moz.build
@@ -31,17 +31,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/libANGLE/moz.build
+++ b/gfx/angle/targets/libANGLE/moz.build
@@ -37,17 +37,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/libEGL/moz.build
+++ b/gfx/angle/targets/libEGL/moz.build
@@ -34,17 +34,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/libGLESv2/moz.build
+++ b/gfx/angle/targets/libGLESv2/moz.build
@@ -38,17 +38,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/preprocessor/moz.build
+++ b/gfx/angle/targets/preprocessor/moz.build
@@ -31,17 +31,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/targets/translator/moz.build
+++ b/gfx/angle/targets/translator/moz.build
@@ -34,17 +34,16 @@ DEFINES['_CRT_SECURE_NO_DEPRECATE'] = Tr
 DEFINES['_HAS_EXCEPTIONS'] = '0'
 DEFINES['_SCL_SECURE_NO_DEPRECATE'] = True
 DEFINES['_SECURE_ATL'] = True
 DEFINES['_UNICODE'] = True
 #DEFINES['_USING_V110_SDK71_'] = True
 #DEFINES['_WIN32_WINNT'] = '0x0A00'
 #DEFINES['_WINDOWS'] = True
 #DEFINES['__STD_C'] = True
-#DEFINES['constexpr14'] = 'constexpr'
 
 LOCAL_INCLUDES += [
     '../../checkout/',
     '../../checkout/include/',
     '../../checkout/out/gen/',
     '../../checkout/out/gen/angle/',
     '../../checkout/src/',
     '../../checkout/src/common/third_party/base/',
--- a/gfx/angle/update-angle.py
+++ b/gfx/angle/update-angle.py
@@ -1,9 +1,9 @@
-#!/bin/python3
+#! /usr/bin/env python3
 assert __name__ == '__main__'
 
 '''
 To update ANGLE in Gecko, use Windows with git-bash, and setup depot_tools and
 python3.
 
 Upstream: https://chromium.googlesource.com/angle/angle
 
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -253,17 +253,17 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
     FT_Library library = Factory::NewFTLibrary();
     MOZ_ASSERT(library);
     Factory::SetFTLibrary(library);
   }
 #endif
 
   // Make sure to do this *after* we update gfxVars above.
   if (gfxVars::UseWebRender()) {
-    wr::WebRenderAPI::InitExternalLogHandler();
+    wr::WebRenderAPI::InitRustLogForGpuProcess();
 
     wr::RenderThread::Start();
   }
 
   VRManager::ManagerInit();
   // Send a message to the UI process that we're done.
   GPUDeviceData data;
   RecvGetDeviceStatus(&data);
@@ -489,17 +489,17 @@ GPUParent::ActorDestroy(ActorDestroyReas
   dom::VideoDecoderManagerParent::ShutdownVideoBridge();
   CompositorThreadHolder::Shutdown();
   VRListenerThreadHolder::Shutdown();
   // There is a case that RenderThread exists when gfxVars::UseWebRender() is false.
   // This could happen when WebRender was fallbacked to compositor.
   if (wr::RenderThread::Get()) {
     wr::RenderThread::ShutDown();
 
-    wr::WebRenderAPI::ShutdownExternalLogHandler();
+    wr::WebRenderAPI::ShutdownRustLogForGpuProcess();
   }
   Factory::ShutDown();
 #if defined(XP_WIN)
   DeviceManagerDx::Shutdown();
 #endif
   LayerTreeOwnerTracker::Shutdown();
   gfxVars::Shutdown();
   gfxConfig::Shutdown();
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1014,20 +1014,16 @@ gfxPlatform::Shutdown()
 /* static */ void
 gfxPlatform::InitLayersIPC()
 {
   if (sLayersIPCIsUp) {
     return;
   }
   sLayersIPCIsUp = true;
 
-  if (gfxVars::UseWebRender()) {
-    wr::WebRenderAPI::InitExternalLogHandler();
-  }
-
   if (XRE_IsContentProcess()) {
     if (gfxVars::UseOMTP()) {
       layers::PaintThread::Start();
     }
   } else if (XRE_IsParentProcess()) {
     if (gfxVars::UseWebRender()) {
       wr::RenderThread::Start();
     }
@@ -1070,20 +1066,16 @@ gfxPlatform::ShutdownLayersIPC()
 
           Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
         }
 
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
-
-    if (gfxVars::UseWebRender()) {
-      wr::WebRenderAPI::ShutdownExternalLogHandler();
-    }
 }
 
 void
 gfxPlatform::WillShutdown()
 {
     // Destoy these first in case they depend on backend-specific resources.
     // Otherwise, the backend's destructor would be called before the
     // base gfxPlatform destructor.
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -6,16 +6,17 @@ license = "MPL-2.0"
 
 [dependencies]
 rayon = "1"
 thread_profiler = "0.1.1"
 euclid = { version = "0.17", features = ["serde"] }
 app_units = "0.6"
 gleam = "0.4.32"
 log = "0.4"
+env_logger = "0.5"
 
 [dependencies.webrender]
 path = "../webrender"
 version = "0.57.2"
 default-features = false
 features = ["capture"]
 
 [target.'cfg(target_os = "windows")'.dependencies]
--- a/gfx/webrender_bindings/Moz2DImageRenderer.cpp
+++ b/gfx/webrender_bindings/Moz2DImageRenderer.cpp
@@ -39,21 +39,34 @@ namespace std {
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace wr {
 
 struct FontTemplate {
-  const uint8_t *mData;
+  const uint8_t* mData;
   size_t mSize;
   uint32_t mIndex;
-  const VecU8 *mVec;
+  const VecU8* mVec;
   RefPtr<UnscaledFont> mUnscaledFont;
+
+  FontTemplate()
+    : mData(nullptr)
+    , mSize(0)
+    , mIndex(0)
+    , mVec(nullptr)
+  {}
+
+  ~FontTemplate() {
+    if (mVec) {
+      wr_dec_ref_arc(mVec);
+    }
+  }
 };
 
 StaticMutex sFontDataTableLock;
 std::unordered_map<FontKey, FontTemplate> sFontDataTable;
 
 // Fixed-size ring buffer logging font deletion events to aid debugging.
 static struct FontDeleteLog {
   static const size_t MAX_ENTRIES = 256;
@@ -70,113 +83,114 @@ static struct FontDeleteLog {
     AddEntry(AsUint64(aKey));
   }
 
   // Store namespace clears as font id 0, since this will never be allocated.
   void Add(WrIdNamespace aNamespace) {
     AddEntry(AsUint64(WrFontKey { aNamespace, 0 }));
   }
 
+  void AddAll() {
+    AddEntry(0);
+  }
+
   // Find a matching entry in the log, searching backwards starting at the newest
   // entry and finishing with the oldest entry. Returns a brief description of why
   // the font was deleted, if known.
   const char* Find(WrFontKey aKey) {
     uint64_t keyEntry = AsUint64(aKey);
     uint64_t namespaceEntry = AsUint64(WrFontKey { aKey.mNamespace, 0 });
     size_t offset = mNextEntry;
     do {
       offset = (offset + MAX_ENTRIES - 1) % MAX_ENTRIES;
       if (mEntries[offset] == keyEntry) {
         return "deleted font";
       } else if (mEntries[offset] == namespaceEntry) {
         return "cleared namespace";
+      } else if (!mEntries[offset]) {
+        return "cleared all";
       }
     } while (offset != mNextEntry);
     return "unknown font";
   }
 } sFontDeleteLog;
 
 void
+ClearAllBlobImageResources() {
+  StaticMutexAutoLock lock(sFontDataTableLock);
+  sFontDeleteLog.AddAll();
+  sFontDataTable.clear();
+}
+
+extern "C" {
+void
 ClearBlobImageResources(WrIdNamespace aNamespace) {
   StaticMutexAutoLock lock(sFontDataTableLock);
   sFontDeleteLog.Add(aNamespace);
   for (auto i = sFontDataTable.begin(); i != sFontDataTable.end();) {
     if (i->first.mNamespace == aNamespace) {
-      if (i->second.mVec) {
-        wr_dec_ref_arc(i->second.mVec);
-      }
       i = sFontDataTable.erase(i);
     } else {
       i++;
     }
   }
 }
 
-extern "C" {
 void
 AddFontData(WrFontKey aKey, const uint8_t *aData, size_t aSize, uint32_t aIndex, const ArcVecU8 *aVec) {
   StaticMutexAutoLock lock(sFontDataTableLock);
   auto i = sFontDataTable.find(aKey);
   if (i == sFontDataTable.end()) {
-    FontTemplate font;
+    FontTemplate& font = sFontDataTable[aKey];
     font.mData = aData;
     font.mSize = aSize;
     font.mIndex = aIndex;
     font.mVec = wr_add_ref_arc(aVec);
-    sFontDataTable[aKey] = font;
   }
 }
 
 void
 AddNativeFontHandle(WrFontKey aKey, void* aHandle, uint32_t aIndex) {
   StaticMutexAutoLock lock(sFontDataTableLock);
   auto i = sFontDataTable.find(aKey);
   if (i == sFontDataTable.end()) {
-    FontTemplate font;
-    font.mData = nullptr;
-    font.mSize = 0;
-    font.mIndex = 0;
-    font.mVec = nullptr;
+    FontTemplate& font = sFontDataTable[aKey];
 #ifdef XP_MACOSX
     font.mUnscaledFont = new UnscaledFontMac(reinterpret_cast<CGFontRef>(aHandle), true);
 #elif defined(XP_WIN)
     font.mUnscaledFont = new UnscaledFontDWrite(reinterpret_cast<IDWriteFontFace*>(aHandle), nullptr);
 #elif defined(ANDROID)
     font.mUnscaledFont = new UnscaledFontFreeType(reinterpret_cast<const char*>(aHandle), aIndex);
 #else
     font.mUnscaledFont = new UnscaledFontFontconfig(reinterpret_cast<const char*>(aHandle), aIndex);
 #endif
-    sFontDataTable[aKey] = font;
   }
 }
 
 void
 DeleteFontData(WrFontKey aKey) {
   StaticMutexAutoLock lock(sFontDataTableLock);
   sFontDeleteLog.Add(aKey);
   auto i = sFontDataTable.find(aKey);
   if (i != sFontDataTable.end()) {
-    if (i->second.mVec) {
-      wr_dec_ref_arc(i->second.mVec);
-    }
     sFontDataTable.erase(i);
   }
 }
 }
 
 RefPtr<UnscaledFont>
 GetUnscaledFont(Translator *aTranslator, wr::FontKey key) {
   StaticMutexAutoLock lock(sFontDataTableLock);
   auto i = sFontDataTable.find(key);
   if (i == sFontDataTable.end()) {
     gfxDevCrash(LogReason::UnscaledFontNotFound) << "Failed to get UnscaledFont entry for FontKey " << key.mHandle
                                                  << " because " << sFontDeleteLog.Find(key);
     return nullptr;
   }
-  auto &data = i->second;
+  FontTemplate &data = i->second;
   if (data.mUnscaledFont) {
     return data.mUnscaledFont;
   }
   MOZ_ASSERT(data.mData);
   FontType type =
 #ifdef XP_MACOSX
     FontType::MAC;
 #elif defined(XP_WIN)
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -92,25 +92,29 @@ RenderThread::ShutDown()
   task.Wait();
 
   sRenderThread = nullptr;
 #ifdef XP_WIN
   widget::WinCompositorWindowThread::ShutDown();
 #endif
 }
 
+extern void ClearAllBlobImageResources();
+
 void
 RenderThread::ShutDownTask(layers::SynchronousTask* aTask)
 {
   layers::AutoCompleteTask complete(aTask);
   MOZ_ASSERT(IsInRenderThread());
 
   // Releasing on the render thread will allow us to avoid dispatching to remove
   // remaining textures from the texture map.
   layers::SharedSurfacesParent::Shutdown();
+
+  ClearAllBlobImageResources();
 }
 
 // static
 MessageLoop*
 RenderThread::Loop()
 {
   return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
 }
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -270,27 +270,29 @@ void
 TransactionWrapper::UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
                                          const layers::FrameMetrics::ViewID& aScrollId,
                                          const wr::LayoutPoint& aScrollPosition)
 {
   wr_transaction_scroll_layer(mTxn, aPipelineId, aScrollId, aScrollPosition);
 }
 
 /*static*/ void
-WebRenderAPI::InitExternalLogHandler()
+WebRenderAPI::InitRustLogForGpuProcess()
 {
-  // Redirect the webrender's log to gecko's log system.
-  // The current log level is "error".
-  mozilla::wr::wr_init_external_log_handler(wr::WrLogLevelFilter::Error);
+  MOZ_ASSERT(XRE_IsGPUProcess());
+  // Initialize rust log for gpu process.
+  // Rust log of non-gpu process is initialized by Servo_Initialize()
+  mozilla::wr::wr_init_log_for_gpu_process();
 }
 
 /*static*/ void
-WebRenderAPI::ShutdownExternalLogHandler()
+WebRenderAPI::ShutdownRustLogForGpuProcess()
 {
-  mozilla::wr::wr_shutdown_external_log_handler();
+  MOZ_ASSERT(XRE_IsGPUProcess());
+  mozilla::wr::wr_shutdown_log_for_gpu_process();
 }
 
 /*static*/ already_AddRefed<WebRenderAPI>
 WebRenderAPI::Create(layers::CompositorBridgeParent* aBridge,
                      RefPtr<widget::CompositorWidget>&& aWidget,
                      const wr::WrWindowId& aWindowId,
                      LayoutDeviceIntSize aSize)
 {
@@ -352,18 +354,16 @@ WebRenderAPI::CreateDocument(LayoutDevic
   return api.forget();
 }
 
 wr::WrIdNamespace
 WebRenderAPI::GetNamespace() {
   return wr_api_get_namespace(mDocHandle);
 }
 
-extern void ClearBlobImageResources(WrIdNamespace aNamespace);
-
 WebRenderAPI::~WebRenderAPI()
 {
   if (!mRootDocumentApi) {
     wr_api_delete_document(mDocHandle);
   }
 
   if (!mRootApi) {
     RenderThread::Get()->SetDestroyed(GetId());
@@ -371,31 +371,16 @@ WebRenderAPI::~WebRenderAPI()
     layers::SynchronousTask task("Destroy WebRenderAPI");
     auto event = MakeUnique<RemoveRenderer>(&task);
     RunOnRenderThread(Move(event));
     task.Wait();
 
     wr_api_shut_down(mDocHandle);
   }
 
-  // wr_api_get_namespace cannot be marked destructor-safe because it has a
-  // return value, and we can't call it if MOZ_BUILD_WEBRENDER is not defined
-  // because it's not destructor-safe. So let's just ifdef around it. This is
-  // basically a hack to get around compile-time warnings, this code never runs
-  // unless MOZ_BUILD_WEBRENDER is defined anyway.
-#ifdef MOZ_BUILD_WEBRENDER
-  wr::WrIdNamespace ns = GetNamespace();
-#else
-  wr::WrIdNamespace ns{0};
-#endif
-
-  // Clean up any resources the blob image renderer is holding onto that
-  // can no longer be used once this WR API instance goes away.
-  ClearBlobImageResources(ns);
-
   wr_api_delete(mDocHandle);
 }
 
 void
 WebRenderAPI::SendTransaction(TransactionBuilder& aTxn)
 {
   wr_transaction_update_resources(aTxn.Raw(), aTxn.RawUpdates());
   wr_api_send_transaction(mDocHandle, aTxn.Raw());
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -169,18 +169,18 @@ public:
   static already_AddRefed<WebRenderAPI> Create(layers::CompositorBridgeParent* aBridge,
                                                RefPtr<widget::CompositorWidget>&& aWidget,
                                                const wr::WrWindowId& aWindowId,
                                                LayoutDeviceIntSize aSize);
 
   already_AddRefed<WebRenderAPI> CreateDocument(LayoutDeviceIntSize aSize, int8_t aLayerIndex);
 
   // Redirect the WR's log to gfxCriticalError/Note.
-  static void InitExternalLogHandler();
-  static void ShutdownExternalLogHandler();
+  static void InitRustLogForGpuProcess();
+  static void ShutdownRustLogForGpuProcess();
 
   already_AddRefed<WebRenderAPI> Clone();
 
   wr::WindowId GetId() const { return mId; }
 
   bool HitTest(const wr::WorldPoint& aPoint,
                wr::WrPipelineId& aOutPipelineId,
                layers::FrameMetrics::ViewID& aOutScrollId,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,8 +1,9 @@
+use std::env;
 use std::ffi::{CStr, CString};
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::ptr;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::os::raw::{c_void, c_char, c_float};
 use gleam::gl;
@@ -15,16 +16,17 @@ use webrender::{ApiRecordingReceiver, Bi
 use webrender::{AsyncPropertySampler, PipelineInfo, SceneBuilderHooks};
 use webrender::{ProgramCache, UploadMethod, VertexUsageHint};
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dImageRenderer;
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
 use log;
+use env_logger::filter::Filter;
 
 #[cfg(target_os = "windows")]
 use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
 
 #[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 #[cfg(target_os = "macos")]
 use core_graphics::font::CGFont;
@@ -58,31 +60,29 @@ impl WrExternalImageBufferType {
 /// cbindgen:field-names=[mHandle]
 /// cbindgen:derive-lt=true
 /// cbindgen:derive-lte=true
 type WrEpoch = Epoch;
 /// cbindgen:field-names=[mHandle]
 /// cbindgen:derive-lt=true
 /// cbindgen:derive-lte=true
 /// cbindgen:derive-neq=true
-type WrIdNamespace = IdNamespace;
+pub type WrIdNamespace = IdNamespace;
 
 /// cbindgen:field-names=[mNamespace, mHandle]
 type WrPipelineId = PipelineId;
 /// cbindgen:field-names=[mNamespace, mHandle]
 /// cbindgen:derive-neq=true
 type WrImageKey = ImageKey;
 /// cbindgen:field-names=[mNamespace, mHandle]
 pub type WrFontKey = FontKey;
 /// cbindgen:field-names=[mNamespace, mHandle]
 type WrFontInstanceKey = FontInstanceKey;
 /// cbindgen:field-names=[mNamespace, mHandle]
 type WrYuvColorSpace = YuvColorSpace;
-/// cbindgen:field-names=[mNamespace, mHandle]
-type WrLogLevelFilter = log::LevelFilter;
 
 fn make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
     if ptr.is_null() {
         &[]
     } else {
         unsafe { slice::from_raw_parts(ptr, len) }
     }
 }
@@ -2355,35 +2355,52 @@ extern "C" {
 type ExternalMessageHandler = unsafe extern "C" fn(msg: *const c_char);
 
 struct WrExternalLogHandler {
     error_msg: ExternalMessageHandler,
     warn_msg: ExternalMessageHandler,
     info_msg: ExternalMessageHandler,
     debug_msg: ExternalMessageHandler,
     trace_msg: ExternalMessageHandler,
-    log_level: log::Level,
+    inner: Filter
 }
 
 impl WrExternalLogHandler {
-    fn new(log_level: log::Level) -> WrExternalLogHandler {
+    fn new() -> Self {
+        use env_logger::filter::Builder;
+
+        // Filter cration code is borrowed from Servo_Initialize()
+        let mut builder = Builder::new();
+        let default_level = if cfg!(debug_assertions) { "warn" } else { "error" };
+        let builder = match env::var("RUST_LOG") {
+            Ok(v) => builder.parse(&v),
+            _ => builder.parse(default_level),
+        };
+
         WrExternalLogHandler {
             error_msg: gfx_critical_note,
-            warn_msg: gfx_critical_note,
+            warn_msg: gecko_printf_stderr_output,
             info_msg: gecko_printf_stderr_output,
             debug_msg: gecko_printf_stderr_output,
             trace_msg: gecko_printf_stderr_output,
-            log_level: log_level,
+            inner: builder.build(),
         }
     }
+
+    fn init() -> Result<(), log::SetLoggerError> {
+        let logger = Self::new();
+
+        log::set_max_level(logger.inner.filter());
+        log::set_boxed_logger(Box::new(logger))
+    }
 }
 
 impl log::Log for WrExternalLogHandler {
     fn enabled(&self, metadata : &log::Metadata) -> bool {
-        metadata.level() <= self.log_level
+        self.inner.enabled(metadata)
     }
 
     fn log(&self, record: &log::Record) {
         if self.enabled(record.metadata()) {
             // For file path and line, please check the record.location().
             let msg = CString::new(format!("WR: {}",
                                            record.args())).unwrap();
             unsafe {
@@ -2398,26 +2415,23 @@ impl log::Log for WrExternalLogHandler {
         }
     }
 
     fn flush(&self) {
     }
 }
 
 #[no_mangle]
-pub extern "C" fn wr_init_external_log_handler(log_filter: WrLogLevelFilter) {
-    log::set_max_level(log_filter);
-    let logger = Box::new(WrExternalLogHandler::new(log_filter
-                                                    .to_level()
-                                                    .unwrap_or(log::Level::Error)));
-    let _ = log::set_logger(unsafe { &*Box::into_raw(logger) });
+pub extern "C" fn wr_init_log_for_gpu_process() {
+    WrExternalLogHandler::init().unwrap();
 }
 
 #[no_mangle]
-pub extern "C" fn wr_shutdown_external_log_handler() {
+pub extern "C" fn wr_shutdown_log_for_gpu_process() {
+    // log does not support shutdown
 }
 
 #[no_mangle]
 pub extern "C" fn wr_root_scroll_node_id() -> usize {
     // The PipelineId doesn't matter here, since we just want the numeric part of the id
     // produced for any given root reference frame.
     match ClipId::root_scroll_node(PipelineId(0, 0)) {
         ClipId::Clip(id, _) => id,
--- a/gfx/webrender_bindings/src/lib.rs
+++ b/gfx/webrender_bindings/src/lib.rs
@@ -8,16 +8,17 @@ extern crate webrender;
 extern crate euclid;
 extern crate app_units;
 extern crate gleam;
 extern crate rayon;
 extern crate thread_profiler;
 
 #[macro_use]
 extern crate log;
+extern crate env_logger;
 
 #[cfg(target_os = "windows")]
 extern crate dwrote;
 
 #[cfg(target_os = "macos")]
 extern crate core_foundation;
 #[cfg(target_os = "macos")]
 extern crate core_graphics;
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -489,27 +489,29 @@ impl BlobImageRenderer for Moz2dImageRen
     }
     fn delete_font(&mut self, font: FontKey) {
         unsafe { DeleteFontData(font); }
     }
 
     fn delete_font_instance(&mut self, _key: FontInstanceKey) {
     }
 
-    fn clear_namespace(&mut self, _namespace: IdNamespace) {
+    fn clear_namespace(&mut self, namespace: IdNamespace) {
+        unsafe { ClearBlobImageResources(namespace); }
     }
 }
 
-use bindings::WrFontKey;
+use bindings::{WrFontKey, WrIdNamespace};
 
 #[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &Arc<Vec> to an extern function
 extern "C" {
     fn AddFontData(key: WrFontKey, data: *const u8, size: usize, index: u32, vec: &ArcVecU8);
     fn AddNativeFontHandle(key: WrFontKey, handle: *mut c_void, index: u32);
     fn DeleteFontData(key: WrFontKey);
+    fn ClearBlobImageResources(namespace: WrIdNamespace);
 }
 
 impl Moz2dImageRenderer {
     pub fn new(workers: Arc<ThreadPool>) -> Self {
         let (tx, rx) = channel();
         Moz2dImageRenderer {
             blob_commands: HashMap::new(),
             rendered_images: HashMap::new(),
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -96,41 +96,16 @@ enum class ImageFormat : uint32_t {
 enum class ImageRendering : uint32_t {
   Auto = 0,
   CrispEdges = 1,
   Pixelated = 2,
 
   Sentinel /* this must be last for serialization purposes. */
 };
 
-// An enum representing the available verbosity level filters of the logger.
-//
-// A `LevelFilter` may be compared directly to a [`Level`]. Use this type
-// to get and set the maximum log level with [`max_level()`] and [`set_max_level`].
-//
-// [`Level`]: enum.Level.html
-// [`max_level()`]: fn.max_level.html
-// [`set_max_level`]: fn.set_max_level.html
-enum class LevelFilter : uintptr_t {
-  // A level lower than all log levels.
-  Off,
-  // Corresponds to the `Error` log level.
-  Error,
-  // Corresponds to the `Warn` log level.
-  Warn,
-  // Corresponds to the `Info` log level.
-  Info,
-  // Corresponds to the `Debug` log level.
-  Debug,
-  // Corresponds to the `Trace` log level.
-  Trace,
-
-  Sentinel /* this must be last for serialization purposes. */
-};
-
 enum class LineOrientation : uint8_t {
   Vertical,
   Horizontal,
 
   Sentinel /* this must be last for serialization purposes. */
 };
 
 enum class LineStyle : uint8_t {
@@ -775,18 +750,16 @@ struct GlyphOptions {
   bool operator==(const GlyphOptions& aOther) const {
     return render_mode == aOther.render_mode &&
            flags == aOther.flags;
   }
 };
 
 using WrYuvColorSpace = YuvColorSpace;
 
-using WrLogLevelFilter = LevelFilter;
-
 struct ByteSlice {
   const uint8_t *buffer;
   uintptr_t len;
 
   bool operator==(const ByteSlice& aOther) const {
     return buffer == aOther.buffer &&
            len == aOther.len;
   }
@@ -1384,17 +1357,17 @@ WR_INLINE
 void wr_dp_save(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dump_display_list(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
-void wr_init_external_log_handler(WrLogLevelFilter aLogFilter)
+void wr_init_log_for_gpu_process()
 WR_FUNC;
 
 extern bool wr_moz2d_render_cb(ByteSlice aBlob,
                                uint32_t aWidth,
                                uint32_t aHeight,
                                ImageFormat aFormat,
                                const uint16_t *aTileSize,
                                const TileOffset *aTileOffset,
@@ -1578,17 +1551,17 @@ WR_FUNC;
 
 WR_INLINE
 void wr_set_item_tag(WrState *aState,
                      uint64_t aScrollId,
                      uint16_t aHitInfo)
 WR_FUNC;
 
 WR_INLINE
-void wr_shutdown_external_log_handler()
+void wr_shutdown_log_for_gpu_process()
 WR_FUNC;
 
 WR_INLINE
 void wr_state_delete(WrState *aState)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
 WrState *wr_state_new(WrPipelineId aPipelineId,
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -684,23 +684,17 @@ bool Pickle::WriteWString(const std::wst
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
 #endif
 }
 
 bool Pickle::WriteData(const char* data, uint32_t length) {
-#ifdef FUZZING
-  std::string v(data, length);
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzData(v, v.size());
-  return WriteInt(v.size()) && WriteBytes(v.data(), v.size());
-#else
    return WriteInt(length) && WriteBytes(data, length);
-#endif
 }
 
 void Pickle::InputBytes(const char* data, uint32_t length) {
   buffers_.WriteBytes(data, length);
 }
 
 int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
   size_t pos = buffers_.Size() - offset;
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -749,16 +749,19 @@ bool Channel::ChannelImpl::ProcessOutgoi
 
 bool Channel::ChannelImpl::Send(Message* message) {
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   DLOG(INFO) << "sending message @" << message << " on channel @" << this
              << " with type " << message->type()
              << " (" << output_queue_.size() << " in queue)";
 #endif
 
+#ifdef FUZZING
+  message = Singleton<mozilla::ipc::Faulty>::get()->MutateIPCMessage("Channel::ChannelImpl::Send", message);
+#endif
 
   // If the channel has been closed, ProcessOutgoingMessages() is never going
   // to pop anything off output_queue; output_queue will only get emptied when
   // the channel is destructed.  We might as well delete message now, instead
   // of waiting for the channel to be destructed.
   if (closed_) {
     if (mozilla::ipc::LoggingEnabled()) {
       fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -16,31 +16,38 @@
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #endif
 
 #if defined(OS_POSIX)
 #include "nsAutoPtr.h"
 #endif
 
+#ifdef FUZZING
+#include "mozilla/ipc/Faulty.h"
+#endif
+
 namespace base {
 struct FileDescriptor;
 }
 
 class FileDescriptorSet;
 
 namespace IPC {
 
 //------------------------------------------------------------------------------
 
 // Generated by IPDL compiler
 const char* StringFromIPCMessageType(uint32_t aMessageType);
 
 class Channel;
 class Message;
+#ifdef FUZZING
+class Faulty;
+#endif
 struct LogData;
 
 class Message : public Pickle {
  public:
   typedef uint32_t msgid_t;
 
   enum NestedLevel {
     NOT_NESTED = 1,
@@ -378,16 +385,19 @@ class Message : public Pickle {
   }
 #endif
 #endif
 
 
   friend class Channel;
   friend class MessageReplyDeserializer;
   friend class SyncMessage;
+#ifdef FUZZING
+  friend class mozilla::ipc::Faulty;
+#endif
 
 #ifdef MOZ_TASK_TRACER
   void TaskTracerDispatch();
   class AutoTaskTracerRun
     : public mozilla::tasktracer::AutoSaveCurTraceInfo {
     Message& mMsg;
     uint64_t mTaskId;
     uint64_t mSourceEventId;
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -271,33 +271,39 @@ ProtocolErrorBreakpoint(const char* aMsg
     // reproduce.  Log always in the hope that someone finds the error
     // message.
     printf_stderr("IPDL protocol error: %s\n", aMsg);
 }
 
 void
 FatalError(const char* aMsg, bool aIsParent)
 {
+#ifndef FUZZING
   ProtocolErrorBreakpoint(aMsg);
+#endif
 
   nsAutoCString formattedMessage("IPDL error: \"");
   formattedMessage.AppendASCII(aMsg);
   if (aIsParent) {
     // We're going to crash the parent process because at this time
     // there's no other really nice way of getting a minidump out of
     // this process if we're off the main thread.
     formattedMessage.AppendLiteral("\". Intentionally crashing.");
     NS_ERROR(formattedMessage.get());
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"),
                                        nsDependentCString(aMsg));
     AnnotateSystemError();
+#ifndef FUZZING
     MOZ_CRASH("IPC FatalError in the parent process!");
+#endif
   } else {
     formattedMessage.AppendLiteral("\". abort()ing as a result.");
+#ifndef FUZZING
     MOZ_CRASH_UNSAFE_OOL(formattedMessage.get());
+#endif
   }
 }
 
 void
 LogicError(const char* aMsg)
 {
   MOZ_CRASH_UNSAFE_OOL(aMsg);
 }
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -44,20 +44,16 @@ EXPORTS.mozilla.ipc += [
     'SharedMemoryBasic.h',
     'Shmem.h',
     'TaskFactory.h',
     'Transport.h',
     'URIUtils.h',
     'WindowsMessageLoop.h',
 ]
 
-if CONFIG['FUZZING'] == '1':
-    EXPORTS.mozilla.ipc += ['Faulty.h']
-    SOURCES += ['Faulty.cpp']
-
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS.mozilla.ipc += [
         'Transport_win.h',
     ]
     SOURCES += [
         'SharedMemory_windows.cpp',
         'Transport_win.cpp',
         'WindowsMessageLoop.cpp',
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -466,16 +466,21 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(J
             return AppendBytes(data, size);
         });
     }
 
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
         return bufList_.SizeOfExcludingThis(mallocSizeOf);
     }
 
+    // Temporary until the scope is moved into JSStructuredCloneData.
+    void IgnoreTransferables() {
+        ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny;
+    }
+
     void discardTransferables();
 };
 
 /**
  * Implements StructuredDeserialize and StructuredDeserializeWithTransfer.
  *
  * Note: If `data` contains transferable objects, it can be read only once.
  */
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2737,33 +2737,33 @@ static bool
 SetIonCheckGraphCoherency(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     jit::JitOptions.checkGraphConsistency = ToBoolean(args.get(0));
     args.rval().setUndefined();
     return true;
 }
 
+// A JSObject that holds structured clone data, similar to the C++ class
+// JSAutoStructuredCloneBuffer.
 class CloneBufferObject : public NativeObject {
     static const JSPropertySpec props_[3];
 
     static const size_t DATA_SLOT = 0;
-    static const size_t LENGTH_SLOT = 1;
-    static const size_t SYNTHETIC_SLOT = 2;
-    static const size_t NUM_SLOTS = 3;
+    static const size_t SYNTHETIC_SLOT = 1;
+    static const size_t NUM_SLOTS = 2;
 
   public:
     static const Class class_;
 
     static CloneBufferObject* Create(JSContext* cx) {
         RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_)));
         if (!obj)
             return nullptr;
         obj->as<CloneBufferObject>().setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
-        obj->as<CloneBufferObject>().setReservedSlot(LENGTH_SLOT, Int32Value(0));
         obj->as<CloneBufferObject>().setReservedSlot(SYNTHETIC_SLOT, BooleanValue(false));
 
         if (!JS_DefineProperties(cx, obj, props_))
             return nullptr;
 
         return &obj->as<CloneBufferObject>();
     }
 
@@ -2788,24 +2788,25 @@ class CloneBufferObject : public NativeO
     bool isSynthetic() const {
         return getReservedSlot(SYNTHETIC_SLOT).toBoolean();
     }
 
     void setData(JSStructuredCloneData* aData, bool synthetic) {
         MOZ_ASSERT(!data());
         setReservedSlot(DATA_SLOT, PrivateValue(aData));
         setReservedSlot(SYNTHETIC_SLOT, BooleanValue(synthetic));
+
+        // Temporary until the scope is moved into JSStructuredCloneData.
+        if (synthetic)
+            aData->IgnoreTransferables();
     }
 
     // Discard an owned clone buffer.
     void discard() {
-        if (data()) {
-            JSAutoStructuredCloneBuffer clonebuf(JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
-            clonebuf.adopt(Move(*data()));
-        }
+        js_delete(data());
         setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
     }
 
     static bool
     setCloneBuffer_impl(JSContext* cx, const CallArgs& args) {
         Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
 
         uint8_t* data = nullptr;
@@ -3078,46 +3079,49 @@ Deserialize(JSContext* cx, unsigned argc
             if (!str)
                 return false;
             auto maybeScope = ParseCloneScope(cx, str);
             if (!maybeScope) {
                 JS_ReportErrorASCII(cx, "Invalid structured clone scope");
                 return false;
             }
 
+            if (fuzzingSafe && *maybeScope < scope) {
+                JS_ReportErrorASCII(cx, "Fuzzing builds must not set less restrictive scope "
+                                    "than the deserialized clone buffer's scope");
+                return false;
+            }
+
             scope = *maybeScope;
         }
     }
 
     // Clone buffer was already consumed?
     if (!obj->data()) {
         JS_ReportErrorASCII(cx, "deserialize given invalid clone buffer "
                             "(transferables already consumed?)");
         return false;
     }
 
     bool hasTransferable;
     if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
         return false;
 
-    if (obj->isSynthetic() && scope != JS::StructuredCloneScope::DifferentProcess) {
-        JS_ReportErrorASCII(cx, "clone buffer data is synthetic but may contain pointers");
-        return false;
-    }
-
     RootedValue deserialized(cx);
     if (!JS_ReadStructuredClone(cx, *obj->data(),
                                 JS_STRUCTURED_CLONE_VERSION,
                                 scope,
                                 &deserialized, nullptr, nullptr))
     {
         return false;
     }
     args.rval().set(deserialized);
 
+    // Consume any clone buffer with transferables; throw an error if it is
+    // deserialized again.
     if (hasTransferable)
         obj->discard();
 
     return true;
 }
 
 static bool
 DetachArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/jsapi-tests/testNewObject.cpp
+++ b/js/src/jsapi-tests/testNewObject.cpp
@@ -114,8 +114,40 @@ BEGIN_TEST(testNewObject_1)
     obj = JS_New(cx, ctor, JS::HandleValueArray::subarray(argv, 0, 3));
     CHECK(obj);
     CHECK(JS_GetElement(cx, ctor, 0, &v));
     CHECK(v.isInt32(0));
 
     return true;
 }
 END_TEST(testNewObject_1)
+
+BEGIN_TEST(testNewObject_IsMapObject)
+{
+    // Test IsMapObject and IsSetObject
+
+    JS::RootedValue vMap(cx);
+    EVAL("Map", &vMap);
+    JS::RootedObject Map(cx, vMap.toObjectOrNull());
+
+    bool isMap = false;
+    bool isSet = false;
+    JS::RootedObject mapObj(cx, JS_New(cx, Map, JS::HandleValueArray::empty()));
+    CHECK(mapObj);
+    CHECK(JS::IsMapObject(cx, mapObj, &isMap));
+    CHECK(isMap);
+    CHECK(JS::IsSetObject(cx, mapObj, &isSet));
+    CHECK(!isSet);
+
+    JS::RootedValue vSet(cx);
+    EVAL("Set", &vSet);
+    JS::RootedObject Set(cx, vSet.toObjectOrNull());
+
+    JS::RootedObject setObj(cx, JS_New(cx, Set, JS::HandleValueArray::empty()));
+    CHECK(setObj);
+    CHECK(JS::IsMapObject(cx, setObj, &isMap));
+    CHECK(!isMap);
+    CHECK(JS::IsSetObject(cx, setObj, &isSet));
+    CHECK(isSet);
+
+    return true;
+}
+END_TEST(testNewObject_IsMapObject)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7800,19 +7800,18 @@ dom_genericGetter(JSContext* cx, unsigne
     JSJitGetterOp getter = info->getter;
     return getter(cx, obj, val.toPrivate(), JSJitGetterCallArgs(args));
 }
 
 static bool
 dom_genericSetter(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 1);
-
-    if (!args.thisv().isObject()) {
+
+    if (args.length() < 1 || !args.thisv().isObject()) {
         args.rval().setUndefined();
         return true;
     }
 
     RootedObject obj(cx, &args.thisv().toObject());
     if (JS_GetClass(obj) != &dom_class) {
         args.rval().set(UndefinedValue());
         return true;
--- a/js/src/tests/non262/extensions/clone-errors.js
+++ b/js/src/tests/non262/extensions/clone-errors.js
@@ -30,12 +30,13 @@ for (let [write_scope, read_scope] of [[
   var ab = new ArrayBuffer(12);
   var buffer = serialize(ab, [ab], { scope: write_scope });
   var caught = false;
   try {
     deserialize(buffer, { scope: read_scope });
   } catch (exc) {
     caught = true;
   }
-  assertEq(caught, true, `${write_scope} clone buffer should not be deserializable as ${read_scope}`);
+  // The scope check is disabled by bug 1433642. It will be re-added in bug 1456604.
+  // assertEq(caught, true, `${write_scope} clone buffer should not be deserializable as ${read_scope}`);
 }
 
 reportCompare(0, 0, "ok");
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -238,29 +238,29 @@ def convertTestFile(test262parser, testS
 
     # Skip non-test files.
     isSupportFile = fileNameEndsWith(testName, "FIXTURE")
     if isSupportFile:
         refTestSkip.append("not a test file")
 
     # Skip tests with unsupported features.
     if "features" in testRec:
-        unsupported = UNSUPPORTED_FEATURES.intersection(testRec["features"])
+        unsupported = [f for f in testRec["features"] if f in UNSUPPORTED_FEATURES]
         if unsupported:
-            refTestSkip.append("%s is not supported" % ",".join(list(unsupported)))
+            refTestSkip.append("%s is not supported" % ",".join(unsupported))
         else:
-            releaseOrBeta = RELEASE_OR_BETA.intersection(testRec["features"])
+            releaseOrBeta = [f for f in testRec["features"] if f in RELEASE_OR_BETA]
             if releaseOrBeta:
                 refTestSkipIf.append(("release_or_beta",
-                                      "%s is not released yet" % ",".join(list(releaseOrBeta))))
+                                      "%s is not released yet" % ",".join(releaseOrBeta)))
 
-            featureCheckNeeded = set(FEATURE_CHECK_NEEDED.keys()).intersection(testRec["features"])
+            featureCheckNeeded = [f for f in testRec["features"] if f in FEATURE_CHECK_NEEDED]
             if featureCheckNeeded:
                 refTestSkipIf.append(("||".join([FEATURE_CHECK_NEEDED[f] for f in featureCheckNeeded]),
-                                      "%s is not enabled unconditionally" % ",".join(list(featureCheckNeeded))))
+                                      "%s is not enabled unconditionally" % ",".join(featureCheckNeeded)))
 
     # Includes for every test file in a directory is collected in a single
     # shell.js file per directory level. This is done to avoid adding all
     # test harness files to the top level shell.js file.
     if "includes" in testRec:
         assert not raw, "Raw test with includes: %s" % testName
         includeSet.update(testRec["includes"])
 
--- a/js/src/tests/test262/built-ins/Atomics/wait/cannot-suspend-throws.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/cannot-suspend-throws.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')||xulRuntime.shell) -- SharedArrayBuffer,Atomics,CannotSuspendMainAgent is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')||xulRuntime.shell) -- Atomics,SharedArrayBuffer,CannotSuspendMainAgent is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Atomics.wait throws if agent cannot be suspended, CanBlock is false
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/false-for-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/false-for-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   False timeout arg should result in an +0 timeout
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/nan-for-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/nan-for-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   NaN timeout arg should result in an infinite timeout
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/negative-index-throws.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/negative-index-throws.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Throws a RangeError is index < 0
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/out-of-range-index-throws.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/out-of-range-index-throws.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Throws a RangeError if value of index arg is out of range
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-index-throws.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-index-throws.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Throws a TypeError if index arg can not be converted to an Integer
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-timeout-throws.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-timeout-throws.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Throws a TypeError if timeout arg is a Symbol
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/true-for-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/true-for-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   True timeout arg should result in a timeout value of 1
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/undefined-for-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/undefined-for-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Undefined timeout arg should result in an infinite timeout
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/undefined-index-defaults-to-zero.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/undefined-index-defaults-to-zero.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-atomics.wait
 description: >
   An undefined index arg should translate to 0
 info: |
   Atomics.wait( typedArray, index, value, timeout )
--- a/js/src/tests/test262/built-ins/Atomics/wait/wait-index-value-not-equal.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/wait-index-value-not-equal.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.wait
 description: >
   Returns "not-equal" when value of index is not equal
 info: |
--- a/js/src/tests/test262/built-ins/Atomics/wait/was-woken-before-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/was-woken-before-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('Atomics')) -- SharedArrayBuffer,Atomics is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-atomics.wait
 description: >
   Test that Atomics.wait returns the right result when it was awoken before
   a timeout
 info: |
--- a/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-diff-buffer-other-type-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-diff-buffer-other-type-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-%typedarray%.prototype.set-typedarray-offset
 description: >
   Set values from different instances using the different buffer and different
--- a/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-diff-buffer-same-type-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-diff-buffer-same-type-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-%typedarray%.prototype.set-typedarray-offset
 description: >
   Set values from different instances using the different buffer and same
   constructor. srcBuffer values are cached.
--- a/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-same-buffer-same-type-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArray/prototype/set/BigInt/typedarray-arg-set-values-same-buffer-same-type-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-%typedarray%.prototype.set-typedarray-offset
 description: >
   Set values from different instances using the same buffer and same
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/bufferbyteoffset-throws-from-modulo-element-size-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/bufferbyteoffset-throws-from-modulo-element-size-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a RangeError if bufferByteLength modulo elementSize ≠ 0
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-negative-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-negative-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a RangeError if ToInteger(byteOffset) is < 0
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-negative-zero-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-negative-zero-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2015 André Bargull. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: pending
 description: >
   TypedArray's [[ByteOffset]] internal slot is always a positive number, test with negative zero.
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-symbol-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-is-symbol-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return abrupt from parsing integer value from byteOffset as a symbol
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-throws-from-modulo-element-size-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-throws-from-modulo-element-size-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a RangeError if ToInteger(byteOffset) modulo elementSize is not 0
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-to-number-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/byteoffset-to-number-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return abrupt from parsing integer value from byteOffset
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/custom-proto-access-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/custom-proto-access-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return abrupt completion getting newTarget's prototype
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-length-and-offset-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-length-and-offset-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return new typedArray from defined length and offset
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-length-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-length-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return new typedArray from defined length
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-negative-length-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-negative-length-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws RangeError for negative ToInteger(length)
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-offset-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/defined-offset-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return new typedArray from defined offset
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/excessive-length-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/excessive-length-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   If offset + newByteLength > bufferByteLength, throw a RangeError exception.
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/excessive-offset-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/excessive-offset-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a RangeError if bufferByteLength - ToInteger(byteOffset) < 0
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/invoked-with-undefined-newtarget-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/invoked-with-undefined-newtarget-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a TypeError if NewTarget is undefined.
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/is-referenced-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/is-referenced-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Reuse buffer argument instead of making a new clone
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/length-access-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/length-access-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Returns abrupt from ToLength(length)
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/length-is-symbol-throws-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/length-is-symbol-throws-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Throws a TypeError if length is a Symbol
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/new-instance-extensibility-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/new-instance-extensibility-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   The new typedArray instance from a buffer argument is extensible
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: Default [[Prototype]] value derived from realm of the newTarget
 info: |
     [...]
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/returns-new-instance-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/returns-new-instance-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Return new typedArray from undefined offset and length
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/toindex-bytelength-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/toindex-bytelength-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   ToIndex(length) operations
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/toindex-byteoffset-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/toindex-byteoffset-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   ToIndex(byteOffset) operations
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/typedarray-backed-by-sharedarraybuffer.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/typedarray-backed-by-sharedarraybuffer.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-typedarray-typedarray
 description: >
   Passing a SharedArrayBuffer-backed TypedArray to a TypedArray constructor
   produces an ArrayBuffer-backed TypedArray.
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/use-custom-proto-if-object-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/use-custom-proto-if-object-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Use prototype from new target if it's an Object
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/use-default-proto-if-custom-proto-is-not-object-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/use-default-proto-if-custom-proto-is-not-object-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-typedarray-buffer-byteoffset-length
 description: >
   Use prototype from %TypedArray% if newTarget's prototype is not an Object
 info: |
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/internals/Get/BigInt/indexed-value-sab.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/internals/Get/BigInt/indexed-value-sab.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')||!this.hasOwnProperty('BigInt')) -- SharedArrayBuffer,BigInt is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- BigInt,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-integer-indexed-exotic-objects-get-p-receiver
 description: >
   Return value from valid numeric index, with SharedArrayBuffer
 includes: [testBigIntTypedArray.js]
--- a/js/src/tests/test262/language/expressions/class/fields-private-arrow-fnc-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-arrow-fnc-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-arrow-fnc.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, arrow function expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, arrow-function, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-arrow-fnc-init-err-contains-super.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-arrow-fnc-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-arrow-fnc.template
 /*---
 description: Syntax error if `super()` used in class field (private field, arrow function expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, arrow-function, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-literal-name-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-literal-name-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-name.template
 /*---
 description: Syntax error if `arguments` used in class field (ClassElementName PrivateName)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-literal-name-init-err-contains-super.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-literal-name-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-name.template
 /*---
 description: Syntax error if `super()` used in class field (ClassElementName PrivateName)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-ternary-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-ternary-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-ternary.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, ternary expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-ternary-init-err-contains-super.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-ternary-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-ternary.template
 /*---
 description: Syntax error if `super()` used in class field (private field, ternary expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-typeof-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-typeof-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-typeof.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, typeof expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/expressions/class/fields-private-typeof-init-err-contains-super.js
+++ b/js/src/tests/test262/language/expressions/class/fields-private-typeof-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-expr-fields-private-typeof.template
 /*---
 description: Syntax error if `super()` used in class field (private field, typeof expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-arrow-fnc-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-arrow-fnc-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-arrow-fnc.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, arrow function expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, arrow-function, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-arrow-fnc-init-err-contains-super.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-arrow-fnc-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-arrow-fnc.template
 /*---
 description: Syntax error if `super()` used in class field (private field, arrow function expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, arrow-function, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-literal-name-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-literal-name-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-name.template
 /*---
 description: Syntax error if `arguments` used in class field (ClassElementName PrivateName)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-literal-name-init-err-contains-super.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-literal-name-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-name.template
 /*---
 description: Syntax error if `super()` used in class field (ClassElementName PrivateName)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-ternary-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-ternary-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-ternary.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, ternary expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-ternary-init-err-contains-super.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-ternary-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-ternary.template
 /*---
 description: Syntax error if `super()` used in class field (private field, ternary expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-typeof-init-err-contains-arguments.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-typeof-init-err-contains-arguments.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-arguments.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-typeof.template
 /*---
 description: Syntax error if `arguments` used in class field (private field, typeof expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/tests/test262/language/statements/class/fields-private-typeof-init-err-contains-super.js
+++ b/js/src/tests/test262/language/statements/class/fields-private-typeof-init-err-contains-super.js
@@ -1,9 +1,9 @@
-// |reftest| skip error:SyntaxError -- class-fields-private,class-fields-public is not supported
+// |reftest| skip error:SyntaxError -- class-fields-public,class-fields-private is not supported
 // This file was procedurally generated from the following sources:
 // - src/class-fields/init-err-contains-super.case
 // - src/class-fields/initializer-error/cls-decl-fields-private-typeof.template
 /*---
 description: Syntax error if `super()` used in class field (private field, typeof expression)
 esid: sec-class-definitions-static-semantics-early-errors
 features: [class, class-fields-public, class-fields-private]
 flags: [generated]
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -425,23 +425,16 @@ struct JSStructuredCloneReader {
     SCInput& in;
 
     // The widest scope that the caller will accept, where
     // SameProcessSameThread is the widest (it can store anything it wants) and
     // DifferentProcess is the narrowest (it cannot contain pointers and must
     // be valid cross-process.)
     JS::StructuredCloneScope allowedScope;
 
-    // The scope the buffer was generated for (what sort of buffer it is.) The
-    // scope is not just a permissions thing; it also affects the storage
-    // format (eg a Transferred ArrayBuffer can be stored as a pointer for
-    // SameProcessSameThread but must have its contents in the clone buffer for
-    // DifferentProcess.)
-    JS::StructuredCloneScope storedScope;
-
     // Stack of objects with properties remaining to be read.
     AutoValueVector objs;
 
     // Array of all objects read during this deserialization, for resolving
     // backreferences.
     //
     // For backreferences to work correctly, objects must be added to this
     // array in exactly the order expected by the version of the Writer that
@@ -2054,24 +2047,16 @@ JSStructuredCloneReader::readSharedArray
     // transmission point, but that's tricky, and it will be a very rare problem
     // in any case.  Just fail at the receiving end if we can't handle it.
 
     if (!context()->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_DISABLED);
         return false;
     }
 
-    // We must not transfer buffer pointers cross-process.  The cloneDataPolicy
-    // in the sender should guard against this; check that it does.
-    if (storedScope > JS::StructuredCloneScope::SameProcessDifferentThread) {
-        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
-                                  "can't transfer SharedArrayBuffer cross-process");
-        return false;
-    }
-
     // The new object will have a new reference to the rawbuf.
 
     if (!rawbuf->addReference()) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
         return false;
     }
 
     JSObject* obj = SharedArrayBufferObject::New(context(), rawbuf, byteLength);
@@ -2390,38 +2375,35 @@ JSStructuredCloneReader::startRead(Mutab
 
 bool
 JSStructuredCloneReader::readHeader()
 {
     uint32_t tag, data;
     if (!in.getPair(&tag, &data))
         return in.reportTruncated();
 
-    if (tag != SCTAG_HEADER) {
+    JS::StructuredCloneScope storedScope;
+    if (tag == SCTAG_HEADER) {
+        MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+        storedScope = JS::StructuredCloneScope(data);
+    } else {
         // Old structured clone buffer. We must have read it from disk.
         storedScope = JS::StructuredCloneScope::DifferentProcess;
-        return true;
     }
 
-    MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
-    storedScope = JS::StructuredCloneScope(data);
-
-    if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) &&
-        data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) &&
-        data != uint32_t(JS::StructuredCloneScope::DifferentProcess))
+    if (storedScope != JS::StructuredCloneScope::SameProcessSameThread &&
+        storedScope != JS::StructuredCloneScope::SameProcessDifferentThread &&
+        storedScope != JS::StructuredCloneScope::DifferentProcess)
     {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "invalid structured clone scope");
         return false;
     }
-    if (storedScope < allowedScope) {
-        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
-                                  "incompatible structured clone scope");
-        return false;
-    }
+
+    // Do not check storedScope due to bug 1434308, until bug 1456604 is fixed.
 
     return true;
 }
 
 bool
 JSStructuredCloneReader::readTransferMap()
 {
     JSContext* cx = context();
@@ -2452,20 +2434,22 @@ JSStructuredCloneReader::readTransferMap
         if (!in.readPtr(&content))
             return false;
 
         uint64_t extraData;
         if (!in.read(&extraData))
             return false;
 
         if (tag == SCTAG_TRANSFER_MAP_ARRAY_BUFFER) {
-            if (storedScope == JS::StructuredCloneScope::DifferentProcess) {
+            if (allowedScope == JS::StructuredCloneScope::DifferentProcess) {
                 // Transferred ArrayBuffers in a DifferentProcess clone buffer
-                // are treated as if they weren't Transferred at all.
-                continue;
+                // are treated as if they weren't Transferred at all. We should
+                // only see SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER.
+                ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
+                return false;
             }
 
             size_t nbytes = extraData;
             MOZ_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA ||
                        data == JS::SCTAG_TMO_MAPPED_DATA);
             if (data == JS::SCTAG_TMO_ALLOC_DATA)
                 obj = JS_NewArrayBufferWithContents(cx, nbytes, content);
             else if (data == JS::SCTAG_TMO_MAPPED_DATA)
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6248,16 +6248,20 @@ var ExternalApps = {
 
       return apps.length == 1 ? Strings.browser.formatStringFromName("helperapps.openWithApp2", [apps[0].name], 1) :
                                 Strings.browser.GetStringFromName("helperapps.openWithList2");
     }, this.filter, this.openExternal);
   },
 
   filter: {
     matches: function(aElement) {
+      if (!Services.prefs.getBoolPref("network.protocol-handler.external-default")) {
+        return false;
+      }
+
       let uri = ExternalApps._getMediaLink(aElement);
       let apps = [];
       if (uri) {
         apps = HelperApps.getAppsForUri(uri);
       }
       return apps.length > 0;
     }
   },
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -453,17 +453,17 @@ class TaskClusterImagesProvider(MachComm
 
 
 @CommandProvider
 class TaskClusterPartialsData(object):
     @Command('release-history', category="ci",
              description="Query balrog for release history used by enable partials generation")
     @CommandArgument('-b', '--branch',
                      help="The gecko project branch used in balrog, such as "
-                          "mozilla-central, release, date")
+                          "mozilla-central, release, maple")
     @CommandArgument('--product', default='Firefox',
                      help="The product identifier, such as 'Firefox'")
     def generate_partials_builds(self, product, branch):
         from taskgraph.util.partials import populate_release_history
         try:
             import yaml
             release_history = {'release_history': populate_release_history(product, branch)}
             print(yaml.safe_dump(release_history, allow_unicode=True, default_flow_style=False))
--- a/taskcluster/taskgraph/test/test_util_attributes.py
+++ b/taskcluster/taskgraph/test/test_util_attributes.py
@@ -79,20 +79,20 @@ class MatchRunOnProjects(unittest.TestCa
         self.assertFalse(match_run_on_projects('larch', ['integration']))
         self.assertTrue(match_run_on_projects('autoland', ['integration']))
         self.assertTrue(match_run_on_projects('mozilla-inbound', ['integration']))
         self.assertFalse(match_run_on_projects('mozilla-central', ['integration']))
         self.assertFalse(match_run_on_projects('mozilla-beta', ['integration']))
         self.assertFalse(match_run_on_projects('mozilla-integration', ['integration']))
 
     def test_combo(self):
-        self.assertTrue(match_run_on_projects('try', ['release', 'try', 'date']))
-        self.assertFalse(match_run_on_projects('larch', ['release', 'try', 'date']))
-        self.assertTrue(match_run_on_projects('date', ['release', 'try', 'date']))
-        self.assertFalse(match_run_on_projects('autoland', ['release', 'try', 'date']))
-        self.assertFalse(match_run_on_projects('mozilla-inbound', ['release', 'try', 'date']))
-        self.assertTrue(match_run_on_projects('mozilla-central', ['release', 'try', 'date']))
-        self.assertTrue(match_run_on_projects('mozilla-beta', ['release', 'try', 'date']))
-        self.assertTrue(match_run_on_projects('mozilla-release', ['release', 'try', 'date']))
+        self.assertTrue(match_run_on_projects('try', ['release', 'try', 'maple']))
+        self.assertFalse(match_run_on_projects('larch', ['release', 'try', 'maple']))
+        self.assertTrue(match_run_on_projects('maple', ['release', 'try', 'maple']))
+        self.assertFalse(match_run_on_projects('autoland', ['release', 'try', 'maple']))
+        self.assertFalse(match_run_on_projects('mozilla-inbound', ['release', 'try', 'maple']))
+        self.assertTrue(match_run_on_projects('mozilla-central', ['release', 'try', 'maple']))
+        self.assertTrue(match_run_on_projects('mozilla-beta', ['release', 'try', 'maple']))
+        self.assertTrue(match_run_on_projects('mozilla-release', ['release', 'try', 'maple']))
 
 
 if __name__ == '__main__':
     main()
--- a/taskcluster/taskgraph/transforms/task.py
+++ b/taskcluster/taskgraph/transforms/task.py
@@ -641,17 +641,16 @@ BRANCH_PRIORITIES = {
     'mozilla-inbound': 'low',
     'try': 'very-low',
     'try-comm-central': 'very-low',
     'alder': 'very-low',
     'ash': 'very-low',
     'birch': 'very-low',
     'cedar': 'very-low',
     'cypress': 'very-low',
-    'date': 'very-low',
     'elm': 'very-low',
     'fig': 'very-low',
     'gum': 'very-low',
     'holly': 'very-low',
     'jamun': 'very-low',
     'larch': 'very-low',
     'maple': 'very-low',
     'oak': 'very-low',
--- a/testing/mozharness/configs/builds/branch_specifics.py
+++ b/testing/mozharness/configs/builds/branch_specifics.py
@@ -212,19 +212,16 @@ config = {
     },
     'mozilla-inbound': {
         'repo_path': 'integration/mozilla-inbound',
     },
     'autoland': {
         'repo_path': 'integration/autoland',
     },
     'ux': {},
-    'date': {
-        'update_channel': 'nightly-date',
-    },
     'cypress': {
         # bug 1164935
         'branch_uses_per_checkin_strategy': True,
     },
 
     ### other branches that do not require anything special:
     'alder': {},
     'ash': {},
deleted file mode 100644
--- a/testing/mozharness/configs/multi_locale/date_android-armv6.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-    "work_dir": ".",
-    "log_name": "multilocale",
-    "objdir": "obj-firefox",
-    "locales_file": "build/mobile/locales/l10n-changesets.json",
-    "locales_platform": "android-multilocale",
-    "locales_dir": "mobile/android/locales",
-    "ignore_locales": ["en-US", "multi"],
-    "repos": [{
-        "repo": "https://hg.mozilla.org/date",
-        "branch": "default",
-        "dest": "build"
-    },{
-        "repo": "https://hg.mozilla.org/build/buildbot-configs",
-        "branch": "production",
-        "dest": "build/configs"
-    },{
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools"
-    }],
-    "vcs_share_base": "/builds/hg-shared",
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-    "hg_l10n_tag": "default",
-    "l10n_dir": "l10n-central",
-    "mozilla_dir": "build",
-    "mozconfig": "build/mobile/android/config/mozconfigs/android-armv6/nightly"
-}
deleted file mode 100644
--- a/testing/mozharness/configs/multi_locale/date_android-x86.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-    "work_dir": ".",
-    "log_name": "multilocale",
-    "objdir": "obj-firefox",
-    "locales_file": "build/mobile/locales/l10n-changesets.json",
-    "locales_platform": "android-multilocale",
-    "locales_dir": "mobile/android/locales",
-    "ignore_locales": ["en-US", "multi"],
-    "repos": [{
-        "repo": "https://hg.mozilla.org/date",
-        "branch": "default",
-        "dest": "build"
-    },{
-        "repo": "https://hg.mozilla.org/build/buildbot-configs",
-        "branch": "production",
-        "dest": "build/configs"
-    },{
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools"
-    }],
-    "vcs_share_base": "/builds/hg-shared",
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-    "hg_l10n_tag": "default",
-    "l10n_dir": "l10n-central",
-    "mozilla_dir": "build",
-    "mozconfig": "build/mobile/android/config/mozconfigs/android-x86/nightly"
-}
deleted file mode 100644
--- a/testing/mozharness/configs/multi_locale/date_android.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-    "work_dir": ".",
-    "log_name": "multilocale",
-    "objdir": "obj-firefox",
-    "locales_file": "build/mobile/locales/l10n-changesets.json",
-    "locales_platform": "android-multilocale",
-    "locales_dir": "mobile/android/locales",
-    "ignore_locales": ["en-US", "multi"],
-    "repos": [{
-        "repo": "https://hg.mozilla.org/date",
-        "branch": "default",
-        "dest": "build"
-    },{
-        "repo": "https://hg.mozilla.org/build/buildbot-configs",
-        "branch": "production",
-        "dest": "build/configs"
-    },{
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools"
-    }],
-    "vcs_share_base": "/builds/hg-shared",
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-    "hg_l10n_tag": "default",
-    "l10n_dir": "l10n-central",
-    "mozilla_dir": "build"
-}
deleted file mode 100644
--- a/testing/mozharness/configs/single_locale/date.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import os
-
-config = {
-    "nightly_build": True,
-    "branch": "date",
-    "en_us_binary_url": "http://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central",
-    "update_channel": "nightly-date",
-
-    # l10n
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-
-    # mar
-    "mar_tools_url": os.environ.get(
-        "MAR_TOOLS_URL",
-        # Buildbot l10n fetches from ftp rather than setting an environ var
-        "http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-central/mar-tools/%(platform)s"
-    ),
-
-    # repositories
-    "mozilla_dir": "date",
-    "repos": [{
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools",
-    }, {
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/projects/date",
-        "revision": "%(revision)s",
-        "dest": "date",
-    }],
-    # purge options
-    'is_automation': True,
-}
deleted file mode 100644
--- a/testing/mozharness/configs/single_locale/date_android-api-16.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import os
-
-BRANCH = "date"
-MOZILLA_DIR = BRANCH
-EN_US_BINARY_URL = "http://archive.mozilla.org/pub/" \
-                   "mobile/nightly/latest-date-android-api-16/en-US"
-
-config = {
-    "branch": BRANCH,
-    "log_name": "single_locale",
-    "objdir": "obj-firefox",
-    "is_automation": True,
-    "buildbot_json_path": "buildprops.json",
-    "force_clobber": True,
-    "clobberer_url": "https://api.pub.build.mozilla.org/clobberer/lastclobber",
-    "locales_file": "%s/mobile/locales/l10n-changesets.json" % MOZILLA_DIR,
-    "locales_dir": "mobile/android/locales",
-    "ignore_locales": ["en-US"],
-    "nightly_build": True,
-    'balrog_credentials_file': 'oauth.txt',
-    "tools_repo": "https://hg.mozilla.org/build/tools",
-    "tooltool_config": {
-        "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest",
-        "output_dir": "%(abs_work_dir)s/" + MOZILLA_DIR,
-    },
-    "repos": [{
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools",
-    }, {
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/projects/date",
-        "revision": "%(revision)s",
-        "dest": MOZILLA_DIR,
-    }],
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-    "hg_l10n_tag": "default",
-    'vcs_share_base': "/builds/hg-shared",
-
-    "l10n_dir": "l10n-central",
-    "repack_env": {
-        # so ugly, bug 951238
-        "LD_LIBRARY_PATH": "/lib:/tools/gcc-4.7.2-0moz1/lib:/tools/gcc-4.7.2-0moz1/lib64",
-        "MOZ_OBJDIR": "obj-firefox",
-        "EN_US_BINARY_URL": os.environ.get("EN_US_BINARY_URL", EN_US_BINARY_URL),
-        "MOZ_UPDATE_CHANNEL": "nightly-date",
-    },
-    "upload_branch": "%s-android-api-16" % BRANCH,
-    "ssh_key_dir": "~/.ssh",
-    "mozilla_dir": MOZILLA_DIR,
-    "mozconfig": "%s/mobile/android/config/mozconfigs/android-api-16/l10n-nightly" % MOZILLA_DIR,
-    "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
-    "stage_product": "mobile",
-    "platform": "android",
-
-    # Balrog
-    "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
-}
deleted file mode 100644
--- a/testing/mozharness/configs/single_locale/dev-mozilla-beta_devedition.py
+++ /dev/null
@@ -1,39 +0,0 @@
-config = {
-    "branch": "date",
-    "nightly_build": True,
-    "update_channel": "aurora",  # devedition uses aurora based branding
-
-    # l10n
-    "hg_l10n_base": "https://hg.mozilla.org/l10n-central",
-
-    # repositories
-    # staging beta dev releases use date repo for now
-    "mozilla_dir": "date",
-    "repos": [{
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/build/tools",
-        "branch": "default",
-        "dest": "tools",
-    }, {
-        "vcs": "hg",
-        "repo": "https://hg.mozilla.org/projects/date",
-        "branch": "%(revision)s",
-        "dest": "date",
-        "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified",
-    }],
-    # purge options
-    'is_automation': True,
-    'purge_minsize': 12,
-    'default_actions': [
-        "clobber",
-        "pull",
-        "clone-locales",
-        "list-locales",
-        "setup",
-        "repack",
-        "taskcluster-upload",
-        "summary",
-    ],
-
-    "update_channel": "aurora",
-}
--- a/testing/web-platform/meta/svg/interfaces.html.ini
+++ b/testing/web-platform/meta/svg/interfaces.html.ini
@@ -1,18 +1,15 @@
 [interfaces.html]
   [SVGGeometryElement interface: operation isPointInFill(DOMPoint)]
     expected: FAIL
 
   [SVGGeometryElement interface: operation isPointInStroke(DOMPoint)]
     expected: FAIL
 
-  [SVGNumber interface: existence and properties of interface object]
-    expected: FAIL
-
   [SVGSVGElement interface: operation getIntersectionList(DOMRectReadOnly,SVGElement)]
     expected: FAIL
 
   [SVGSVGElement interface: operation getEnclosureList(DOMRectReadOnly,SVGElement)]
     expected: FAIL
 
   [SVGSVGElement interface: operation checkIntersection(SVGElement,DOMRectReadOnly)]
     expected: FAIL
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -45,16 +45,19 @@ var {
   getConsole,
   getInnerWindowID,
   getUniqueId,
   getWinUtils,
 } = ExtensionUtils;
 
 XPCOMUtils.defineLazyGetter(this, "console", getConsole);
 
+XPCOMUtils.defineLazyPreferenceGetter(this, "DELAYED_BG_STARTUP",
+                                      "extensions.webextensions.background-delayed-startup");
+
 var ExtensionCommon;
 
 /**
  * A sentinel class to indicate that an array of values should be
  * treated as an array when used as a promise resolution value, but as a
  * spread expression (...args) when passed to a callback.
  */
 class SpreadArgs extends Array {
@@ -1700,16 +1703,22 @@ class EventManager {
       let {context, name, register, inputHandling = false, persistent = null} = params;
       this.context = context;
       this.name = name;
       this.register = register;
       this.inputHandling = inputHandling;
       this.persistent = persistent;
     }
 
+    // Don't bother with persistent event handling if delayed background
+    // startup is not enabled.
+    if (!DELAYED_BG_STARTUP) {
+      this.persistent = null;
+    }
+
     this.unregister = new Map();
     this.remove = new Map();
 
     if (this.persistent) {
       if (this.context.viewType !== "background") {
         this.persistent = null;
       }
       if (AppConstants.DEBUG) {
@@ -1791,24 +1800,30 @@ class EventManager {
 
     for (let [module, moduleEntry] of extension.persistentListeners) {
       let api = extension.apiManager.getAPI(module, extension, "addon_parent");
       for (let [event, eventEntry] of moduleEntry) {
         for (let listener of eventEntry.values()) {
           let primed = {pendingEvents: []};
           listener.primed = primed;
 
-          let wakeup = (...args) => new Promise((resolve, reject) => {
+          let wakeup = () => new Promise(resolve => {
+            extension.once("startup", resolve);
+            extension.emit("background-page-event");
+          });
+
+          let fireEvent = (...args) => new Promise((resolve, reject) => {
             primed.pendingEvents.push({args, resolve, reject});
             extension.emit("background-page-event");
           });
 
           let fire = {
-            sync: wakeup,
-            async: wakeup,
+            wakeup,
+            sync: fireEvent,
+            async: fireEvent,
           };
 
           let {unregister, convert} = api.primeListener(extension, event, fire, listener.params);
           Object.assign(primed, {unregister, convert});
         }
       }
     }
   }
@@ -1918,25 +1933,32 @@ class EventManager {
     if (this.persistent) {
       recordStartupData = true;
       let {module, event} = this.persistent;
 
       let key = uneval(args);
       EventManager._initPersistentListeners(extension);
       let listener = extension.persistentListeners
                               .get(module).get(event).get(key);
-      if (listener) {
-        let {primed} = listener;
-        listener.primed = null;
 
-        primed.convert(fire);
-        unregister = primed.unregister;
+      if (listener) {
+        // If extensions.webextensions.background-delayed-startup is disabled,
+        // we can have stored info here but no primed listener.  This check
+        // can be removed if/when we make delayed background startup the only
+        // supported setting.
+        let {primed} = listener;
+        if (primed) {
+          listener.primed = null;
 
-        for (let evt of primed.pendingEvents) {
-          evt.resolve(fire.async(...evt.args));
+          primed.convert(fire, this.context);
+          unregister = primed.unregister;
+
+          for (let evt of primed.pendingEvents) {
+            evt.resolve(fire.async(...evt.args));
+          }
         }
 
         recordStartupData = false;
         this.remove.set(callback, () => {
           EventManager.clearPersistentListener(extension, module, event, uneval(args));
         });
       }
     }
--- a/toolkit/components/extensions/parent/ext-backgroundPage.js
+++ b/toolkit/components/extensions/parent/ext-backgroundPage.js
@@ -74,17 +74,16 @@ this.backgroundPage = class extends Exte
 
     // There are two ways to start the background page:
     // 1. If a primed event fires, then start the background page as
     //    soon as we have painted a browser window.  Note that we have
     //    to touch browserPaintedPromise here to initialize the listener
     //    or else we can miss it if the event occurs after the first
     //    window is painted but before #2
     // 2. After all windows have been restored.
-    void browserPaintedPromise;
     extension.once("background-page-event", async () => {
       await browserPaintedPromise;
       extension.emit("start-background-page");
     });
 
     browserStartupPromise.then(() => {
       extension.emit("start-background-page");
     });
--- a/toolkit/components/extensions/parent/ext-toolkit.js
+++ b/toolkit/components/extensions/parent/ext-toolkit.js
@@ -70,28 +70,17 @@ global.getContainerForCookieStoreId = fu
 };
 
 global.isValidCookieStoreId = function(storeId) {
   return isDefaultCookieStoreId(storeId) ||
          isPrivateCookieStoreId(storeId) ||
          isContainerCookieStoreId(storeId);
 };
 
-function makeEventPromise(name, event) {
-  Object.defineProperty(global, name, {
-    get() {
-      let promise = ExtensionUtils.promiseObserved(event);
-      Object.defineProperty(global, name, {value: promise});
-      return promise;
-    },
-    configurable: true,
-    enumerable: true,
-  });
+function makeStartupPromise(event) {
+  return ExtensionUtils.promiseObserved(event).then(() => {});
 }
 
 // browserPaintedPromise and browserStartupPromise are promises that
 // resolve after the first browser window is painted and after browser
 // windows have been restored, respectively.
-// These promises must be referenced during startup to be valid -- if the
-// first reference happens after the corresponding event has occurred,
-// the Promise will never resolve.
-makeEventPromise("browserPaintedPromise", "browser-delayed-startup-finished");
-makeEventPromise("browserStartupPromise", "sessionstore-windows-restored");
+global.browserPaintedPromise = makeStartupPromise("browser-delayed-startup-finished");
+global.browserStartupPromise = makeStartupPromise("sessionstore-windows-restored");
--- a/toolkit/components/extensions/parent/ext-webRequest.js
+++ b/toolkit/components/extensions/parent/ext-webRequest.js
@@ -2,105 +2,129 @@
 
 // This file expects tabTracker to be defined in the global scope (e.g.
 // by ext-utils.js).
 /* global tabTracker */
 
 ChromeUtils.defineModuleGetter(this, "WebRequest",
                                "resource://gre/modules/WebRequest.jsm");
 
-// EventManager-like class specifically for WebRequest. Inherits from
-// EventManager. Takes care of converting |details| parameter
-// when invoking listeners.
-function WebRequestEventManager(context, eventName) {
-  let name = `webRequest.${eventName}`;
-  let register = (fire, filter, info) => {
-    let listener = data => {
-      let browserData = {tabId: -1, windowId: -1};
-      if (data.browser) {
-        browserData = tabTracker.getBrowserData(data.browser);
-      }
-      if (filter.tabId != null && browserData.tabId != filter.tabId) {
-        return;
-      }
-      if (filter.windowId != null && browserData.windowId != filter.windowId) {
-        return;
+// The guts of a WebRequest event handler.  Takes care of converting
+// |details| parameter when invoking listeners.
+function registerEvent(extension, eventName, fire, filter, info, tabParent = null) {
+  let listener = async data => {
+    let browserData = {tabId: -1, windowId: -1};
+    if (data.browser) {
+      browserData = tabTracker.getBrowserData(data.browser);
+    }
+    if (filter.tabId != null && browserData.tabId != filter.tabId) {
+      return;
+    }
+    if (filter.windowId != null && browserData.windowId != filter.windowId) {
+      return;
+    }
+
+    let event = data.serialize(eventName);
+    event.tabId = browserData.tabId;
+
+    if (data.registerTraceableChannel) {
+      if (fire.wakeup) {
+        await fire.wakeup();
       }
+      data.registerTraceableChannel(extension.policy, tabParent);
+    }
 
-      let event = data.serialize(eventName);
-      event.tabId = browserData.tabId;
+    return fire.sync(event);
+  };
 
-      return fire.sync(event);
-    };
+  let filter2 = {};
+  if (filter.urls) {
+    let perms = new MatchPatternSet([...extension.whiteListedHosts.patterns,
+                                     ...extension.optionalOrigins.patterns]);
+
+    filter2.urls = new MatchPatternSet(filter.urls);
 
-    let filter2 = {};
-    if (filter.urls) {
-      let perms = new MatchPatternSet([...context.extension.whiteListedHosts.patterns,
-                                       ...context.extension.optionalOrigins.patterns]);
+    if (!perms.overlapsAll(filter2.urls)) {
+      Cu.reportError("The webRequest.addListener filter doesn't overlap with host permissions.");
+    }
+  }
+  if (filter.types) {
+    filter2.types = filter.types;
+  }
+  if (filter.tabId) {
+    filter2.tabId = filter.tabId;
+  }
+  if (filter.windowId) {
+    filter2.windowId = filter.windowId;
+  }
 
-      filter2.urls = new MatchPatternSet(filter.urls);
+  let blockingAllowed = extension.hasPermission("webRequestBlocking");
 
-      if (!perms.overlapsAll(filter2.urls)) {
-        Cu.reportError("The webRequest.addListener filter doesn't overlap with host permissions.");
+  let info2 = [];
+  if (info) {
+    for (let desc of info) {
+      if (desc == "blocking" && !blockingAllowed) {
+        Cu.reportError("Using webRequest.addListener with the blocking option " +
+                       "requires the 'webRequestBlocking' permission.");
+      } else {
+        info2.push(desc);
       }
     }
-    if (filter.types) {
-      filter2.types = filter.types;
-    }
-    if (filter.tabId) {
-      filter2.tabId = filter.tabId;
-    }
-    if (filter.windowId) {
-      filter2.windowId = filter.windowId;
-    }
-
-    let blockingAllowed = context.extension.hasPermission("webRequestBlocking");
+  }
 
-    let info2 = [];
-    if (info) {
-      for (let desc of info) {
-        if (desc == "blocking" && !blockingAllowed) {
-          Cu.reportError("Using webRequest.addListener with the blocking option " +
-                         "requires the 'webRequestBlocking' permission.");
-        } else {
-          info2.push(desc);
-        }
-      }
-    }
-
-    let listenerDetails = {
-      addonId: context.extension.id,
-      extension: context.extension.policy,
-      blockingAllowed,
-      tabParent: context.xulBrowser.frameLoader.tabParent,
-    };
-
-    WebRequest[eventName].addListener(
-      listener, filter2, info2,
-      listenerDetails);
-    return () => {
-      WebRequest[eventName].removeListener(listener);
-    };
+  let listenerDetails = {
+    addonId: extension.id,
+    extension: extension.policy,
+    blockingAllowed,
   };
 
-  return new EventManager({context, name, register}).api();
+  WebRequest[eventName].addListener(
+    listener, filter2, info2,
+    listenerDetails);
+
+  return {
+    unregister: () => { WebRequest[eventName].removeListener(listener); },
+    convert(_fire, context) {
+      fire = _fire;
+      tabParent = context.xulBrowser.frameLoader.tabParent;
+    },
+  };
+}
+
+function makeWebRequestEvent(context, name) {
+  return new EventManager({
+    context,
+    name: `webRequest.${name}`,
+    persistent: {
+      module: "webRequest",
+      event: name,
+    },
+    register: (fire, filter, info) => {
+      return registerEvent(context.extension, name, fire, filter, info,
+                           context.xulBrowser.frameLoader.tabParent).unregister;
+    },
+  }).api();
 }
 
 this.webRequest = class extends ExtensionAPI {
+  primeListener(extension, event, fire, params) {
+    return registerEvent(extension, event, fire, ...params);
+  }
+
   getAPI(context) {
     return {
       webRequest: {
-        onBeforeRequest: WebRequestEventManager(context, "onBeforeRequest"),
-        onBeforeSendHeaders: WebRequestEventManager(context, "onBeforeSendHeaders"),
-        onSendHeaders: WebRequestEventManager(context, "onSendHeaders"),
-        onHeadersReceived: WebRequestEventManager(context, "onHeadersReceived"),
-        onAuthRequired: WebRequestEventManager(context, "onAuthRequired"),
-        onBeforeRedirect: WebRequestEventManager(context, "onBeforeRedirect"),
-        onResponseStarted: WebRequestEventManager(context, "onResponseStarted"),
-        onErrorOccurred: WebRequestEventManager(context, "onErrorOccurred"),
-        onCompleted: WebRequestEventManager(context, "onCompleted"),
+        onBeforeRequest: makeWebRequestEvent(context, "onBeforeRequest"),
+        onBeforeSendHeaders: makeWebRequestEvent(context, "onBeforeSendHeaders"),
+        onSendHeaders: makeWebRequestEvent(context, "onSendHeaders"),
+        onHeadersReceived: makeWebRequestEvent(context, "onHeadersReceived"),
+        onAuthRequired: makeWebRequestEvent(context, "onAuthRequired"),
+        onBeforeRedirect: makeWebRequestEvent(context, "onBeforeRedirect"),
+        onResponseStarted: makeWebRequestEvent(context, "onResponseStarted"),
+        onErrorOccurred: makeWebRequestEvent(context, "onErrorOccurred"),
+        onCompleted: makeWebRequestEvent(context, "onCompleted"),
         handlerBehaviorChanged: function() {
           // TODO: Flush all caches.
         },
       },
     };
   }
 };
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_startup.js
@@ -0,0 +1,172 @@
+"use strict";
+
+PromiseTestUtils.whitelistRejectionsGlobally(/Message manager disconnected/);
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "43");
+
+let {
+  promiseRestartManager,
+  promiseShutdownManager,
+  promiseStartupManager,
+} = AddonTestUtils;
+
+const server = createHttpServer({hosts: ["example.com"]});
+server.registerDirectory("/data/", do_get_file("data"));
+
+Services.prefs.setBoolPref("extensions.webextensions.background-delayed-startup", true);
+
+function trackEvents(wrapper) {
+  let events = new Map();
+  for (let event of ["background-page-event", "start-background-page"]) {
+    events.set(event, false);
+    wrapper.extension.once(event, () => events.set(event, true));
+  }
+  return events;
+}
+
+// Test that a non-blocking listener during startup does not immediately
+// start the background page, but the event is queued until the background
+// page is started.
+add_task(async function() {
+  await promiseStartupManager();
+
+  let extension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "permanent",
+    manifest: {
+      permissions: ["webRequest", "http://example.com/"],
+    },
+
+    background() {
+      browser.webRequest.onBeforeRequest.addListener(details => {
+        browser.test.sendMessage("saw-request");
+      }, {urls: ["http://example.com/data/file_sample.html"]});
+    },
+  });
+
+  await extension.startup();
+
+  await promiseRestartManager(false);
+
+  let events = trackEvents(extension);
+
+  await ExtensionTestUtils.fetch("http://example.com/",
+                                 "http://example.com/data/file_sample.html");
+
+  equal(events.get("background-page-event"), true,
+        "Should have gotten a background page event");
+  equal(events.get("start-background-page"), false,
+        "Background page should not be started");
+
+  Services.obs.notifyObservers(null, "browser-delayed-startup-finished");
+  await new Promise(executeSoon);
+
+  equal(events.get("start-background-page"), true,
+        "Should have gotten start-background-page event");
+
+  await extension.awaitMessage("saw-request");
+  ok(true, "Background page loaded and received webRequest event");
+
+  await extension.unload();
+
+  await promiseShutdownManager();
+});
+
+// Tests that filters are handled properly: if we have a blocking listener
+// with a filter, a request that does not match the filter does not get
+// suspended and does not start the background page.
+add_task(async function() {
+  await promiseStartupManager();
+
+  let extension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "permanent",
+    manifest: {
+      permissions: ["webRequest", "webRequestBlocking",
+                    "http://test1.example.com/"],
+    },
+
+    background() {
+      browser.webRequest.onBeforeRequest.addListener(details => {
+        browser.test.fail("Listener should not have been called");
+      }, {urls: ["http://test1.example.com/*"]}, ["blocking"]);
+
+      browser.test.sendMessage("ready");
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("ready");
+
+  await promiseRestartManager(false);
+
+  let events = trackEvents(extension);
+
+  await ExtensionTestUtils.fetch("http://example.com/",
+                                 "http://example.com/data/file_sample.html");
+
+  equal(events.get("background-page-event"), false,
+        "Should not have gotten a background page event");
+
+  Services.obs.notifyObservers(null, "browser-delayed-startup-finished");
+  await new Promise(executeSoon);
+
+  equal(events.get("start-background-page"), false,
+        "Should not have tried to start background page yet");
+
+  Services.obs.notifyObservers(null, "sessionstore-windows-restored");
+  await extension.awaitMessage("ready");
+
+  await extension.unload();
+  await promiseShutdownManager();
+});
+
+// Test that a block listener that uses filterResponseData() works
+// properly (i.e., that the delayed call to registerTraceableChannel
+// works properly).
+add_task(async function() {
+  const DATA = `<!DOCTYPE html>
+<html>
+<body>
+  <h1>This is a modified page</h1>
+</body>
+</html>`;
+
+  function background(data) {
+    browser.webRequest.onBeforeRequest.addListener(details => {
+      let filter = browser.webRequest.filterResponseData(details.requestId);
+      filter.onstop = () => {
+        let encoded = new TextEncoder("utf-8").encode(data);
+        filter.write(encoded);
+        filter.close();
+      };
+    }, {urls: ["http://example.com/data/file_sample.html"]}, ["blocking"]);
+  }
+
+  await promiseStartupManager();
+
+  let extension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "permanent",
+    manifest: {
+      permissions: ["webRequest", "webRequestBlocking", "http://example.com/"],
+    },
+
+    background: `(${background})(${uneval(DATA)})`,
+  });
+
+  await extension.startup();
+
+  await promiseRestartManager(false);
+
+  let dataPromise = ExtensionTestUtils.fetch("http://example.com/",
+                                             "http://example.com/data/file_sample.html");
+
+  Services.obs.notifyObservers(null, "browser-delayed-startup-finished");
+  let data = await dataPromise;
+
+  equal(data, DATA, "Stream filter was properly installed for a load during startup");
+
+  await extension.unload();
+  await promiseShutdownManager();
+});
+
--- a/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
@@ -110,16 +110,17 @@ skip-if = os == 'android' # Bug 1258975 
 skip-if = os == "android"
 [test_ext_unload_frame.js]
 skip-if = true # Too frequent intermittent failures
 [test_ext_webRequest_auth.js]
 [test_ext_webRequest_filterResponseData.js]
 [test_ext_webRequest_permission.js]
 [test_ext_webRequest_responseBody.js]
 [test_ext_webRequest_set_cookie.js]
+[test_ext_webRequest_startup.js]
 [test_ext_webRequest_suspend.js]
 [test_ext_webRequest_webSocket.js]
 [test_ext_xhr_capabilities.js]
 [test_native_manifests.js]
 subprocess = true
 skip-if = os == "android"
 [test_ext_permissions.js]
 skip-if = os == "android" # Bug 1350559
--- a/toolkit/content/tests/chrome/window_panel.xul
+++ b/toolkit/content/tests/chrome/window_panel.xul
@@ -226,41 +226,16 @@ var tests = [
 
       var tree = $("tree");
       tree.currentIndex = 0;
       panel.appendChild(tree);
       checkTreeCoords();
     }
   },
   {
-    testname: "noautohide panel with backdrag",
-    attrs: { noautohide: true, backdrag: "true" },
-    test: function(panel) {
-      var label = document.createElement("label");
-      label.id = "backdragspot";
-      label.setAttribute("value", "Hello There");
-      panel.appendChild(label);
-      panel.openPopupAtScreen(200, 230);
-    },
-    result: function(testname, panel) {
-      var oldrect = panel.getOuterScreenRect();
-
-      // Linux uses native window moving
-      if (!navigator.platform.includes("Linux")) {
-        var backdragspot = document.getElementById("backdragspot");
-        synthesizeMouse(backdragspot, 5, 5, { type: "mousedown" });
-        synthesizeMouse(backdragspot, 15, 20, { type: "mousemove" });
-        synthesizeMouse(backdragspot, 15, 20, { type: "mouseup" });
-
-        is(panel.getOuterScreenRect().left, 210, testname + "left");
-        is(panel.getOuterScreenRect().top, 245, testname + "top");
-      }
-    }
-  },
-  {
     // The panel should be allowed to appear and remain offscreen
     testname: "normal panel with flip='none' off-screen",
     attrs: { "flip": "none" },
     test: function(panel) {
       panel.openPopup(document.documentElement, "", -100 - mozInnerScreenX, -100 - mozInnerScreenY, false, false, null);
     },
     result: function(testname, panel) {
       var panelrect = panel.getBoundingClientRect();
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/content/widgets/popup.xml
@@ -270,32 +270,16 @@
       </handler>
     </handlers>
   </binding>
 
   <binding id="panel"
            extends="chrome://global/content/bindings/popup.xml#popup-base">
     <implementation>
       <field name="_prevFocus">0</field>
-      <field name="_dragBindingAlive">true</field>
-      <constructor>
-      <![CDATA[
-        if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
-          this._draggableStarted = true;
-          try {
-            let tmp = {};
-            ChromeUtils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
-            let draghandle = new tmp.WindowDraggingElement(this);
-            draghandle.mouseDownCheck = function() {
-              return this._dragBindingAlive;
-            };
-          } catch (e) {}
-        }
-      ]]>
-      </constructor>
     </implementation>
 
     <handlers>
       <handler event="popupshowing"><![CDATA[
         // Capture the previous focus before has a chance to get set inside the panel
         try {
           this._prevFocus = Cu
                             .getWeakReference(document.commandDispatcher.focusedElement);
--- a/toolkit/modules/WindowDraggingUtils.jsm
+++ b/toolkit/modules/WindowDraggingUtils.jsm
@@ -4,22 +4,21 @@
 
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 const HAVE_CSS_WINDOW_DRAG_SUPPORT = ["win", "macosx"].includes(AppConstants.platform);
 
 var EXPORTED_SYMBOLS = [ "WindowDraggingElement" ];
 
 function WindowDraggingElement(elem) {
+  if (HAVE_CSS_WINDOW_DRAG_SUPPORT) {
+    return;
+  }
   this._elem = elem;
   this._window = elem.ownerGlobal;
-  if (HAVE_CSS_WINDOW_DRAG_SUPPORT && !this.isPanel()) {
-    return;
-  }
-
   this._elem.addEventListener("mousedown", this);
 }
 
 WindowDraggingElement.prototype = {
   mouseDownCheck(e) { return true; },
   dragTags: ["box", "hbox", "vbox", "spacer", "label", "statusbarpanel", "stack",
              "toolbaritem", "toolbarseparator", "toolbarspring", "toolbarspacer",
              "radiogroup", "deck", "scrollbox", "arrowscrollbox", "tabs"],
@@ -46,56 +45,26 @@ WindowDraggingElement.prototype = {
     }
     while (target != this._elem) {
       if (!this.dragTags.includes(target.localName))
         return false;
       target = target.parentNode;
     }
     return true;
   },
-  isPanel() {
-    return ChromeUtils.getClassName(this._elem) == "XULElement" &&
-           this._elem.localName == "panel";
-  },
   handleEvent(aEvent) {
-    let isPanel = this.isPanel();
     switch (aEvent.type) {
       case "mousedown":
-        if (!this.shouldDrag(aEvent))
-          return;
-        if (!/^gtk/i.test(AppConstants.MOZ_WIDGET_TOOLKIT)) {
-          if (isPanel) {
-            let screenRect = this._elem.getOuterScreenRect();
-            this._deltaX = aEvent.screenX - screenRect.left;
-            this._deltaY = aEvent.screenY - screenRect.top;
-          } else {
-            this._deltaX = aEvent.screenX - this._window.screenX;
-            this._deltaY = aEvent.screenY - this._window.screenY;
-          }
+        if (this.shouldDrag(aEvent)) {
+          this._window.addEventListener("mousemove", this, { once: true });
+          this._window.addEventListener("mouseup", this, { once: true });
         }
-        this._draggingWindow = true;
-        this._window.addEventListener("mousemove", this);
-        this._window.addEventListener("mouseup", this);
         break;
       case "mousemove":
-        if (/^gtk/i.test(AppConstants.MOZ_WIDGET_TOOLKIT)) {
-          // On GTK, there is a toolkit-level function which handles
-          // window dragging. We want to start moving the window
-          // on the first mousemove event after mousedown.
-          this._window.beginWindowMove(aEvent, isPanel ? this._elem : null);
-          this._window.removeEventListener("mousemove", this);
-          break;
-        }
-        if (this._draggingWindow) {
-          let toDrag = this.isPanel() ? this._elem : this._window;
-          toDrag.moveTo(aEvent.screenX - this._deltaX, aEvent.screenY - this._deltaY);
-        }
+        this._window.beginWindowMove(aEvent);
+        this._window.removeEventListener("mouseup", this);
         break;
       case "mouseup":
-        if (this._draggingWindow) {
-          this._draggingWindow = false;
-          this._window.removeEventListener("mousemove", this);
-          this._window.removeEventListener("mouseup", this);
-        }
+        this._window.removeEventListener("mousemove", this);
         break;
     }
   }
 };
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -751,17 +751,19 @@ HttpObserverManager = {
           if (this.STATUS_TYPES.has(kind)) {
             commonData.statusCode = channel.statusCode;
             commonData.statusLine = channel.statusLine;
           }
         }
         let data = Object.create(commonData);
 
         if (registerFilter && opts.blocking && opts.extension) {
-          channel.registerTraceableChannel(opts.extension, opts.tabParent);
+          data.registerTraceableChannel = (extension, tabParent) => {
+            channel.registerTraceableChannel(extension, tabParent);
+          };
         }
 
         if (opts.requestHeaders) {
           requestHeaders = requestHeaders || new RequestHeaderChanger(channel);
           data.requestHeaders = requestHeaders.toArray();
         }
 
         if (opts.responseHeaders) {
rename from ipc/glue/Faulty.cpp
rename to tools/fuzzing/faulty/Faulty.cpp
--- a/ipc/glue/Faulty.cpp
+++ b/tools/fuzzing/faulty/Faulty.cpp
@@ -2,29 +2,43 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cerrno>
 #include <climits>
 #include <cmath>
+#include <fstream>
 #include <prinrval.h>
 #include <unistd.h>
 #include "base/string_util.h"
+#include "FuzzingMutate.h"
+#include "FuzzingTraits.h"
+#include "chrome/common/ipc_channel.h"
 #include "chrome/common/ipc_message.h"
-#include "chrome/common/ipc_channel.h"
+#include "chrome/common/file_descriptor_set_posix.h"
 #include "mozilla/ipc/Faulty.h"
 #include "mozilla/TypeTraits.h"
+#include "nsNetCID.h"
+#include "nsIFile.h"
+#include "nsIFileStreams.h"
+#include "nsILineInputStream.h"
+#include "nsLocalFile.h"
+#include "nsPrintfCString.h"
+#include "nsTArray.h"
 #include "nsXULAppAPI.h"
 #include "prenv.h"
 
+
 namespace mozilla {
 namespace ipc {
 
+using namespace mozilla::fuzzing;
+
 const unsigned int Faulty::sDefaultProbability = Faulty::DefaultProbability();
 const bool Faulty::sIsLoggingEnabled = Faulty::Logging();
 
 /**
  * RandomNumericValue generates negative and positive integrals.
  */
 template <typename T>
 T RandomIntegral()
@@ -55,17 +69,17 @@ T RandomNumericLimit() {
  * RandomIntegerRange returns a random integral within a user defined range.
  */
 template <typename T>
 T RandomIntegerRange(T min, T max)
 {
   static_assert(mozilla::IsIntegral<T>::value == true,
                 "T must be an integral type");
   MOZ_ASSERT(min < max);
-  return static_cast<T>(random() % (max - min) + min);
+  return static_cast<T>((random() % (max - min + 1)) + min);
 }
 
 /**
  * RandomFloatingPointRange returns a random floating-point number within a
  * user defined range.
  */
 template <typename T>
 T RandomFloatingPointRange(T min, T max)
@@ -83,61 +97,55 @@ T RandomFloatingPointRange(T min, T max)
 template <typename T>
 T RandomFloatingPoint()
 {
   static_assert(mozilla::IsFloatingPoint<T>::value == true,
                 "T must be a floating point type");
   int radix = RandomIntegerRange<int>(std::numeric_limits<T>::min_exponent,
                                       std::numeric_limits<T>::max_exponent);
   T x = static_cast<T>(pow(2.0, static_cast<double>(radix)));
-  return x * RandomFloatingPointRange<T>(1.0, 2.0);
+  return x * RandomFloatingPointRange<T>(0.0, 10.0);
 }
 
 /**
  * FuzzIntegralType mutates an incercepted integral type of a pickled message.
  */
 template <typename T>
 void FuzzIntegralType(T* v, bool largeValues)
 {
   static_assert(mozilla::IsIntegral<T>::value == true,
                 "T must be an integral type");
   switch (random() % 6) {
     case 0:
       if (largeValues) {
         (*v) = RandomIntegral<T>();
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
-
     case 1:
       if (largeValues) {
         (*v) = RandomNumericLimit<T>();
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
-
     case 2:
       if (largeValues) {
         (*v) = RandomIntegerRange<T>(std::numeric_limits<T>::min(),
                                      std::numeric_limits<T>::max());
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
     default:
       switch(random() % 2) {
         case 0:
           // Prevent underflow
           if (*v != std::numeric_limits<T>::min()) {
             (*v)--;
             break;
           }
-          // Fall through
           MOZ_FALLTHROUGH;
         case 1:
           // Prevent overflow
           if (*v != std::numeric_limits<T>::max()) {
             (*v)++;
             break;
           }
       }
@@ -154,111 +162,143 @@ void FuzzFloatingPointType(T* v, bool la
   static_assert(mozilla::IsFloatingPoint<T>::value == true,
                 "T must be a floating point type");
   switch (random() % 6) {
     case 0:
       if (largeValues) {
         (*v) = RandomNumericLimit<T>();
         break;
     }
-    // Fall through
     MOZ_FALLTHROUGH;
     case 1:
       if (largeValues) {
         (*v) = RandomFloatingPointRange<T>(std::numeric_limits<T>::min(),
                                            std::numeric_limits<T>::max());
         break;
       }
-    // Fall through
     MOZ_FALLTHROUGH;
     default:
       (*v) = RandomFloatingPoint<T>();
   }
 }
 
 /**
  * FuzzStringType mutates an incercepted string type of a pickled message.
  */
 template <typename T>
 void FuzzStringType(T& v, const T& literal1, const T& literal2)
 {
   switch (random() % 5) {
     case 4:
       v = v + v;
-      // Fall through
       MOZ_FALLTHROUGH;
     case 3:
       v = v + v;
-      // Fall through
       MOZ_FALLTHROUGH;
     case 2:
       v = v + v;
       break;
     case 1:
       v += literal1;
       break;
     case 0:
       v = literal2;
       break;
   }
 }
 
 
 Faulty::Faulty()
+  // Mutate messages as a blob.
+  : mFuzzMessages(!!PR_GetEnv("FAULTY_MESSAGES"))
   // Enables the strategy for fuzzing pipes.
-  : mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
+  , mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
   // Enables the strategy for fuzzing pickled messages.
   , mFuzzPickle(!!PR_GetEnv("FAULTY_PICKLE"))
   // Uses very large values while fuzzing pickled messages.
   // This may cause a high amount of malloc_abort() / NS_ABORT_OOM crashes.
   , mUseLargeValues(!!PR_GetEnv("FAULTY_LARGE_VALUES"))
+  // Use the provided blacklist as whitelist.
+  , mUseAsWhitelist(!!PR_GetEnv("FAULTY_AS_WHITELIST"))
   // Sets up our target process.
   , mIsValidProcessType(IsValidProcessType())
 {
-  FAULTY_LOG("Initializing.");
+  if (mIsValidProcessType) {
+    FAULTY_LOG("Initializing for new process of type '%s' with pid %u.",
+      XRE_ChildProcessTypeToString(XRE_GetProcessType()),
+      getpid());
+
+    /* Setup random seed. */
+    const char* userSeed = PR_GetEnv("FAULTY_SEED");
+    unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
+    if (userSeed) {
+      long n = std::strtol(userSeed, nullptr, 10);
+      if (n != 0) {
+        randomSeed = static_cast<unsigned long>(n);
+      }
+    }
+    srandom(randomSeed);
 
-  const char* userSeed = PR_GetEnv("FAULTY_SEED");
-  unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
-  if (userSeed) {
-    long n = std::strtol(userSeed, nullptr, 10);
-    if (n != 0) {
-      randomSeed = static_cast<unsigned long>(n);
+    /* Setup directory for dumping messages. */
+    mMessagePath = PR_GetEnv("FAULTY_MESSAGE_PATH");
+    if (mMessagePath && *mMessagePath) {
+      if (CreateOutputDirectory(mMessagePath) != NS_OK) {
+        mMessagePath = nullptr;
+      }
     }
-  }
-  srandom(randomSeed);
+
+    /* Set IPC messages blacklist. */
+    mBlacklistPath = PR_GetEnv("FAULTY_BLACKLIST");
+    if (mBlacklistPath && *mBlacklistPath) {
+      FAULTY_LOG("* Using message blacklist    = %s", mBlacklistPath);
+    }
 
-  FAULTY_LOG("Fuzz probability = %u", sDefaultProbability);
-  FAULTY_LOG("Random seed      = %lu", randomSeed);
-  FAULTY_LOG("Strategy: pickle = %s", mFuzzPickle ? "enabled" : "disabled");
-  FAULTY_LOG("Strategy: pipe   = %s", mFuzzPipes ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: messages = %s", mFuzzMessages ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: pickle   = %s", mFuzzPickle ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: pipe     = %s", mFuzzPipes ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing probability        = %u", sDefaultProbability);
+    FAULTY_LOG("* Fuzzing mutation factor    = %u", MutationFactor());
+    FAULTY_LOG("* RNG seed                   = %lu", randomSeed);
+
+    sMsgCounter = 0;
+  }
 }
 
 // static
 bool
 Faulty::IsValidProcessType(void)
 {
   bool isValidProcessType;
   const bool targetChildren = !!PR_GetEnv("FAULTY_CHILDREN");
   const bool targetParent = !!PR_GetEnv("FAULTY_PARENT");
+  unsigned short int currentProcessType = XRE_GetProcessType();
 
   if (targetChildren && !targetParent) {
-    // Fuzz every process type but not the content process.
-    isValidProcessType = XRE_GetProcessType() != GeckoProcessType_Content;
+    // Fuzz every child process type but not the parent process.
+    isValidProcessType = currentProcessType == GeckoProcessType_Default;
+  } else if (!targetChildren && targetParent
+          && (currentProcessType == GeckoProcessType_Plugin
+          || currentProcessType == GeckoProcessType_Content
+          || currentProcessType == GeckoProcessType_GMPlugin
+          || currentProcessType == GeckoProcessType_GPU
+          || currentProcessType == GeckoProcessType_PDFium)) {
+    // Fuzz inside any of the above child process only.
+    isValidProcessType = true;
   } else if (targetChildren && targetParent) {
     // Fuzz every process type.
     isValidProcessType = true;
   } else {
-    // Fuzz the content process only.
-    isValidProcessType = XRE_GetProcessType() == GeckoProcessType_Content;
+    // Fuzz no process type at all.
+    isValidProcessType = false;
   }
 
-  // Parent and children are different threads in the same process on
-  // desktop builds.
   if (!isValidProcessType) {
-    FAULTY_LOG("Invalid process type for pid=%d", getpid());
+    FAULTY_LOG("Disabled for this process of type '%s' with pid %d.",
+      XRE_ChildProcessTypeToString(XRE_GetProcessType()),
+      getpid());
   }
 
   return isValidProcessType;
 }
 
 // static
 unsigned int
 Faulty::DefaultProbability(void)
@@ -277,55 +317,66 @@ Faulty::DefaultProbability(void)
 // static
 bool
 Faulty::Logging(void)
 {
   // Enables logging of sendmsg() calls even in optimized builds.
   return !!PR_GetEnv("FAULTY_ENABLE_LOGGING");
 }
 
-unsigned int
-Faulty::Random(unsigned int aMax)
+
+// static
+uint32_t
+Faulty::MutationFactor()
 {
-  MOZ_ASSERT(aMax > 0);
-  return static_cast<unsigned int>(random() % aMax);
-}
+  static uint64_t sPropValue = FAULTY_DEFAULT_MUTATION_FACTOR;
+  static bool sInitialized = false;
+
+  if (sInitialized) {
+    return sPropValue;
+  }
+  sInitialized = true;
 
-bool
-Faulty::GetChance(unsigned int aProbability)
-{
-  return Random(aProbability) == 0;
+  const char* factor = PR_GetEnv("FAULTY_MUTATION_FACTOR");
+  if (factor) {
+    long n = strtol(factor, nullptr, 10);
+    if (n != 0) {
+      sPropValue = n;
+      return sPropValue;
+    }
+  }
+  return sPropValue;
 }
 
 //
 // Strategy: Pipes
 //
 
 void
 Faulty::MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability)
 {
   if (!mFuzzPipes) {
     return;
   }
 
   if (aPipe > -1) {
-    FAULTY_LOG("collecting pipe %d to bucket of pipes (count: %ld)",
+    FAULTY_LOG("Collecting pipe %d to bucket of pipes (count: %ld)",
                aPipe, mFds.size());
     mFds.insert(aPipe);
   }
 
-  if (mFds.size() > 0 && GetChance(aProbability)) {
+  if (mFds.size() > 0 && FuzzingTraits::Sometimes(aProbability)) {
     std::set<int>::iterator it(mFds.begin());
-    std::advance(it, Random(mFds.size()));
-    FAULTY_LOG("trying to close collected pipe: %d", *it);
+    std::advance(it, FuzzingTraits::Random(mFds.size()));
+    FAULTY_LOG("Trying to close collected pipe: %d", *it);
     errno = 0;
     while ((close(*it) == -1 && (errno == EINTR))) {
       ;
     }
-    FAULTY_LOG("pipe status after attempt to close: %d", errno);
+    FAULTY_LOG("Pipe status after attempt to close: %d", errno);
     mFds.erase(it);
   }
 }
 
 //
 // Strategy: Pickle
 //
 
@@ -334,333 +385,535 @@ Faulty::MutateBool(bool* aValue)
 {
   *aValue = !(*aValue);
 }
 
 void
 Faulty::FuzzBool(bool* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       bool oldValue = *aValue;
       MutateBool(aValue);
-      FAULTY_LOG("pickle field {bool} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |bool| of value: %d mutated to: %d",
                  (int)oldValue, (int)*aValue);
     }
   }
 }
 
 void
 Faulty::MutateChar(char* aValue)
 {
   FuzzIntegralType<char>(aValue, true);
 }
 
 void
 Faulty::FuzzChar(char* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       char oldValue = *aValue;
       MutateChar(aValue);
-      FAULTY_LOG("pickle field {char} of value: %c changed to: %c",
+      FAULTY_LOG("Message field |char| of value: %c mutated to: %c",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUChar(unsigned char* aValue)
 {
   FuzzIntegralType<unsigned char>(aValue, true);
 }
 
 void
 Faulty::FuzzUChar(unsigned char* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       unsigned char oldValue = *aValue;
       MutateUChar(aValue);
-      FAULTY_LOG("pickle field {unsigned char} of value: %u changed to: %u",
+      FAULTY_LOG("Message field |unsigned char| of value: %u mutated to: %u",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt16(int16_t* aValue)
 {
   FuzzIntegralType<int16_t>(aValue, true);
 }
 
 void
 Faulty::FuzzInt16(int16_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int16_t oldValue = *aValue;
       MutateInt16(aValue);
-      FAULTY_LOG("pickle field {Int16} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |int16| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt16(uint16_t* aValue)
 {
   FuzzIntegralType<uint16_t>(aValue, true);
 }
 
 void
 Faulty::FuzzUInt16(uint16_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint16_t oldValue = *aValue;
       MutateUInt16(aValue);
-      FAULTY_LOG("pickle field {UInt16} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |uint16| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt(int* aValue)
 {
   FuzzIntegralType<int>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzInt(int* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int oldValue = *aValue;
       MutateInt(aValue);
-      FAULTY_LOG("pickle field {int} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |int| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt32(uint32_t* aValue)
 {
   FuzzIntegralType<uint32_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzUInt32(uint32_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint32_t oldValue = *aValue;
       MutateUInt32(aValue);
-      FAULTY_LOG("pickle field {UInt32} of value: %u changed to: %u",
+      FAULTY_LOG("Message field |uint32| of value: %u mutated to: %u",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateLong(long* aValue)
 {
   FuzzIntegralType<long>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzLong(long* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       long oldValue = *aValue;
       MutateLong(aValue);
-      FAULTY_LOG("pickle field {long} of value: %ld changed to: %ld",
+      FAULTY_LOG("Message field |long| of value: %ld mutated to: %ld",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateULong(unsigned long* aValue)
 {
   FuzzIntegralType<unsigned long>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzULong(unsigned long* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       unsigned long oldValue = *aValue;
       MutateULong(aValue);
-      FAULTY_LOG("pickle field {unsigned long} of value: %lu changed to: %lu",
+      FAULTY_LOG("Message field |unsigned long| of value: %lu mutated to: %lu",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateSize(size_t* aValue)
 {
   FuzzIntegralType<size_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzSize(size_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       size_t oldValue = *aValue;
       MutateSize(aValue);
-      FAULTY_LOG("pickle field {size_t} of value: %zu changed to: %zu",
+      FAULTY_LOG("Message field |size_t| of value: %zu mutated to: %zu",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt64(uint64_t* aValue)
 {
   FuzzIntegralType<uint64_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzUInt64(uint64_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint64_t oldValue = *aValue;
       MutateUInt64(aValue);
-      FAULTY_LOG("pickle field {UInt64} of value: %" PRIu64 " changed to: %" PRIu64,
+      FAULTY_LOG("Message field |uint64| of value: %" PRIu64 " mutated to: %" PRIu64,
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt64(int64_t* aValue)
 {
   FuzzIntegralType<int64_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzInt64(int64_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int64_t oldValue = *aValue;
       MutateInt64(aValue);
-      FAULTY_LOG("pickle field {UInt64} of value: %" PRIu64 " changed to: %" PRIu64,
+      FAULTY_LOG("Message field |int64| of value: %" PRIu64 " mutated to: %" PRIu64,
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateDouble(double* aValue)
 {
   FuzzFloatingPointType<double>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzDouble(double* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       double oldValue = *aValue;
       MutateDouble(aValue);
-      FAULTY_LOG("pickle field {double} of value: %f changed to: %f",
+      FAULTY_LOG("Message field |double| of value: %f mutated to: %f",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateFloat(float* aValue)
 {
   FuzzFloatingPointType<float>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzFloat(float* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       float oldValue = *aValue;
       MutateFloat(aValue);
-      FAULTY_LOG("pickle field {float} of value: %f changed to: %f",
+      FAULTY_LOG("Message field |float| of value: %f mutated to: %f",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::FuzzString(std::string& aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       std::string oldValue = aValue;
       FuzzStringType<std::string>(aValue, "xoferiF", std::string());
-      FAULTY_LOG("pickle field {string} of value: %s changed to: %s",
+      FAULTY_LOG("Message field |string| of value: %s mutated to: %s",
                  oldValue.c_str(), aValue.c_str());
     }
   }
 }
 
 void
 Faulty::FuzzWString(std::wstring& aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       std::wstring oldValue = aValue;
-      FAULTY_LOG("pickle field {wstring}");
+      FAULTY_LOG("Message field |wstring|");
       FuzzStringType<std::wstring>(aValue, L"xoferiF", std::wstring());
     }
   }
 }
 
-void
-Faulty::FuzzString16(string16& aValue, unsigned int aProbability)
-{
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      string16 oldValue = aValue;
-      FAULTY_LOG("pickle field {string16}");
-      FuzzStringType<string16>(aValue,
-        string16(ASCIIToUTF16(std::string("xoferiF"))),
-        string16(ASCIIToUTF16(std::string())));
+// static
+nsresult
+Faulty::CreateOutputDirectory(const char *aPathname) {
+  nsCOMPtr<nsIFile> path;
+  bool exists;
+  nsresult rv;
+
+  rv = NS_NewNativeLocalFile(nsDependentCString(aPathname),
+                             true,
+                             getter_AddRefs(path));
+
+  rv = path->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (!exists) {
+    rv = path->Create(nsIFile::DIRECTORY_TYPE, 0755);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
     }
   }
+
+  return NS_OK;
+}
+
+/* static */
+nsresult
+Faulty::ReadFile(const char* aPathname, nsTArray<nsCString> &aArray)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> file;
+
+  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aPathname),
+                       true,
+                       getter_AddRefs(file));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool exists = false;
+  rv = file->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv)) || !exists) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIFileInputStream> fileStream(
+    do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = fileStream->Init(file, -1, -1, 0);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoCString line;
+  bool more = true;
+  do {
+    rv = lineStream->ReadLine(line, &more);
+    if (line.IsEmpty()) {
+      continue;
+    }
+    if (line.CharAt(0) == '#') {
+      /* Ignore comments. */
+      continue;
+    }
+    aArray.AppendElement(line);
+  } while (more);
+
+  file.forget();
+
+  return NS_OK;
+}
+
+bool
+Faulty::IsMessageNameBlacklisted(const char *aMessageName) {
+  static bool sFileLoaded = false;
+  static nsTArray<nsCString> sMessageBlacklist;
+
+  if (!sFileLoaded && mBlacklistPath) {
+    if (ReadFile(mBlacklistPath, sMessageBlacklist) != NS_OK) {
+      return false;
+    }
+    sFileLoaded = true;
+  }
+
+  if (sMessageBlacklist.Length() == 0) {
+    return false;
+  }
+
+  return sMessageBlacklist.Contains(aMessageName);
+}
+
+// static
+std::vector<uint8_t>
+Faulty::GetDataFromIPCMessage(IPC::Message* aMsg)
+{
+  const Pickle::BufferList& buffers = aMsg->Buffers();
+  std::vector<uint8_t> data;
+  data.reserve(buffers.Size());
+
+  Pickle::BufferList::IterImpl i = buffers.Iter();
+  while (!i.Done()) {
+    size_t s = i.RemainingInSegment();
+    data.insert(data.end(), i.Data(), i.Data() + s);
+
+    i.Advance(buffers, s);
+  }
+
+  return data;
+}
+
+// static
+void
+Faulty::CopyFDs(IPC::Message* aDstMsg, IPC::Message* aSrcMsg) {
+    FileDescriptorSet* dstFdSet = aDstMsg->file_descriptor_set();
+    FileDescriptorSet* srcFdSet = aSrcMsg->file_descriptor_set();
+    for (size_t i = 0; i < srcFdSet->size(); i++) {
+        int fd = srcFdSet->GetDescriptorAt(i);
+        dstFdSet->Add(fd);
+    }
+}
+
+IPC::Message *
+Faulty::MutateIPCMessage(const char *aChannel, IPC::Message* aMsg, unsigned int aProbability) {
+  if (!mIsValidProcessType || !mFuzzMessages) {
+    return aMsg;
+  }
+
+  sMsgCounter += 1;
+  LogMessage(aChannel, aMsg);
+
+  /* Skip immediately if we shall not try to fuzz this message. */
+  if (!FuzzingTraits::Sometimes(aProbability)) {
+    return aMsg;
+  }
+
+  const bool isMessageListed = IsMessageNameBlacklisted(aMsg->name());
+
+  /* Check if this message is blacklisted and shall not get fuzzed. */
+  if (isMessageListed && !mUseAsWhitelist) {
+    FAULTY_LOG("BLACKLISTED: %s", aMsg->name());
+    return aMsg;
+  }
+
+  /* Check if the message is whitelisted. */
+  if (!isMessageListed && mUseAsWhitelist) {
+    /* Silently skip this message. */
+    return aMsg;
+  }
+
+  /* Retrieve BufferLists as data from original message. */
+  std::vector<uint8_t> data(GetDataFromIPCMessage(aMsg));
+
+  /* Check if there is enough data in the message to fuzz. */
+  uint32_t headerSize = aMsg->HeaderSizeFromData(nullptr, nullptr);
+  if (headerSize == data.size()) {
+    FAULTY_LOG("IGNORING: %s", aMsg->name());
+    return aMsg;
+  }
+
+  /* Mutate the message data. */
+  size_t maxMutations = FuzzingTraits::Frequency(data.size(), MutationFactor());
+  FAULTY_LOG("FUZZING (%zu bytes): %s", maxMutations, aMsg->name());
+  while (maxMutations--) {
+    /* Ignore the header data of the message. */
+    uint32_t pos = RandomIntegerRange<uint32_t>(headerSize, data.size() - 1);
+    switch (FuzzingTraits::Random(6)) {
+      case 0:
+        break;
+      case 1:
+        data.at(pos) = RandomIntegerRange<uint8_t>(0, 1);
+        break;
+      case 2:
+        data.at(pos) ^= (1 << RandomIntegerRange<uint8_t>(0, 8));
+        break;
+      default:
+        data.at(pos) = RandomIntegerRange<uint8_t>(255, 255);
+    }
+  }
+
+  /* Build new message. */
+  auto *mutatedMsg = new IPC::Message(reinterpret_cast<const char*>(data.data()), data.size());
+  CopyFDs(mutatedMsg, aMsg);
+
+  /* Dump original message for diff purposes. */
+  DumpMessage(aChannel, aMsg, nsPrintfCString(".%zu.o", sMsgCounter).get());
+  /* Dump mutated message for diff purposes. */
+  DumpMessage(aChannel, mutatedMsg, nsPrintfCString(".%zu.m", sMsgCounter).get());
+
+  delete aMsg;
+
+  return mutatedMsg;
 }
 
 void
-Faulty::FuzzBytes(void* aData, int aLength, unsigned int aProbability)
-{
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      FAULTY_LOG("pickle field {bytes}");
-      // Too destructive. |WriteBytes| is used in many of the above data
-      // types as base function.
-      //FuzzData(static_cast<char*>(aData), aLength);
-    }
+Faulty::LogMessage(const char* aChannel, IPC::Message* aMsg) {
+  if (!mIsValidProcessType) {
+    return;
   }
+
+  std::string fileName = nsPrintfCString("message.%u.%zu",
+    getpid(), sMsgCounter).get();
+
+  FAULTY_LOG("Process: %u | Size: %10zu | %-20s | %s => %s",
+    XRE_GetProcessType(),
+    aMsg->Buffers().Size(),
+    fileName.c_str(),
+    aChannel,
+    aMsg->name());
 }
 
 void
-Faulty::FuzzData(std::string& aValue, int aLength, unsigned int aProbability)
+Faulty::DumpMessage(const char *aChannel, IPC::Message* aMsg, std::string aAppendix)
 {
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      FAULTY_LOG("pickle field {data}");
-      for (int i = 0; i < aLength; ++i) {
-        if (GetChance(aProbability)) {
-          FuzzIntegralType<char>(&aValue[i], true);
-        }
-      }
-    }
+  if (!mIsValidProcessType || !mMessagePath) {
+    return;
   }
+
+  std::vector<uint8_t> data(GetDataFromIPCMessage(aMsg));
+  std::string fileName;
+
+  if (!aAppendix.empty()) {
+    fileName = nsPrintfCString("%s/message.%u%s",
+      mMessagePath, getpid(), aAppendix.c_str()).get();
+  } else {
+    fileName = nsPrintfCString("%s/%s",
+      mMessagePath, fileName.c_str()).get();
+  }
+
+  std::fstream fp;
+  fp.open(fileName, std::fstream::out | std::fstream::binary);
+  fp.write(reinterpret_cast<const char*>(data.data()), data.size());
+  fp.close();
 }
 
 } // namespace ipc
 } // namespace mozilla
+
rename from ipc/glue/Faulty.h
rename to tools/fuzzing/faulty/Faulty.h
--- a/ipc/glue/Faulty.h
+++ b/tools/fuzzing/faulty/Faulty.h
@@ -4,24 +4,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ipc_Faulty_h
 #define mozilla_ipc_Faulty_h
 
 #include <set>
 #include <string>
-#include "nsDebug.h"
+#include <vector>
 #include "base/string16.h"
 #include "base/singleton.h"
+#include "nsDebug.h"
+#include "nsTArray.h"
 
 #define FAULTY_DEFAULT_PROBABILITY 1000
+#define FAULTY_DEFAULT_MUTATION_FACTOR 10
 #define FAULTY_LOG(fmt, args...) \
   if (mozilla::ipc::Faulty::IsLoggingEnabled()) { \
-    printf_stderr("[Faulty] " fmt "\n", ## args); \
+    printf_stderr("[Faulty] (%10u) " fmt "\n", getpid(), ## args); \
   }
 
 namespace IPC {
   // Needed for blacklisting messages.
   class Message;
 }
 
 namespace mozilla {
@@ -31,58 +34,76 @@ class Faulty
 {
   public:
     // Used as a default argument for the Fuzz|datatype| methods.
     static const unsigned int sDefaultProbability;
 
     static unsigned int DefaultProbability(void);
     static bool Logging(void);
     static bool IsLoggingEnabled(void) { return sIsLoggingEnabled; }
+    static std::vector<uint8_t> GetDataFromIPCMessage(IPC::Message* aMsg);
+    static nsresult CreateOutputDirectory(const char *aPathname);
+    static nsresult ReadFile(const char* aPathname, nsTArray<nsCString> &aArray);
+    static void CopyFDs(IPC::Message* aDstMsg, IPC::Message* aSrcMsg);
 
+    // Fuzzing methods for Pickle.
     void FuzzBool(bool* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzChar(char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUChar(unsigned char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt16(int16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt16(uint16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt(int* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt32(uint32_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzLong(long* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzULong(unsigned long* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt64(int64_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt64(uint64_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzSize(size_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzFloat(float* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzDouble(double* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzString(std::string& aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzWString(std::wstring& aValue, unsigned int aProbability=sDefaultProbability);
-    void FuzzString16(string16& aValue, unsigned int aProbability=sDefaultProbability);
-    void FuzzData(std::string& aData, int aLength, unsigned int aProbability=sDefaultProbability);
     void FuzzBytes(void* aData, int aLength, unsigned int aProbability=sDefaultProbability);
 
+    // Fuzzing methods for pipe fuzzing.
     void MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability=sDefaultProbability);
 
+    // Fuzzing methods for message blob fuzzing.
+    void DumpMessage(const char *aChannel, IPC::Message* aMsg, std::string aAppendix=nullptr);
+    bool IsMessageNameBlacklisted(const char* aMessageName);
+    IPC::Message* MutateIPCMessage(const char *aChannel, IPC::Message* aMsg,
+      unsigned int aProbability=sDefaultProbability);
+
+    void LogMessage(const char* aChannel, IPC::Message* aMsg);
+
   private:
     std::set<int> mFds;
 
+    const bool mFuzzMessages;
     const bool mFuzzPipes;
     const bool mFuzzPickle;
     const bool mUseLargeValues;
+    const bool mUseAsWhitelist;
     const bool mIsValidProcessType;
 
+    const char* mMessagePath;
+    const char* mBlacklistPath;
+
+    size_t sMsgCounter;
+
     static const bool sIsLoggingEnabled;
 
     Faulty();
     friend struct DefaultSingletonTraits<Faulty>;
     DISALLOW_EVIL_CONSTRUCTORS(Faulty);
 
     static bool IsValidProcessType(void);
+    static uint32_t MutationFactor();
 
-    unsigned int Random(unsigned int aMax);
-    bool GetChance(unsigned int aProbability);
-
+    // Fuzzing methods for Pickle
     void MutateBool(bool* aValue);
     void MutateChar(char* aValue);
     void MutateUChar(unsigned char* aValue);
     void MutateInt16(int16_t* aValue);
     void MutateUInt16(uint16_t* aValue);
     void MutateInt(int* aValue);
     void MutateUInt32(uint32_t* aValue);
     void MutateLong(long* aValue);
@@ -93,8 +114,9 @@ class Faulty
     void MutateFloat(float* aValue);
     void MutateDouble(double* aValue);
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif
+
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/faulty/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+  'Faulty.cpp'
+]
+
+EXPORTS.mozilla.ipc += [
+  'Faulty.h'
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
--- a/tools/fuzzing/moz.build
+++ b/tools/fuzzing/moz.build
@@ -7,16 +7,17 @@
 DIRS += [
   'interface',
   'registry',
 ]
 
 if not CONFIG['JS_STANDALONE']:
   DIRS += [
     'common',
+    'faulty',
     'messagemanager',
     'shmem',
   ]
 
 if CONFIG['LIBFUZZER']:
   DIRS += [
     'libfuzzer',
   ]