Merge autoland to mozilla-central r=merge a=merge
authorCiure Andrei <aciure@mozilla.com>
Fri, 15 Dec 2017 23:49:52 +0200
changeset 448285 fff6ca61de4510d3ef0ad17751bd134fd576577a
parent 448227 6f0b1fa79e838579c9444383d7775966378117b8 (current diff)
parent 448284 ff0c2391364e596ddfddafe31e88466a3c65c811 (diff)
child 448292 4398768baa23a1d1888116a484817e20f2701dcc
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central r=merge a=merge
devtools/client/netmonitor/test/shared-head.js
layout/reftests/svg/smil/event/accesskey-entity-1.svg
layout/reftests/svg/smil/event/accesskey-entity-2.svg
--- a/accessible/.eslintrc.js
+++ b/accessible/.eslintrc.js
@@ -4,14 +4,13 @@ module.exports = {
   "rules": {
     // Warn about cyclomatic complexity in functions.
     "complexity": ["error", 42],
 
     // XXX These are rules that are enabled in the recommended configuration, but
     // disabled here due to failures when initially implemented. They should be
     // removed (and hence enabled) at some stage.
     "consistent-return": "off",
-    "object-shorthand": "off",
     "no-unexpected-multiline": "off",
     "no-unsafe-finally": "off",
     "no-useless-call": "off",
   }
 };
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -293,17 +293,17 @@ this.AccessFu = { // jshint ignore:line
 
   _handleMessageManager: function _handleMessageManager(aMessageManager) {
     if (this._enabled) {
       this._addMessageListeners(aMessageManager);
     }
     this._loadFrameScript(aMessageManager);
   },
 
-  onEvent: function(event, data, callback) {
+  onEvent(event, data, callback) {
     switch (event) {
       case "Accessibility:Settings":
         this._systemPref = data.enabled;
         this._enableOrDisable();
         break;
       case "Accessibility:NextObject":
       case "Accessibility:PreviousObject": {
         let rule = "Simple";
@@ -420,18 +420,17 @@ this.AccessFu = { // jshint ignore:line
 
   /**
    * Adjusts the given bounds relative to the given browser.
    * @param {Rect} aJsonBounds the bounds to adjust
    * @param {browser} aBrowser the browser we want the bounds relative to
    * @param {bool} aToCSSPixels whether to convert to CSS pixels (as opposed to
    *               device pixels)
    */
-  adjustContentBounds:
-    function(aJsonBounds, aBrowser, aToCSSPixels) {
+  adjustContentBounds(aJsonBounds, aBrowser, aToCSSPixels) {
       let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
                             aJsonBounds.right - aJsonBounds.left,
                             aJsonBounds.bottom - aJsonBounds.top);
       let win = Utils.win;
       let dpr = win.devicePixelRatio;
       let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
 
       // Add the offset; the offset is in CSS pixels, so multiply the
@@ -874,17 +873,17 @@ var Input = {
   },
 
   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;
 
     mm.sendAsyncMessage("AccessFu:Activate",
-                        {offset: offset, activateIfKey: aActivateIfKey});
+                        {offset, activateIfKey: aActivateIfKey});
   },
 
   sendContextMenuMessage: function sendContextMenuMessage() {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage("AccessFu:ContextMenu", {});
   },
 
   setEditState: function setEditState(aEditState) {
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -234,17 +234,17 @@ this.EventManager.prototype = {
           Ci.nsIAccessibleObjectAttributeChangedEvent);
         if (evt.changedAttribute !== "aria-hidden") {
           // Only handle aria-hidden attribute change.
           break;
         }
         let hidden = Utils.isHidden(aEvent.accessible);
         this[hidden ? "_handleHide" : "_handleShow"](evt);
         if (this.inTest) {
-          this.sendMsgFunc("AccessFu:AriaHidden", { hidden: hidden });
+          this.sendMsgFunc("AccessFu:AriaHidden", { hidden });
         }
         break;
       }
       case Events.SHOW:
       {
         this._handleShow(aEvent);
         break;
       }
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -300,17 +300,17 @@ function compileDetail(aType, aPoints, k
       maxDeltaY = deltaY;
     }
     // Since the gesture is resolving, reset the points' distance information
     // since they are passed to the next potential gesture.
     point.reset();
   }
   return {
     type: aType,
-    touches: touches,
+    touches,
     deltaX: maxDeltaX,
     deltaY: maxDeltaY
   };
 }
 
 /**
  * A general gesture object.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -164,17 +164,17 @@ VisualPresenter.prototype.viewportChange
     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: bounds,
+          bounds,
           padding: this.BORDER_PADDING
         }
       };
     }
 
     return null;
   };
 
@@ -193,17 +193,17 @@ VisualPresenter.prototype.pivotChanged =
             aContext.bounds : Utils.getTextBounds(aContext.accessibleForBounds,
                                                   aContext.startOffset,
                                                   aContext.endOffset);
 
       return {
         type: this.type,
         details: {
           eventType: "vc-change",
-          bounds: bounds,
+          bounds,
           padding: this.BORDER_PADDING
         }
       };
     } catch (e) {
       Logger.logException(e, "Failed to get bounds");
       return null;
     }
   };
@@ -292,17 +292,17 @@ AndroidPresenter.prototype.pivotChanged 
       androidEvents.push({eventType: (isExploreByTouch) ?
                            this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
                          text: Utils.localize(UtteranceGenerator.genForContext(
                            aContext)),
                          bounds: aContext.bounds,
                          clickable: aContext.accessible.actionCount > 0,
                          checkable: state.contains(States.CHECKABLE),
                          checked: state.contains(States.CHECKED),
-                         brailleOutput: brailleOutput});
+                         brailleOutput});
     }
 
 
     return {
       type: this.type,
       details: androidEvents
     };
   };
@@ -318,17 +318,17 @@ AndroidPresenter.prototype.actionInvoked
       text = Utils.localize(UtteranceGenerator.genForAction(aObject,
         aActionName));
     }
 
     return {
       type: this.type,
       details: [{
         eventType: this.ANDROID_VIEW_CLICKED,
-        text: text,
+        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.
@@ -377,17 +377,17 @@ AndroidPresenter.prototype.textSelection
         aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput).details;
 
       androidEvents.push({
         eventType: this.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
         text: [aText],
         fromIndex: aStart,
         toIndex: aEnd,
         itemCount: aText.length,
-        brailleOutput: brailleOutput
+        brailleOutput
       });
     }
 
     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,
--- a/accessible/tests/mochitest/.eslintrc.js
+++ b/accessible/tests/mochitest/.eslintrc.js
@@ -6,19 +6,12 @@ module.exports = {
   ],
   "rules": {
     "mozilla/no-cpows-in-tests": "error",
     "mozilla/reject-importGlobalProperties": "error",
 
     // XXX These are rules that are enabled in the recommended configuration, but
     // disabled here due to failures when initially implemented. They should be
     // removed (and hence enabled) at some stage.
-    "comma-spacing": "off",
-    "no-cond-assign": "off",
-    "no-lonely-if": "off",
     "no-nested-ternary": "off",
-    "no-new-object": "off",
-    "no-redeclare": "off",
-    "no-shadow": "off",
     "no-undef": "off",
-    "space-unary-ops": "off",
   }
 };
--- a/accessible/tests/mochitest/actions/test_link.html
+++ b/accessible/tests/mochitest/actions/test_link.html
@@ -19,17 +19,17 @@
   <script type="application/javascript">
     function getAnchorTargetDocumentAcc() {
       var thisTabDocAcc = getTabDocAccessible();
       var thisDocTabPanelAcc = thisTabDocAcc.parent.parent;
       var tabPanelsAcc = thisDocTabPanelAcc.parent;
       var newDocTabPanelAcc = tabPanelsAcc.firstChild;
       var nextAcc = newDocTabPanelAcc;
 
-      while (nextAcc = nextAcc.nextSibling) {
+      while ((nextAcc = nextAcc.nextSibling)) {
         // Find the last accessible for a browser with about:mozilla loaded.
         if (nextAcc.firstChild.DOMNode.currentURI.spec == "about:mozilla") {
           newDocTabPanelAcc = nextAcc;
         }
       }
 
       return newDocTabPanelAcc.firstChild.firstChild;
     }
--- a/accessible/tests/mochitest/aom/test_general.html
+++ b/accessible/tests/mochitest/aom/test_general.html
@@ -67,17 +67,17 @@
         states = [
           "readonly", "busy", "focusable", "opaque", "stale", "enabled", "sensitive"
         ];
         break;
       default:
         ok(false, "Unexpected amount of states");
     }
     if (states) {
-      for (var i = 0; i < states.length; i++) {
+      for (let i = 0; i < states.length; i++) {
         is(anode.states[i], states[i], `${states[i]} state is expected at ${i}th index`);
       }
     }
 
     ok(anode.is("document", "focusable"),
        "correct role and state on an accessible node");
 
     is(anode.get("explicit-name"), "true",
@@ -91,17 +91,17 @@
       attrs = [
         "margin-left", "text-align", "text-indent", "margin-right",
         "tag", "margin-top", "margin-bottom", "display",
         "explicit-name"
       ];
     }
 
     is(anode.attributes.length, attrs.length, "correct number of attributes");
-    for (var i = 0; i < attrs.length; i++) {
+    for (let i = 0; i < attrs.length; i++) {
       ok(attrs.indexOf(anode.attributes[i]) >= 0,
          `${anode.attributes[i]} attribute is expected and found`);
     }
 
     finish();
   }
   </script>
 </head>
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -75,28 +75,28 @@ function testGroupAttrs(aAccOrElmOrID, a
   acc.groupPosition(levelObj, setSizeObj, posInSetObj);
 
   if (aPosInSet && aSetSize) {
     is(posInSetObj.value, aPosInSet,
        "Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
     is(setSizeObj.value, aSetSize,
        "Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
 
-    var attrs = {
+    let attrs = {
       "posinset": String(aPosInSet),
       "setsize": String(aSetSize)
     };
     testAttrs(aAccOrElmOrID, attrs, true);
   }
 
   if (aLevel) {
     is(levelObj.value, aLevel,
        "Wrong group level for " + prettyName(aAccOrElmOrID));
 
-    var attrs = { "level": String(aLevel) };
+    let attrs = { "level": String(aLevel) };
     testAttrs(aAccOrElmOrID, attrs, true);
   }
 }
 
 // //////////////////////////////////////////////////////////////////////////////
 // Text attributes.
 
 /**
@@ -138,20 +138,20 @@ function testTextAttrs(aID, aOffset, aAt
 
   is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
   is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
 
   compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
 
   // include attributes exposed on hyper text accessible
   var expectedAttrs = {};
-  for (var name in aAttrs)
+  for (let name in aAttrs)
     expectedAttrs[name] = aAttrs[name];
 
-  for (var name in aDefAttrs) {
+  for (let name in aDefAttrs) {
     if (!(name in expectedAttrs))
       expectedAttrs[name] = aDefAttrs[name];
   }
 
   attrs = getTextAttributes(aID, accessible, true, aOffset,
                             startOffset, endOffset);
 
   if (!attrs)
@@ -194,17 +194,17 @@ function testDefaultTextAttrs(aID, aDefA
  * Test text attributes for wrong offset.
  */
 function testTextAttrsWrongOffset(aID, aOffset) {
   var res = false;
   try {
   var s = {}, e = {};
   var acc = getAccessible(ID, [nsIAccessibleText]);
     acc.getTextAttributes(false, 157, s, e);
-  } catch (e) {
+  } catch (ex) {
     res = true;
   }
 
   ok(res,
      "text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID));
 }
 
 const kNormalFontWeight =
@@ -316,17 +316,17 @@ function testAttrsInternal(aAccOrElmOrID
   compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs);
 }
 
 function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
                       aAbsentAttrs) {
   // Check if all obtained attributes are expected and have expected value.
   var enumerate = aAttrs.enumerate();
   while (enumerate.hasMoreElements()) {
-    var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
+    let prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
 
     if (!(prop.key in aExpectedAttrs)) {
       if (!aSkipUnexpectedAttrs)
         ok(false, "Unexpected attribute '" + prop.key + "' having '" +
            prop.value + "'" + aErrorMsg);
     } else {
       var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg;
       var expectedValue = aExpectedAttrs[prop.key];
@@ -334,35 +334,35 @@ function compareAttrs(aErrorMsg, aAttrs,
       if (typeof expectedValue == "function")
         ok(expectedValue(prop.value), msg);
       else
         is(prop.value, expectedValue, msg);
     }
   }
 
   // Check if all expected attributes are presented.
-  for (var name in aExpectedAttrs) {
+  for (let name in aExpectedAttrs) {
     var value = "";
     try {
       value = aAttrs.getStringProperty(name);
     } catch (e) { }
 
     if (!value)
       ok(false,
          "There is no expected attribute '" + name + "' " + aErrorMsg);
   }
 
   // Check if all unexpected attributes are absent.
   if (aAbsentAttrs) {
     for (var name in aAbsentAttrs) {
       var wasFound = false;
 
-      var enumerate = aAttrs.enumerate();
+      enumerate = aAttrs.enumerate();
       while (enumerate.hasMoreElements()) {
-        var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
+        let prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
         if (prop.key == name)
           wasFound = true;
       }
     }
 
     ok(!wasFound,
        "There is an unexpected attribute '" + name + "' " + aErrorMsg);
   }
--- a/accessible/tests/mochitest/autocomplete.js
+++ b/accessible/tests/mochitest/autocomplete.js
@@ -71,17 +71,17 @@ function ResultsHeap(aValues, aComments)
 
 ResultsHeap.prototype =
 {
   constructor: ResultsHeap,
 
   /**
    * Return AutoCompleteResult for the given search string.
    */
-  getAutoCompleteResultFor: function(aSearchString) {
+  getAutoCompleteResultFor(aSearchString) {
     var values = [], comments = [];
     for (var idx = 0; idx < this.values.length; idx++) {
       if (this.values[idx].indexOf(aSearchString) != -1) {
         values.push(this.values[idx]);
         comments.push(this.comments[idx]);
       }
     }
     return new AutoCompleteResult(values, comments);
@@ -100,36 +100,35 @@ function AutoCompleteSearch(aName, aAllR
   this.allResults = aAllResults;
 }
 
 AutoCompleteSearch.prototype =
 {
   constructor: AutoCompleteSearch,
 
   // nsIAutoCompleteSearch implementation
-  startSearch: function(aSearchString, aSearchParam, aPreviousResult,
-                        aListener) {
+  startSearch(aSearchString, aSearchParam, aPreviousResult, aListener) {
     var result = this.allResults.getAutoCompleteResultFor(aSearchString);
     aListener.onSearchResult(this, result);
   },
 
-  stopSearch: function() {},
+  stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface: function(iid) {
+  QueryInterface(iid) {
     if (iid.equals(nsISupports) ||
         iid.equals(nsIFactory) ||
         iid.equals(nsIAutoCompleteSearch))
       return this;
 
     throw Components.results.NS_ERROR_NO_INTERFACE;
   },
 
   // nsIFactory implementation
-  createInstance: function(outer, iid) {
+  createInstance(outer, iid) {
     return this.QueryInterface(iid);
   },
 
   // Search name. Used by AutoCompleteController.
   name: null,
 
   // Results heap.
   allResults: null
@@ -157,44 +156,44 @@ AutoCompleteResult.prototype =
   searchResult: null,
 
   defaultIndex: 0,
 
   get matchCount() {
     return this.values.length;
   },
 
-  getValueAt: function(aIndex) {
+  getValueAt(aIndex) {
     return this.values[aIndex];
   },
 
-  getLabelAt: function(aIndex) {
+  getLabelAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
-  getCommentAt: function(aIndex) {
+  getCommentAt(aIndex) {
     return this.comments[aIndex];
   },
 
-  getStyleAt: function(aIndex) {
+  getStyleAt(aIndex) {
     return null;
   },
 
-  getImageAt: function(aIndex) {
+  getImageAt(aIndex) {
     return "";
   },
 
-  getFinalCompleteValueAt: function(aIndex) {
+  getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
-  removeValueAt: function(aRowIndex, aRemoveFromDb) {},
+  removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface: function(iid) {
+  QueryInterface(iid) {
     if (iid.equals(nsISupports) ||
         iid.equals(nsIAutoCompleteResult))
       return this;
 
     throw Components.results.NS_ERROR_NO_INTERFACE;
   },
 
   // Data
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -419,17 +419,17 @@ function testAccessibleTree(aAccOrElmOrI
 
     case "absentAttributes":
       testAbsentAttrs(acc, accTree[prop]);
       break;
 
     case "interfaces": {
       var ifaces = (accTree[prop] instanceof Array) ?
         accTree[prop] : [ accTree[prop] ];
-      for (var i = 0; i < ifaces.length; i++) {
+      for (let i = 0; i < ifaces.length; i++) {
         ok((acc instanceof ifaces[i]),
            "No " + ifaces[i] + " interface on " + prettyName(acc));
       }
       break;
     }
 
     case "relations": {
       for (var rel in accTree[prop])
@@ -452,26 +452,26 @@ function testAccessibleTree(aAccOrElmOrI
 
     case "tagName":
       is(accTree[prop], acc.DOMNode.tagName, msg);
       break;
 
     case "textAttrs": {
       var prevOffset = -1;
       for (var offset in accTree[prop]) {
-        if (prevOffset != - 1) {
-          var attrs = accTree[prop][prevOffset];
+        if (prevOffset != -1) {
+          let attrs = accTree[prop][prevOffset];
           testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, +offset, true);
         }
         prevOffset = +offset;
       }
 
       if (prevOffset != -1) {
         var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount;
-        var attrs = accTree[prop][prevOffset];
+        let attrs = accTree[prop][prevOffset];
         testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true);
       }
 
       break;
     }
 
     default:
       if (prop.indexOf("todo_") == 0)
@@ -482,17 +482,17 @@ function testAccessibleTree(aAccOrElmOrI
   }
 
   // Test children.
   if ("children" in accTree && accTree.children instanceof Array) {
     var children = acc.children;
     var childCount = children.length;
 
     if (accTree.children.length != childCount) {
-      for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) {
+      for (let i = 0; i < Math.max(accTree.children.length, childCount); i++) {
         var accChild = null, testChild = null;
         try {
           testChild = accTree.children[i];
           accChild = children.queryElementAt(i, nsIAccessible);
 
           if (!testChild) {
             ok(false, prettyName(acc) + " has an extra child at index " + i +
               " : " + prettyName(accChild));
@@ -511,18 +511,18 @@ function testAccessibleTree(aAccOrElmOrI
         } catch (e) {
           ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
              " : " + prettyName(testChild) + ", original tested: " +
              prettyName(aAccOrElmOrID) + ", " + e);
         }
       }
     } else {
       if (aFlags & kSkipTreeFullCheck) {
-        for (var i = 0; i < childCount; i++) {
-          var child = children.queryElementAt(i, nsIAccessible);
+        for (let i = 0; i < childCount; i++) {
+          let child = children.queryElementAt(i, nsIAccessible);
           testAccessibleTree(child, accTree.children[i], aFlags);
         }
         return;
       }
 
       // nsIAccessible::firstChild
       var expectedFirstChild = childCount > 0 ?
         children.queryElementAt(0, nsIAccessible) : null;
@@ -535,17 +535,17 @@ function testAccessibleTree(aAccOrElmOrI
       var expectedLastChild = childCount > 0 ?
         children.queryElementAt(childCount - 1, nsIAccessible) : null;
       var lastChild = null;
       try { lastChild = acc.lastChild; } catch (e) {}
       is(lastChild, expectedLastChild,
          "Wrong last child of " + prettyName(acc));
 
       for (var i = 0; i < childCount; i++) {
-        var child = children.queryElementAt(i, nsIAccessible);
+        let child = children.queryElementAt(i, nsIAccessible);
 
         // nsIAccessible::parent
         var parent = null;
         try { parent = child.parent; } catch (e) {}
         is(parent, acc, "Wrong parent of " + prettyName(child));
 
         // nsIAccessible::indexInParent
         var indexInParent = -1;
@@ -719,18 +719,18 @@ function getTextFromClipboard() {
     createInstance(Components.interfaces.nsITransferable);
   trans.init(getLoadContext());
   if (!trans)
     return "";
 
   trans.addDataFlavor("text/unicode");
   clip.getData(trans, clip.kGlobalClipboard);
 
-  var str = new Object();
-  var strLength = new Object();
+  var str = {};
+  var strLength = {};
   trans.getTransferData("text/unicode", str, strLength);
 
   if (str)
     str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
   if (str)
     return str.data.substring(0, strLength.value / 2);
 
   return "";
@@ -761,30 +761,30 @@ function getAccessibleDOMNodeID(accessib
   } catch (e) { /* This will fail if accessible is not a proxy. */ }
 }
 
 /**
  * Return pretty name for identifier, it may be ID, DOM node or accessible.
  */
 function prettyName(aIdentifier) {
   if (aIdentifier instanceof Array) {
-    var msg = "";
+    let msg = "";
     for (var idx = 0; idx < aIdentifier.length; idx++) {
       if (msg != "")
         msg += ", ";
 
       msg += prettyName(aIdentifier[idx]);
     }
     return msg;
   }
 
   if (aIdentifier instanceof nsIAccessible) {
     var acc = getAccessible(aIdentifier);
     var domID = getAccessibleDOMNodeID(acc);
-    var msg = "[";
+    let msg = "[";
     try {
       if (Services.appinfo.browserTabsRemoteAutostart) {
         if (domID) {
           msg += `DOM node id: ${domID}, `;
         }
       } else {
         msg += `${getNodePrettyName(acc.DOMNode)}, `;
       }
--- a/accessible/tests/mochitest/editabletext/editabletext.js
+++ b/accessible/tests/mochitest/editabletext/editabletext.js
@@ -57,74 +57,74 @@ function editableTextTest(aID) {
       dump(`\nsetTextContents '${aValue}'\n`);
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.setTextContents(aValue);
     }
 
     aSkipStartOffset = aSkipStartOffset || 0;
     var insertTripple = aValue ?
       [ aSkipStartOffset, aSkipStartOffset + aValue.length, aValue ] : null;
-    var oldValue = getValue(aID);
+    var oldValue = getValue();
     var removeTripple = oldValue ?
       [ aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue ] : null;
 
-    this.generateTest(aID, removeTripple, insertTripple, setTextContentsInvoke,
-                      getValueChecker(aID, aValue), testID);
+    this.generateTest(removeTripple, insertTripple, setTextContentsInvoke,
+                      getValueChecker(aValue), testID);
   };
 
   /**
    * insertText test.
    */
   this.insertText = function insertText(aStr, aPos, aResStr, aResPos) {
     var testID = "insertText '" + aStr + "' at " + aPos + " for " +
       prettyName(aID);
 
     function insertTextInvoke() {
       dump(`\ninsertText '${aStr}' at ${aPos} pos\n`);
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.insertText(aStr, aPos);
     }
 
     var resPos = (aResPos != undefined) ? aResPos : aPos;
-    this.generateTest(aID, null, [resPos, resPos + aStr.length, aStr],
-                      insertTextInvoke, getValueChecker(aID, aResStr), testID);
+    this.generateTest(null, [resPos, resPos + aStr.length, aStr],
+                      insertTextInvoke, getValueChecker(aResStr), testID);
   };
 
   /**
    * copyText test.
    */
   this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) {
     var testID = "copyText from " + aStartPos + " to " + aEndPos + " for " +
       prettyName(aID);
 
     function copyTextInvoke() {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.copyText(aStartPos, aEndPos);
     }
 
-    this.generateTest(aID, null, null, copyTextInvoke,
-                      getClipboardChecker(aID, aClipboardStr), testID);
+    this.generateTest(null, null, copyTextInvoke,
+                      getClipboardChecker(aClipboardStr), testID);
   };
 
   /**
    * copyText and pasteText test.
    */
   this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos,
                                                 aPos, aResStr) {
     var testID = "copyText from " + aStartPos + " to " + aEndPos +
       "and pasteText at " + aPos + " for " + prettyName(aID);
 
     function copyNPasteTextInvoke() {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.copyText(aStartPos, aEndPos);
       acc.pasteText(aPos);
     }
 
-    this.generateTest(aID, null, [aStartPos, aEndPos, getTextFromClipboard],
-                      copyNPasteTextInvoke, getValueChecker(aID, aResStr), testID);
+    this.generateTest(null, [aStartPos, aEndPos, getTextFromClipboard],
+                      copyNPasteTextInvoke, getValueChecker(aResStr), testID);
   };
 
   /**
    * cutText test.
    */
   this.cutText = function cutText(aStartPos, aEndPos, aResStr,
                                   aResStartPos, aResEndPos) {
     var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " +
@@ -132,101 +132,101 @@ function editableTextTest(aID) {
 
     function cutTextInvoke() {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.cutText(aStartPos, aEndPos);
     }
 
     var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos;
     var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos;
-    this.generateTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null,
-                      cutTextInvoke, getValueChecker(aID, aResStr), testID);
+    this.generateTest([resStartPos, resEndPos, getTextFromClipboard], null,
+                      cutTextInvoke, getValueChecker(aResStr), testID);
   };
 
   /**
    * cutText and pasteText test.
    */
   this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos,
                                                aPos, aResStr) {
     var testID = "cutText from " + aStartPos + " to " + aEndPos +
       " and pasteText at " + aPos + " for " + prettyName(aID);
 
     function cutNPasteTextInvoke() {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.cutText(aStartPos, aEndPos);
       acc.pasteText(aPos);
     }
 
-    this.generateTest(aID, [aStartPos, aEndPos, getTextFromClipboard],
+    this.generateTest([aStartPos, aEndPos, getTextFromClipboard],
                       [aPos, -1, getTextFromClipboard],
-                      cutNPasteTextInvoke, getValueChecker(aID, aResStr),
+                      cutNPasteTextInvoke, getValueChecker(aResStr),
                       testID);
   };
 
   /**
    * pasteText test.
    */
   this.pasteText = function pasteText(aPos, aResStr) {
     var testID = "pasteText at " + aPos + " for " + prettyName(aID);
 
     function pasteTextInvoke() {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.pasteText(aPos);
     }
 
-    this.generateTest(aID, null, [aPos, -1, getTextFromClipboard],
-                      pasteTextInvoke, getValueChecker(aID, aResStr), testID);
+    this.generateTest(null, [aPos, -1, getTextFromClipboard],
+                      pasteTextInvoke, getValueChecker(aResStr), testID);
   };
 
   /**
    * deleteText test.
    */
   this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) {
     var testID = "deleteText from " + aStartPos + " to " + aEndPos +
       " for " + prettyName(aID);
 
-    var oldValue = getValue(aID).substring(aStartPos, aEndPos);
+    var oldValue = getValue().substring(aStartPos, aEndPos);
     var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null;
 
     function deleteTextInvoke() {
       var acc = getAccessible(aID, [nsIAccessibleEditableText]);
       acc.deleteText(aStartPos, aEndPos);
     }
 
-    this.generateTest(aID, removeTripple, null, deleteTextInvoke,
-                      getValueChecker(aID, aResStr), testID);
+    this.generateTest(removeTripple, null, deleteTextInvoke,
+                      getValueChecker(aResStr), testID);
   };
 
   // ////////////////////////////////////////////////////////////////////////////
   // Implementation details.
 
-  function getValue(aID) {
+  function getValue() {
     var elm = getNode(aID);
     if (elm instanceof Components.interfaces.nsIDOMNSEditableElement)
       return elm.value;
 
     if (elm instanceof Components.interfaces.nsIDOMHTMLDocument)
       return elm.body.textContent;
 
     return elm.textContent;
   }
 
   /**
    * Common checkers.
    */
-  function getValueChecker(aID, aValue) {
+  function getValueChecker(aValue) {
     var checker = {
       check: function valueChecker_check() {
-        is(getValue(aID), aValue, "Wrong value " + aValue);
+        is(getValue(), aValue, "Wrong value " + aValue);
       }
     };
     return checker;
   }
 
-  function getClipboardChecker(aID, aText) {
+  function getClipboardChecker(aText) {
     var checker = {
       check: function clipboardChecker_check() {
         is(getTextFromClipboard(), aText, "Wrong text in clipboard.");
       }
     };
     return checker;
   }
 
@@ -237,41 +237,41 @@ function editableTextTest(aID) {
     var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1];
     if (data)
       data.func.apply(this, data.funcArgs);
   };
 
   /**
    * Used to generate an invoker object for the sheduled test.
    */
-  this.generateTest = function generateTest(aID, aRemoveTriple, aInsertTriple,
+  this.generateTest = function generateTest(aRemoveTriple, aInsertTriple,
                                             aInvokeFunc, aChecker, aInvokerID) {
     var et = this;
     var invoker = {
       eventSeq: [],
 
       invoke: aInvokeFunc,
       finalCheck: function finalCheck() {
         // dumpTree(aID, `'${aID}' tree:`);
 
         aChecker.check();
         et.unwrapNextTest(); // replace dummy invoker on real invoker object.
       },
       getID: function getID() { return aInvokerID; }
     };
 
     if (aRemoveTriple) {
-      var checker = new textChangeChecker(aID, aRemoveTriple[0],
+      let checker = new textChangeChecker(aID, aRemoveTriple[0],
                                           aRemoveTriple[1], aRemoveTriple[2],
                                           false);
       invoker.eventSeq.push(checker);
     }
 
     if (aInsertTriple) {
-      var checker = new textChangeChecker(aID, aInsertTriple[0],
+      let checker = new textChangeChecker(aID, aInsertTriple[0],
                                           aInsertTriple[1], aInsertTriple[2],
                                           true);
       invoker.eventSeq.push(checker);
     }
 
     // Claim that we don't want to fail when no events are expected.
     if (!aRemoveTriple && !aInsertTriple)
       invoker.noEventsOnAction = true;
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1,8 +1,11 @@
+// XXX Bug 1425371 - enable no-redeclare and fix the issues with the tests.
+/* eslint-disable no-redeclare */
+
 // //////////////////////////////////////////////////////////////////////////////
 // Constants
 
 const EVENT_ALERT = nsIAccessibleEvent.EVENT_ALERT;
 const EVENT_DESCRIPTION_CHANGE = nsIAccessibleEvent.EVENT_DESCRIPTION_CHANGE;
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
 const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
 const EVENT_DOCUMENT_LOAD_STOPPED = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED;
@@ -331,22 +334,20 @@ function eventQueue(aEventType) {
                 var checker = eventSeq[idx];
 
                 var typeStr = eventQueue.getEventTypeAsString(checker);
                 var msg = "Test with ID = '" + this.getEventID(checker) +
                   "' succeed. ";
 
                 if (checker.unexpected) {
                   ok(true, msg + `There's no unexpected '${typeStr}' event.`);
+                } else if (checker.todo) {
+                  todo(false, `Todo event '${typeStr}' was caught`);
                 } else {
-                  if (checker.todo) {
-                    todo(false, `Todo event '${typeStr}' was caught`);
-                  } else {
-                    ok(true, `${msg} Event '${typeStr}' was handled.`);
-                  }
+                  ok(true, `${msg} Event '${typeStr}' was handled.`);
                 }
               }
             }
           }
         }
 
         // We don't have completely matched scenario. Report each failure/success
         // for every scenario.
@@ -1996,16 +1997,17 @@ var gA11yEventObserver =
 function listenA11yEvents(aStartToListen) {
   if (aStartToListen) {
     // Add observer when adding the first applicant only.
     if (!(gA11yEventApplicantsCount++))
       Services.obs.addObserver(gA11yEventObserver, "accessible-event");
   } else {
     // Remove observer when there are no more applicants only.
     // '< 0' case should not happen, but just in case: removeObserver() will throw.
+    // eslint-disable-next-line no-lonely-if
     if (--gA11yEventApplicantsCount <= 0)
       Services.obs.removeObserver(gA11yEventObserver, "accessible-event");
   }
 }
 
 function addA11yEventListener(aEventType, aEventHandler) {
   if (!(aEventType in gA11yEventListeners))
     gA11yEventListeners[aEventType] = [];
@@ -2115,17 +2117,17 @@ var gLogger =
       Services.console.logStringMessage("events: " + aMsg);
   },
 
   /**
    * Return true if logging feature is enabled.
    */
   hasFeature: function logger_hasFeature(aFeature) {
     var startIdx = gA11yEventDumpFeature.indexOf(aFeature);
-    if (startIdx == - 1)
+    if (startIdx == -1)
       return false;
 
     var endIdx = startIdx + aFeature.length;
     return endIdx == gA11yEventDumpFeature.length ||
       gA11yEventDumpFeature[endIdx] == ";";
   }
 };
 
--- a/accessible/tests/mochitest/events/test_aria_objattr.html
+++ b/accessible/tests/mochitest/events/test_aria_objattr.html
@@ -38,17 +38,17 @@
         return aAttr + " for " + aID + " " + aValue;
       };
     }
 
     function updateARIAHidden(aID, aIsDefined, aChildId) {
       this.__proto__ = new updateAttribute(aID, "aria-hidden",
                                            aIsDefined ? "true" : "false");
 
-      this.finalCheck = function updateARIAHidden() {
+      this.finalCheck = function updateARIAHidden_finalCheck() {
         if (aIsDefined) {
           testAttrs(aID, {"hidden": "true"}, true);
           testAttrs(aChildId, {"hidden": "true"}, true);
         } else {
           testAbsentAttrs(aID, { "hidden": "true"});
           testAbsentAttrs(aChildId, { "hidden": "true"});
         }
       };
--- a/accessible/tests/mochitest/events/test_attrs.html
+++ b/accessible/tests/mochitest/events/test_attrs.html
@@ -44,22 +44,22 @@
 
     // gA11yEventDumpID = "eventdump"; // debug stuff
     // gA11yEventDumpToConsole = true; // debug stuff
 
     function doTests() {
       gQueue = new eventQueue();
 
       var id = "textbox", noTargetId = "textarea";
-      var checker =
+      let checker =
         new eventFromInputChecker(EVENT_FOCUS, id, "false", noTargetId);
       gQueue.push(new synthFocus(id, checker));
 
       if (!MAC) { // Mac failure is bug 541093
-        var checker =
+        checker =
           new eventFromInputChecker(EVENT_TEXT_CARET_MOVED, id, "true", noTargetId);
         gQueue.push(new synthHomeKey(id, checker));
       }
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
--- a/accessible/tests/mochitest/events/test_dragndrop.html
+++ b/accessible/tests/mochitest/events/test_dragndrop.html
@@ -61,23 +61,23 @@
         return prettyName(aNodeOrID) + " aria-dropeffect changed";
       };
     }
 
     function doTests() {
       // Test aria attribute mutation events
       gQueue = new eventQueue(nsIAccessibleEvent.EVENT_OBJECT_ATTRIBUTE_CHANGED);
 
-      var id = "grabbable";
+      let id = "grabbable";
       gQueue.push(new changeGrabbed(id, "true"));
       gQueue.push(new changeGrabbed(id, "false"));
       todo(false, "uncomment this test when 472142 is fixed.");
       // gQueue.push(new changeGrabbed(id, "undefined"));
 
-      var id = "dropregion";
+      id = "dropregion";
       gQueue.push(new changeDropeffect(id, "copy"));
       gQueue.push(new changeDropeffect(id, "execute"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
--- a/accessible/tests/mochitest/events/test_flush.html
+++ b/accessible/tests/mochitest/events/test_flush.html
@@ -15,17 +15,17 @@
           src="../common.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
 
   <script type="application/javascript">
     SimpleTest.expectAssertions(0, 1);
 
     var gFocusHandler = {
-      handleEvent: function(aEvent) {
+      handleEvent(aEvent) {
         switch (this.count) {
           case 0:
             is(aEvent.DOMNode, getNode("input1"),
                "Focus event for input1 was expected!");
             getAccessible("input2").takeFocus();
             break;
 
           case 1:
--- a/accessible/tests/mochitest/events/test_focus_general.html
+++ b/accessible/tests/mochitest/events/test_focus_general.html
@@ -101,20 +101,19 @@
         gQueue.push(new toggleTopMenu(editableDoc, new topMenuChecker()));
         gQueue.push(new toggleTopMenu(editableDoc, new focusChecker(editableDoc)));
       }
       gQueue.push(new synthContextMenu(editableDoc, new contextMenuChecker()));
       gQueue.push(new synthDownKey(editableDoc, new focusContextMenuItemChecker()));
       gQueue.push(new synthEscapeKey(editableDoc, new focusChecker(editableDoc)));
       if (SEAMONKEY) {
         todo(false, "shift tab from editable document fails on (Windows) SeaMonkey! (Bug 718235)");
+      } else if (LINUX || MAC) {
+        todo(false, "shift tab from editable document fails on linux and Mac, bug 746519!");
       } else {
-      if (LINUX || MAC)
-        todo(false, "shift tab from editable document fails on linux and Mac, bug 746519!");
-      else
         gQueue.push(new synthShiftTab("link", new focusChecker("link")));
       } // ! SEAMONKEY
 
       gQueue.push(new synthFocus("a", new imageMapChecker("a")));
       gQueue.push(new synthFocus("b", new imageMapChecker("b")));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -66,17 +66,17 @@
        * Replace the default target currently registered for a given event type
        * with the nodes in the targets array.
        */
       this.setTargets = function mutateA11yTree_setTargets(aEventType, aTargets) {
         var targetIdx = this.setTarget(aEventType, aTargets[0]);
 
         var type = this.getA11yEventType(aEventType);
         for (var i = 1; i < aTargets.length; i++) {
-          var checker = new invokerChecker(type, aTargets[i]);
+          let checker = new invokerChecker(type, aTargets[i]);
           this.getEventSeq().splice(++targetIdx, 0, checker);
         }
       };
 
       // Implementation
       this.getA11yEventType = function mutateA11yTree_getA11yEventType(aEventType) {
         if (aEventType == kReorderEvent)
           return nsIAccessibleEvent.EVENT_REORDER;
@@ -88,29 +88,29 @@
           return nsIAccessibleEvent.EVENT_SHOW;
       };
 
       this.getEventSeq = function mutateA11yTree_getEventSeq() {
         return this.doNotExpectEvents ? this.unexpectedEventSeq : this.eventSeq;
       };
 
       if (aEventTypes & kHideEvent) {
-        var checker = new invokerChecker(this.getA11yEventType(kHideEvent),
+        let checker = new invokerChecker(this.getA11yEventType(kHideEvent),
                                          this.DOMNode);
         this.getEventSeq().push(checker);
       }
 
       if (aEventTypes & kShowEvent) {
-        var checker = new invokerChecker(this.getA11yEventType(kShowEvent),
+        let checker = new invokerChecker(this.getA11yEventType(kShowEvent),
                                          this.DOMNode);
         this.getEventSeq().push(checker);
       }
 
       if (aEventTypes & kReorderEvent) {
-        var checker = new invokerChecker(this.getA11yEventType(kReorderEvent),
+        let checker = new invokerChecker(this.getA11yEventType(kReorderEvent),
                                          this.DOMNode.parentNode);
         this.getEventSeq().push(checker);
       }
     }
 
     /**
      * Change CSS style for the given node.
      */
@@ -427,61 +427,61 @@
      */
     var gQueue = null;
 
     function doTests() {
       gQueue = new eventQueue();
 
       // Show/hide events by changing of display style of accessible DOM node
       // from 'inline' to 'none', 'none' to 'inline'.
-      var id = "link1";
+      let id = "link1";
       getAccessible(id); // ensure accessible is created
       gQueue.push(new changeStyle(id, "display", "none", kHideEvents));
       gQueue.push(new changeStyle(id, "display", "inline", kShowEvents));
 
       // Show/hide events by changing of visibility style of accessible DOM node
       // from 'visible' to 'hidden', 'hidden' to 'visible'.
-      var id = "link2";
+      id = "link2";
       getAccessible(id);
       gQueue.push(new changeStyle(id, "visibility", "hidden", kHideEvents));
       gQueue.push(new changeStyle(id, "visibility", "visible", kShowEvents));
 
       // Show/hide events by changing of display style of accessible DOM node
       // from 'inline' to 'block', 'block' to 'inline'.
-      var id = "link3";
+      id = "link3";
       getAccessible(id); // ensure accessible is created
       gQueue.push(new changeStyle(id, "display", "block", kHideAndShowEvents));
       gQueue.push(new changeStyle(id, "display", "inline", kHideAndShowEvents));
 
       // Show/hide events by changing of visibility style of accessible DOM node
       // from 'collapse' to 'visible', 'visible' to 'collapse'.
-      var id = "link4";
+      id = "link4";
       gQueue.push(new changeStyle(id, "visibility", "visible", kShowEvents));
       gQueue.push(new changeStyle(id, "visibility", "collapse", kHideEvents));
 
       // Show/hide events by adding new accessible DOM node and removing old one.
-      var id = "link5";
+      id = "link5";
       gQueue.push(new cloneAndAppendToDOM(id));
       gQueue.push(new removeFromDOM(id));
 
       // No show/hide events by adding new not accessible DOM node and removing
       // old one, no reorder event for their parent.
-      var id = "child1";
+      id = "child1";
       gQueue.push(new cloneAndAppendToDOM(id, kNoEvents));
       gQueue.push(new removeFromDOM(id, kNoEvents));
 
       // Show/hide events by adding new accessible DOM node and removing
       // old one, there is reorder event for their parent.
-      var id = "child2";
+      id = "child2";
       gQueue.push(new cloneAndAppendToDOM(id));
       gQueue.push(new removeFromDOM(id));
 
       // Show/hide events by adding new DOM node containing accessible DOM and
       // removing old one, there is reorder event for their parent.
-      var id = "child3";
+      id = "child3";
       gQueue.push(new cloneAndAppendToDOM(id, kShowEvents, getFirstChild,
                                           getParent));
 
       // Hide event for accessible child of unaccessible removed DOM node and
       // reorder event for its parent.
       gQueue.push(new removeFromDOM(id, kHideEvents,
                                     getNEnsureFirstChild, getParent));
 
--- a/accessible/tests/mochitest/events/test_statechange.html
+++ b/accessible/tests/mochitest/events/test_statechange.html
@@ -29,19 +29,19 @@
         // Note: this should fire an EVENT_STATE_CHANGE
         this.DOMNode.designMode = "on";
       };
 
       this.check = function editabledoc_check(aEvent) {
 
         testStates(aDocNode, 0, EXT_STATE_EDITABLE);
 
-        var event = null;
+        let event = null;
         try {
-          var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
+          event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
         } catch (e) {
           ok(false, "State change event was expected");
         }
 
         if (!event) { return; }
 
         ok(event.isExtraState, "Extra state change was expected");
         is(event.state, EXT_STATE_EDITABLE, "Wrong state of statechange event");
--- a/accessible/tests/mochitest/events/test_text.html
+++ b/accessible/tests/mochitest/events/test_text.html
@@ -59,35 +59,35 @@
      * Insert inaccessible child node containing accessibles.
      */
     function insertChildSpan(aID, aInsertAllTogether) {
       this.__proto__ = new textInsertInvoker(aID, 0, 5, "33322");
 
       this.invoke = function insertChildSpan_invoke() {
         // <span><span>333</span><span>22</span></span>
         if (aInsertAllTogether) {
-          var topSpan = document.createElement("span");
-          var fSpan = document.createElement("span");
+          let topSpan = document.createElement("span");
+          let fSpan = document.createElement("span");
           fSpan.textContent = "333";
           topSpan.appendChild(fSpan);
-          var sSpan = document.createElement("span");
+          let sSpan = document.createElement("span");
           sSpan.textContent = "22";
           topSpan.appendChild(sSpan);
 
           this.DOMNode.insertBefore(topSpan, this.DOMNode.childNodes[0]);
 
         } else {
-          var topSpan = document.createElement("span");
+          let topSpan = document.createElement("span");
           this.DOMNode.insertBefore(topSpan, this.DOMNode.childNodes[0]);
 
-          var fSpan = document.createElement("span");
+          let fSpan = document.createElement("span");
           fSpan.textContent = "333";
           topSpan.appendChild(fSpan);
 
-          var sSpan = document.createElement("span");
+          let sSpan = document.createElement("span");
           sSpan.textContent = "22";
           topSpan.appendChild(sSpan);
         }
       };
 
       this.getID = function insertChildSpan_getID() {
        return "Insert inaccessible span containing accessibles" +
           prettyName(aID);
--- a/accessible/tests/mochitest/grid.js
+++ b/accessible/tests/mochitest/grid.js
@@ -66,59 +66,60 @@ function grid(aTableIdentifier) {
   };
 
   this.handleKeyEvent = function handleKeyEvent(aEvent) {
     if (aEvent.target.localName != "td")
       return;
 
     var cell = aEvent.target;
     switch (aEvent.keyCode) {
-      case nsIDOMKeyEvent.DOM_VK_UP:
-        var colsCount = this.getColsCount();
-        var idx = this.getIndexByCell(cell);
+      case nsIDOMKeyEvent.DOM_VK_UP: {
+        let colsCount = this.getColsCount();
+        let idx = this.getIndexByCell(cell);
         var upidx = idx - colsCount;
         if (upidx >= 0) {
           cell.removeAttribute("tabindex");
           var upcell = this.getCellAtIndex(upidx);
           upcell.setAttribute("tabindex", "0");
           upcell.focus();
         }
         break;
-
-      case nsIDOMKeyEvent.DOM_VK_DOWN:
-        var colsCount = this.getColsCount();
-        var idx = this.getIndexByCell(cell);
+      }
+      case nsIDOMKeyEvent.DOM_VK_DOWN: {
+        let colsCount = this.getColsCount();
+        let idx = this.getIndexByCell(cell);
         var downidx = idx + colsCount;
         if (downidx <= this.getMaxIndex()) {
           cell.removeAttribute("tabindex");
           var downcell = this.getCellAtIndex(downidx);
           downcell.setAttribute("tabindex", "0");
           downcell.focus();
         }
         break;
-
-      case nsIDOMKeyEvent.DOM_VK_LEFT:
-        var idx = this.getIndexByCell(cell);
+      }
+      case nsIDOMKeyEvent.DOM_VK_LEFT: {
+        let idx = this.getIndexByCell(cell);
         if (idx > 0) {
           cell.removeAttribute("tabindex");
           var prevcell = this.getCellAtIndex(idx - 1);
           prevcell.setAttribute("tabindex", "0");
           prevcell.focus();
         }
         break;
-
-      case nsIDOMKeyEvent.DOM_VK_RIGHT:
-        var idx = this.getIndexByCell(cell);
+      }
+      case nsIDOMKeyEvent.DOM_VK_RIGHT: {
+        let idx = this.getIndexByCell(cell);
         if (idx < this.getMaxIndex()) {
           cell.removeAttribute("tabindex");
           var nextcell = this.getCellAtIndex(idx + 1);
           nextcell.setAttribute("tabindex", "0");
           nextcell.focus();
         }
         break;
+      }
     }
   };
 
   this.handleClickEvent = function handleClickEvent(aEvent) {
     if (aEvent.target.localName != "td")
       return;
 
     var curCell = this.getCurrentCell();
--- a/accessible/tests/mochitest/hittest/test_zoom_text.html
+++ b/accessible/tests/mochitest/hittest/test_zoom_text.html
@@ -14,24 +14,24 @@
           src="../role.js"></script>
   <script type="application/javascript"
           src="../layout.js"></script>
 
   <script type="application/javascript">
     function doTest() {
       var hyperText = getNode("paragraph");
       var textNode = hyperText.firstChild;
-      var [x, y, width, height] = getBounds(textNode);
+      let [x, y, width, height] = getBounds(textNode);
       testOffsetAtPoint(hyperText, x + width / 2, y + height / 2,
                         COORDTYPE_SCREEN_RELATIVE,
                         hyperText.textContent.length / 2);
 
       zoomDocument(document, 2.0);
 
-      var [x, y, width, height] = getBounds(textNode);
+      [x, y, width, height] = getBounds(textNode);
       testOffsetAtPoint(hyperText, x + width / 2, y + height / 2,
                         COORDTYPE_SCREEN_RELATIVE,
                         hyperText.textContent.length / 2);
 
       zoomDocument(document, 1.0);
 
       SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/hypertext/test_update.html
+++ b/accessible/tests/mochitest/hypertext/test_update.html
@@ -164,17 +164,17 @@
 
     // gA11yEventDumpToConsole = true; // debug stuff
 
     var gQueue = null;
     function doTest() {
       gQueue = new eventQueue();
       gQueue.push(new addLinks("p1"));
       gQueue.push(new updateText("p2"));
-      gQueue.push(new removeChild("div1","div2",
+      gQueue.push(new removeChild("div1", "div2",
                                   "hello my good friend", "hello friend"));
       gQueue.push(new removeFirstChild("c4"));
       gQueue.push(new removeLastChild("c5"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -183,17 +183,17 @@ function AccessFuContentTest(aFuncResult
   this.queue = aFuncResultPairs;
 }
 
 AccessFuContentTest.prototype = {
   expected: [],
   currentAction: null,
   actionNum: -1,
 
-  start: function(aFinishedCallback) {
+  start(aFinishedCallback) {
     Logger.logLevel = Logger.DEBUG;
     this.finishedCallback = aFinishedCallback;
     var self = this;
 
     // Get top content message manager, and set it up.
     this.mms = [Utils.getMessageManager(currentBrowser())];
     this.setupMessageManager(this.mms[0], function() {
       // Get child message managers and set them up
@@ -215,34 +215,34 @@ AccessFuContentTest.prototype = {
               self.pump();
             }
           });
         }
       }
     });
   },
 
-  finish: function() {
+  finish() {
     Logger.logLevel = Logger.INFO;
     for (var mm of this.mms) {
         mm.sendAsyncMessage("AccessFu:Stop");
         mm.removeMessageListener("AccessFu:Present", this);
         mm.removeMessageListener("AccessFu:Input", this);
         mm.removeMessageListener("AccessFu:CursorCleared", this);
         mm.removeMessageListener("AccessFu:Focused", this);
         mm.removeMessageListener("AccessFu:AriaHidden", this);
         mm.removeMessageListener("AccessFu:Ready", this);
         mm.removeMessageListener("AccessFu:ContentStarted", this);
       }
     if (this.finishedCallback) {
       this.finishedCallback();
     }
   },
 
-  setupMessageManager:  function(aMessageManager, aCallback) {
+  setupMessageManager(aMessageManager, aCallback) {
     function contentScript() {
       addMessageListener("AccessFuTest:Focus", function(aMessage) {
         var elem = content.document.querySelector(aMessage.json.selector);
         if (elem) {
           if (aMessage.json.blur) {
             elem.blur();
           } else {
             elem.focus();
@@ -266,17 +266,17 @@ AccessFuContentTest.prototype = {
     });
 
     aMessageManager.loadFrameScript(
       "chrome://global/content/accessibility/content-script.js", false);
     aMessageManager.loadFrameScript(
       "data:,(" + contentScript.toString() + ")();", false);
   },
 
-  pump: function() {
+  pump() {
     this.expected.shift();
     if (this.expected.length) {
       return;
     }
 
     var currentPair = this.queue.shift();
 
     if (currentPair) {
@@ -294,17 +294,17 @@ AccessFuContentTest.prototype = {
       if (!this.expected[0]) {
        this.pump();
      }
     } else {
       this.finish();
     }
   },
 
-  receiveMessage: function(aMessage) {
+  receiveMessage(aMessage) {
     var expected = this.expected[0];
 
     if (!expected) {
       return;
     }
 
     var actionsString = typeof this.currentAction === "function" ?
       this.currentAction.name + "()" : JSON.stringify(this.currentAction);
@@ -495,23 +495,21 @@ ExpectedMessage.prototype.lazyCompare = 
     var expected = aExpected[attr];
     var received = aReceived[attr];
     if (typeof expected === "object") {
       var [childMatches, childDelta] = this.lazyCompare(received, expected);
       if (!childMatches) {
         delta.push(attr + " [ " + childDelta + " ]");
         matches = false;
       }
-    } else {
-      if (received !== expected) {
-        delta.push(
-          attr + " [ expected " + JSON.stringify(expected) +
-          " got " + JSON.stringify(received) + " ]");
-        matches = false;
-      }
+    } else if (received !== expected) {
+      delta.push(
+        attr + " [ expected " + JSON.stringify(expected) +
+        " got " + JSON.stringify(received) + " ]");
+      matches = false;
     }
   }
 
   var msg = delta.length ? delta.join(" ") : "Structures lazily match";
   return [matches, msg + " -- " + aInfo];
 };
 
 ExpectedMessage.prototype.is = function(aReceived, aInfo) {
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -206,17 +206,17 @@
 
           // aria-hidden element that the virtual cursor is positioned on
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Traversal Rule test document", "Phone status bar"])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [doc.defaultView.ariaHideBack,
            new ExpectedCursorChange(
-            ["such app", "wow", {"string": "headingLevel","args": [1]}])],
+            ["such app", "wow", {"string": "headingLevel", "args": [1]}])],
           // Changing aria-hidden attribute twice and making sure that the event
           // is fired only once when the actual change happens.
           [doc.defaultView.ariaHideBack],
           [doc.defaultView.ariaShowBack],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.clearCursor, "AccessFu:CursorCleared"],
 
@@ -234,17 +234,17 @@
 
           // aria-hidden element and auto Move
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Traversal Rule test document", "Phone status bar"])],
           [doc.defaultView.ariaHideBack],
           [ContentMessages.focusSelector("button#back", false),
             // Must not speak Back button as it is aria-hidden
            new ExpectedCursorChange(
-             ["such app", "wow", {"string": "headingLevel","args": [1]}])],
+             ["such app", "wow", {"string": "headingLevel", "args": [1]}])],
           [doc.defaultView.ariaShowBack],
           [ContentMessages.focusSelector("button#back", true), null],
           [ContentMessages.clearCursor, "AccessFu:CursorCleared"],
 
           // Open dialog in outer doc, while cursor is also in outer doc
           [ContentMessages.simpleMoveLast,
            new ExpectedCursorChange(["Traversal Rule test document", "mover",
              "medium", {"string": "slider"}])],
--- a/accessible/tests/mochitest/jsat/test_content_text.html
+++ b/accessible/tests/mochitest/jsat/test_content_text.html
@@ -142,17 +142,17 @@
            new ExpectedCursorChange(
             ["So we don't get dessert?", {string: "label"}]),
            new ExpectedAnnouncement("navigating"),
            new ExpectedEditState({
             editing: false,
             multiline: false,
             atStart: true,
             atEnd: false
-           },{ focused: "html" })
+           }, { focused: "html" })
          ],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(
             [{ string: "entry" }],
             { focused: "html"})],
           [ContentMessages.activateCurrent(0),
            new ExpectedClickAction(),
            new ExpectedAnnouncement("editing"),
--- a/accessible/tests/mochitest/jsat/test_output_mathml.html
+++ b/accessible/tests/mochitest/jsat/test_output_mathml.html
@@ -14,162 +14,162 @@
           src="jsatcommon.js"></script>
   <script type="application/javascript">
 
     function doTest() {
       // Test the following accOrElmOrID.
       var tests = [{
           accOrElmOrID: "math-1",
           expectedUtterance: [
-            [{"string": "open-fence"},"(","x",",","y",{"string": "close-fence"},")"],
-            ["(",{"string": "open-fence"},"x",",","y",")",{"string": "close-fence"}]
+            [{"string": "open-fence"}, "(", "x", ",", "y", {"string": "close-fence"}, ")"],
+            ["(", {"string": "open-fence"}, "x", ",", "y", ")", {"string": "close-fence"}]
           ],
           expectedBraille: [
-            [{"string": "open-fenceAbbr"},"(","x",",","y",{"string": "close-fenceAbbr"},")"],
-            ["(",{"string": "open-fenceAbbr"},"x",",","y",")",{"string": "close-fenceAbbr"}]
+            [{"string": "open-fenceAbbr"}, "(", "x", ",", "y", {"string": "close-fenceAbbr"}, ")"],
+            ["(", {"string": "open-fenceAbbr"}, "x", ",", "y", ")", {"string": "close-fenceAbbr"}]
           ]
         }, {
           accOrElmOrID: "mfrac-1",
           expectedUtterance: [
-            [{"string": "mathmlfraction"},{"string": "numerator"},"a",{"string": "denominator"},"b"],
-            ["a",{"string": "numerator"},"b",{"string": "denominator"},{"string": "mathmlfraction"}]
+            [{"string": "mathmlfraction"}, {"string": "numerator"}, "a", {"string": "denominator"}, "b"],
+            ["a", {"string": "numerator"}, "b", {"string": "denominator"}, {"string": "mathmlfraction"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlfractionAbbr"},{"string": "numeratorAbbr"},"a",{"string": "denominatorAbbr"},"b"],
-            ["a",{"string": "numeratorAbbr"},"b",{"string": "denominatorAbbr"},{"string": "mathmlfractionAbbr"}]
+            [{"string": "mathmlfractionAbbr"}, {"string": "numeratorAbbr"}, "a", {"string": "denominatorAbbr"}, "b"],
+            ["a", {"string": "numeratorAbbr"}, "b", {"string": "denominatorAbbr"}, {"string": "mathmlfractionAbbr"}]
           ]
         }, {
           accOrElmOrID: "mfrac-2",
           expectedUtterance: [
-            [{"string": "mathmlfractionwithoutbar"},{"string": "numerator"},"a",{"string": "denominator"},"b"],
-            ["a",{"string": "numerator"},"b",{"string": "denominator"},{"string": "mathmlfractionwithoutbar"}]
+            [{"string": "mathmlfractionwithoutbar"}, {"string": "numerator"}, "a", {"string": "denominator"}, "b"],
+            ["a", {"string": "numerator"}, "b", {"string": "denominator"}, {"string": "mathmlfractionwithoutbar"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlfractionwithoutbarAbbr"},{"string": "numeratorAbbr"},"a",{"string": "denominatorAbbr"},"b"],
-            ["a",{"string": "numeratorAbbr"},"b",{"string": "denominatorAbbr"},{"string": "mathmlfractionwithoutbarAbbr"}]
+            [{"string": "mathmlfractionwithoutbarAbbr"}, {"string": "numeratorAbbr"}, "a", {"string": "denominatorAbbr"}, "b"],
+            ["a", {"string": "numeratorAbbr"}, "b", {"string": "denominatorAbbr"}, {"string": "mathmlfractionwithoutbarAbbr"}]
           ]
         }, {
           accOrElmOrID: "msub-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "subscript"},"b"],
-            ["a",{"string": "base"},"b",{"string": "subscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "subscript"}, "b"],
+            ["a", {"string": "base"}, "b", {"string": "subscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "subscriptAbbr"},"b"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "subscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "subscriptAbbr"}, "b"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "subscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "msup-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "superscript"},"b"],
-            ["a",{"string": "base"},"b",{"string": "superscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "superscript"}, "b"],
+            ["a", {"string": "base"}, "b", {"string": "superscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "superscriptAbbr"},"b"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "superscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "superscriptAbbr"}, "b"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "superscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "msubsup-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "subscript"},"b",{"string": "superscript"},"c"],
-            ["a",{"string": "base"},"b",{"string": "subscript"},"c",{"string": "superscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "subscript"}, "b", {"string": "superscript"}, "c"],
+            ["a", {"string": "base"}, "b", {"string": "subscript"}, "c", {"string": "superscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "subscriptAbbr"},"b",{"string": "superscriptAbbr"},"c"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "subscriptAbbr"},"c",{"string": "superscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "subscriptAbbr"}, "b", {"string": "superscriptAbbr"}, "c"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "subscriptAbbr"}, "c", {"string": "superscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "mmultiscripts-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "subscript"},"b",{"string": "superscript"},"c",{"string": "superscript"},"d",{"string": "presubscript"},"e",{"string": "presubscript"},"f",{"string": "presuperscript"},"g"],
-            ["a",{"string": "base"},"b",{"string": "subscript"},"c",{"string": "superscript"},"d",{"string": "superscript"},"e",{"string": "presubscript"},"f",{"string": "presubscript"},"g",{"string": "presuperscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "subscript"}, "b", {"string": "superscript"}, "c", {"string": "superscript"}, "d", {"string": "presubscript"}, "e", {"string": "presubscript"}, "f", {"string": "presuperscript"}, "g"],
+            ["a", {"string": "base"}, "b", {"string": "subscript"}, "c", {"string": "superscript"}, "d", {"string": "superscript"}, "e", {"string": "presubscript"}, "f", {"string": "presubscript"}, "g", {"string": "presuperscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "subscriptAbbr"},"b",{"string": "superscriptAbbr"},"c",{"string": "superscriptAbbr"},"d",{"string": "presubscriptAbbr"},"e",{"string": "presubscriptAbbr"},"f",{"string": "presuperscriptAbbr"},"g"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "subscriptAbbr"},"c",{"string": "superscriptAbbr"},"d",{"string": "superscriptAbbr"},"e",{"string": "presubscriptAbbr"},"f",{"string": "presubscriptAbbr"},"g",{"string": "presuperscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "subscriptAbbr"}, "b", {"string": "superscriptAbbr"}, "c", {"string": "superscriptAbbr"}, "d", {"string": "presubscriptAbbr"}, "e", {"string": "presubscriptAbbr"}, "f", {"string": "presuperscriptAbbr"}, "g"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "subscriptAbbr"}, "c", {"string": "superscriptAbbr"}, "d", {"string": "superscriptAbbr"}, "e", {"string": "presubscriptAbbr"}, "f", {"string": "presubscriptAbbr"}, "g", {"string": "presuperscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "munder-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "underscript"},"b"],
-            ["a",{"string": "base"},"b",{"string": "underscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "underscript"}, "b"],
+            ["a", {"string": "base"}, "b", {"string": "underscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "underscriptAbbr"},"b"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "underscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "underscriptAbbr"}, "b"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "underscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "mover-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "overscript"},"b"],
-            ["a",{"string": "base"},"b",{"string": "overscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "overscript"}, "b"],
+            ["a", {"string": "base"}, "b", {"string": "overscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "overscriptAbbr"},"b"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "overscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "overscriptAbbr"}, "b"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "overscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "munderover-1",
           expectedUtterance: [
-            [{"string": "mathmlscripted"},{"string": "base"},"a",{"string": "underscript"},"b",{"string": "overscript"},"c"],
-            ["a",{"string": "base"},"b",{"string": "underscript"},"c",{"string": "overscript"},{"string": "mathmlscripted"}]
+            [{"string": "mathmlscripted"}, {"string": "base"}, "a", {"string": "underscript"}, "b", {"string": "overscript"}, "c"],
+            ["a", {"string": "base"}, "b", {"string": "underscript"}, "c", {"string": "overscript"}, {"string": "mathmlscripted"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlscriptedAbbr"},{"string": "baseAbbr"},"a",{"string": "underscriptAbbr"},"b",{"string": "overscriptAbbr"},"c"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "underscriptAbbr"},"c",{"string": "overscriptAbbr"},{"string": "mathmlscriptedAbbr"}]
+            [{"string": "mathmlscriptedAbbr"}, {"string": "baseAbbr"}, "a", {"string": "underscriptAbbr"}, "b", {"string": "overscriptAbbr"}, "c"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "underscriptAbbr"}, "c", {"string": "overscriptAbbr"}, {"string": "mathmlscriptedAbbr"}]
           ]
         }, {
           accOrElmOrID: "mroot-1",
           expectedUtterance: [
-            [{"string": "mathmlroot"},{"string": "base"},"a",{"string": "root-index"},"b"],
-            ["a",{"string": "base"},"b",{"string": "root-index"},{"string": "mathmlroot"}]
+            [{"string": "mathmlroot"}, {"string": "base"}, "a", {"string": "root-index"}, "b"],
+            ["a", {"string": "base"}, "b", {"string": "root-index"}, {"string": "mathmlroot"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlrootAbbr"},{"string": "baseAbbr"},"a",{"string": "root-indexAbbr"},"b"],
-            ["a",{"string": "baseAbbr"},"b",{"string": "root-indexAbbr"},{"string": "mathmlrootAbbr"}]
+            [{"string": "mathmlrootAbbr"}, {"string": "baseAbbr"}, "a", {"string": "root-indexAbbr"}, "b"],
+            ["a", {"string": "baseAbbr"}, "b", {"string": "root-indexAbbr"}, {"string": "mathmlrootAbbr"}]
           ]
         }, {
           accOrElmOrID: "mtable-1",
           expectedUtterance: [
-            [{"string": "mathmltable"},{"string": "tblColumnInfo","count": 3},{"string": "tblRowInfo","count": 2},{"string": "columnInfo","args": [1]},{"string": "rowInfo","args": [1]},"a",{"string": "columnInfo","args": [2]},{"string": "rowInfo","args": [1]},"b",{"string": "columnInfo","args": [3]},{"string": "rowInfo","args": [1]},"c",{"string": "columnInfo","args": [1]},{"string": "rowInfo","args": [2]},"d",{"string": "columnInfo","args": [2]},{"string": "rowInfo","args": [2]},"e",{"string": "columnInfo","args": [3]},{"string": "rowInfo","args": [2]},"f"],
-            ["a",{"string": "columnInfo","args": [1]},{"string": "rowInfo","args": [1]},"b",{"string": "columnInfo","args": [2]},{"string": "rowInfo","args": [1]},"c",{"string": "columnInfo","args": [3]},{"string": "rowInfo","args": [1]},"d",{"string": "columnInfo","args": [1]},{"string": "rowInfo","args": [2]},"e",{"string": "columnInfo","args": [2]},{"string": "rowInfo","args": [2]},"f",{"string": "columnInfo","args": [3]},{"string": "rowInfo","args": [2]},{"string": "mathmltable"},{"string": "tblColumnInfo","count": 3},{"string": "tblRowInfo","count": 2}]
+            [{"string": "mathmltable"}, {"string": "tblColumnInfo", "count": 3}, {"string": "tblRowInfo", "count": 2}, {"string": "columnInfo", "args": [1]}, {"string": "rowInfo", "args": [1]}, "a", {"string": "columnInfo", "args": [2]}, {"string": "rowInfo", "args": [1]}, "b", {"string": "columnInfo", "args": [3]}, {"string": "rowInfo", "args": [1]}, "c", {"string": "columnInfo", "args": [1]}, {"string": "rowInfo", "args": [2]}, "d", {"string": "columnInfo", "args": [2]}, {"string": "rowInfo", "args": [2]}, "e", {"string": "columnInfo", "args": [3]}, {"string": "rowInfo", "args": [2]}, "f"],
+            ["a", {"string": "columnInfo", "args": [1]}, {"string": "rowInfo", "args": [1]}, "b", {"string": "columnInfo", "args": [2]}, {"string": "rowInfo", "args": [1]}, "c", {"string": "columnInfo", "args": [3]}, {"string": "rowInfo", "args": [1]}, "d", {"string": "columnInfo", "args": [1]}, {"string": "rowInfo", "args": [2]}, "e", {"string": "columnInfo", "args": [2]}, {"string": "rowInfo", "args": [2]}, "f", {"string": "columnInfo", "args": [3]}, {"string": "rowInfo", "args": [2]}, {"string": "mathmltable"}, {"string": "tblColumnInfo", "count": 3}, {"string": "tblRowInfo", "count": 2}]
           ],
           expectedBraille: [
-            [{"string": "mathmltableAbbr"},{"string": "tblColumnInfoAbbr","count": 3},{"string": "tblRowInfoAbbr","count": 2},{"string": "cellInfoAbbr","args": [1,1]},"a",{"string": "cellInfoAbbr","args": [2,1]},"b",{"string": "cellInfoAbbr","args": [3,1]},"c",{"string": "cellInfoAbbr","args": [1,2]},"d",{"string": "cellInfoAbbr","args": [2,2]},"e",{"string": "cellInfoAbbr","args": [3,2]},"f"],
-            ["a",{"string": "cellInfoAbbr","args": [1,1]},"b",{"string": "cellInfoAbbr","args": [2,1]},"c",{"string": "cellInfoAbbr","args": [3,1]},"d",{"string": "cellInfoAbbr","args": [1,2]},"e",{"string": "cellInfoAbbr","args": [2,2]},"f",{"string": "cellInfoAbbr","args": [3,2]},{"string": "mathmltableAbbr"},{"string": "tblColumnInfoAbbr","count": 3},{"string": "tblRowInfoAbbr","count": 2}]
+            [{"string": "mathmltableAbbr"}, {"string": "tblColumnInfoAbbr", "count": 3}, {"string": "tblRowInfoAbbr", "count": 2}, {"string": "cellInfoAbbr", "args": [1, 1]}, "a", {"string": "cellInfoAbbr", "args": [2, 1]}, "b", {"string": "cellInfoAbbr", "args": [3, 1]}, "c", {"string": "cellInfoAbbr", "args": [1, 2]}, "d", {"string": "cellInfoAbbr", "args": [2, 2]}, "e", {"string": "cellInfoAbbr", "args": [3, 2]}, "f"],
+            ["a", {"string": "cellInfoAbbr", "args": [1, 1]}, "b", {"string": "cellInfoAbbr", "args": [2, 1]}, "c", {"string": "cellInfoAbbr", "args": [3, 1]}, "d", {"string": "cellInfoAbbr", "args": [1, 2]}, "e", {"string": "cellInfoAbbr", "args": [2, 2]}, "f", {"string": "cellInfoAbbr", "args": [3, 2]}, {"string": "mathmltableAbbr"}, {"string": "tblColumnInfoAbbr", "count": 3}, {"string": "tblRowInfoAbbr", "count": 2}]
           ]
       }, {
           accOrElmOrID: "menclose-1",
           expectedUtterance: [
-            [{"string": "mathmlenclosed"},{"string": "notation-longdiv"},"a"],
-            ["a",{"string": "notation-longdiv"},{"string": "mathmlenclosed"}]
+            [{"string": "mathmlenclosed"}, {"string": "notation-longdiv"}, "a"],
+            ["a", {"string": "notation-longdiv"}, {"string": "mathmlenclosed"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlenclosedAbbr"},{"string": "notation-longdivAbbr"},"a"],
-            ["a",{"string": "notation-longdivAbbr"},{"string": "mathmlenclosedAbbr"}]
+            [{"string": "mathmlenclosedAbbr"}, {"string": "notation-longdivAbbr"}, "a"],
+            ["a", {"string": "notation-longdivAbbr"}, {"string": "mathmlenclosedAbbr"}]
           ]
         }, {
           accOrElmOrID: "menclose-2",
           expectedUtterance: [
-            [{"string": "mathmlenclosed"},{"string": "notation-circle"},"a"],
-            ["a",{"string": "notation-circle"},{"string": "mathmlenclosed"}]
+            [{"string": "mathmlenclosed"}, {"string": "notation-circle"}, "a"],
+            ["a", {"string": "notation-circle"}, {"string": "mathmlenclosed"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlenclosedAbbr"},{"string": "notation-circleAbbr"},"a"],
-            ["a",{"string": "notation-circleAbbr"},{"string": "mathmlenclosedAbbr"}]
+            [{"string": "mathmlenclosedAbbr"}, {"string": "notation-circleAbbr"}, "a"],
+            ["a", {"string": "notation-circleAbbr"}, {"string": "mathmlenclosedAbbr"}]
           ]
         }, {
           accOrElmOrID: "menclose-3",
           expectedUtterance: [
-            [{"string": "mathmlenclosed"},{"string": "notation-left"},{"string": "notation-top"},{"string": "notation-bottom"},"a"],
-            ["a",{"string": "notation-left"},{"string": "notation-top"},{"string": "notation-bottom"},{"string": "mathmlenclosed"}]
+            [{"string": "mathmlenclosed"}, {"string": "notation-left"}, {"string": "notation-top"}, {"string": "notation-bottom"}, "a"],
+            ["a", {"string": "notation-left"}, {"string": "notation-top"}, {"string": "notation-bottom"}, {"string": "mathmlenclosed"}]
           ],
           expectedBraille: [
-            [{"string": "mathmlenclosedAbbr"},{"string": "notation-leftAbbr"},{"string": "notation-topAbbr"},{"string": "notation-bottomAbbr"},"a"],
-            ["a",{"string": "notation-leftAbbr"},{"string": "notation-topAbbr"},{"string": "notation-bottomAbbr"},{"string": "mathmlenclosedAbbr"}]
+            [{"string": "mathmlenclosedAbbr"}, {"string": "notation-leftAbbr"}, {"string": "notation-topAbbr"}, {"string": "notation-bottomAbbr"}, "a"],
+            ["a", {"string": "notation-leftAbbr"}, {"string": "notation-topAbbr"}, {"string": "notation-bottomAbbr"}, {"string": "mathmlenclosedAbbr"}]
           ]
         }];
 
       // Test all possible utterance order preference values.
       function testOutputOrder(aOutputOrder) {
         return function() {
           SpecialPowers.pushPrefEnv({
             "set": [[PREF_UTTERANCE_ORDER, aOutputOrder]]
--- a/accessible/tests/mochitest/layout.js
+++ b/accessible/tests/mochitest/layout.js
@@ -210,23 +210,23 @@ function getBoundsForDOMElm(aID) {
     var img = elm.ownerDocument.querySelector(selector);
 
     var areaCoords = elm.coords.split(",");
     var areaX = parseInt(areaCoords[0]);
     var areaY = parseInt(areaCoords[1]);
     var areaWidth = parseInt(areaCoords[2]) - areaX;
     var areaHeight = parseInt(areaCoords[3]) - areaY;
 
-    var rect = img.getBoundingClientRect();
+    let rect = img.getBoundingClientRect();
     x = rect.left + areaX;
     y = rect.top + areaY;
     width = areaWidth;
     height = areaHeight;
   } else {
-    var rect = elm.getBoundingClientRect();
+    let rect = elm.getBoundingClientRect();
     x = rect.left;
     y = rect.top;
     width = rect.width;
     height = rect.height;
   }
 
   var elmWindow = elm.ownerGlobal;
   return CSSToDevicePixels(elmWindow,
--- a/accessible/tests/mochitest/name/markup.js
+++ b/accessible/tests/mochitest/name/markup.js
@@ -347,17 +347,17 @@ function evaluateXPath(aNode, aExpr, aRe
     var node = aNode.ownerDocument == null ?
       aNode.documentElement : aNode.ownerDocument.documentElement;
     resolver = xpe.createNSResolver(node);
   }
 
   var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
   var found = [];
   var res;
-  while (res = result.iterateNext())
+  while ((res = result.iterateNext()))
     found.push(res);
 
   return found;
 }
 
 function htmlDocResolver(aPrefix) {
   var ns = {
     "html": "http://www.w3.org/1999/xhtml"
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -18,43 +18,43 @@ const NS_ERROR_INVALID_ARG = 0x80070057;
 // //////////////////////////////////////////////////////////////////////////////
 // Traversal rules
 
 /**
  * Rule object to traverse all focusable nodes and text nodes.
  */
 var HeadersTraversalRule =
 {
-  getMatchRoles: function(aRules) {
+  getMatchRoles(aRules) {
     aRules.value = [ROLE_HEADING];
     return aRules.value.length;
   },
 
   preFilter: PREFILTER_INVISIBLE,
 
-  match: function(aAccessible) {
+  match(aAccessible) {
     return FILTER_MATCH;
   },
 
   QueryInterface: XPCOMUtils.generateQI([nsIAccessibleTraversalRule])
 };
 
 /**
  * Traversal rule for all focusable nodes or leafs.
  */
 var ObjectTraversalRule =
 {
-  getMatchRoles: function(aRules) {
+  getMatchRoles(aRules) {
     aRules.value = [];
     return 0;
   },
 
   preFilter: PREFILTER_INVISIBLE | PREFILTER_ARIA_HIDDEN | PREFILTER_TRANSPARENT,
 
-  match: function(aAccessible) {
+  match(aAccessible) {
     var rv = FILTER_IGNORE;
     var role = aAccessible.role;
     if (hasState(aAccessible, STATE_FOCUSABLE) &&
         (role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME))
       rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH;
     else if (aAccessible.childCount == 0 &&
              role != ROLE_STATICTEXT && aAccessible.name.trim())
       rv = FILTER_MATCH;
@@ -379,27 +379,27 @@ function setModalRootInvoker(aDocAcc, aM
 function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) {
   aDocAcc.virtualCursor.position = null;
 
   // Add modal root (if any)
   aQueue.push(new setModalRootInvoker(aDocAcc, aModalRoot, 0));
 
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
 
-  for (var i = 1; i < aSequence.length; i++) {
-    var invoker =
+  for (let i = 1; i < aSequence.length; i++) {
+    let invoker =
       new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
     aQueue.push(invoker);
   }
 
   // No further more matches for given rule, expect no virtual cursor changes.
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
 
-  for (var i = aSequence.length - 2; i >= 0; i--) {
-    var invoker =
+  for (let i = aSequence.length - 2; i >= 0; i--) {
+    let invoker =
       new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]);
     aQueue.push(invoker);
   }
 
   // No previous more matches for given rule, expect no virtual cursor changes.
   aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
 
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule,
--- a/accessible/tests/mochitest/pivot/test_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/test_virtualcursor.html
@@ -55,17 +55,17 @@
          "An ", "embedded", " document.", "Hide me", "Link 1", "Link 2",
          "Link 3", "Hello", "World"]);
 
       // Just a random smoke test to see if our setTextRange works.
       gQueue.push(
         new setVCRangeInvoker(
           docAcc,
           getAccessible(doc.getElementById("paragraph-2"), nsIAccessibleText),
-          [2,6]));
+          [2, 6]));
 
       gQueue.push(new removeVCPositionInvoker(
         docAcc, doc.getElementById("hide-me")));
 
       gQueue.push(new removeVCRootInvoker(
         doc.getElementById("links")));
 
       var [x, y] = getBounds(getAccessible(doc.getElementById("heading-1-1")));
--- a/accessible/tests/mochitest/pivot/test_virtualcursor_text.html
+++ b/accessible/tests/mochitest/pivot/test_virtualcursor_text.html
@@ -32,185 +32,185 @@
       gQueue = new eventQueue();
 
       gQueue.onFinish = function onFinish() {
         closeBrowserWindow();
       };
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("paragraph-1"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 4],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [4,5],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [4, 5],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [3,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [3, 4],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [5,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [5, 7],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,3],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 3],
                   getAccessible(doc.getElementById("p1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10,14],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10, 14],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,3],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 3],
                   getAccessible(doc.getElementById("p1-link-1"), nsIAccessibleText)));
       // set user input to false, and see if it works
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [5,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [5, 7],
                   getAccessible(doc.getElementById("paragraph-1"), nsIAccessibleText)),
                   false);
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("section-1"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,1],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 1],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,9],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 9],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
       // set user input to false, and see if it works
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10,14],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10, 14],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText),
                   false));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [4,6],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [4, 6],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [7,12],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [7, 12],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 2],
                   getAccessible(doc.getElementById("s1-link-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [15,19],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [15, 19],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [20,28],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [20, 28],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,5],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 5],
                   getAccessible(doc.getElementById("section-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [6,10],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [6, 10],
                   getAccessible(doc.getElementById("section-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,5],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 5],
                   getAccessible(doc.getElementById("section-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [20,28],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [20, 28],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [15,19],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [15, 19],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 2],
                   getAccessible(doc.getElementById("s1-link-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [7,12],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [7, 12],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [4,6],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [4, 6],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [10,14],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [10, 14],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,9],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 9],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,1],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 1],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("s1-link-1"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [1,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [1, 2],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [0,1],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [0, 1],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [1,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [1, 2],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [0,1],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [0, 1],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [1,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [1, 2],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [2,9],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [2, 9],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10,14],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [10, 14],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [3,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [3, 4],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [13,14],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [13, 14],
                   getAccessible(doc.getElementById("s1-link-1"), nsIAccessibleText)));
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("section-2"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [27,28],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", CHAR_BOUNDARY, [27, 28],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [0,1],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", CHAR_BOUNDARY, [0, 1],
                   getAccessible(doc.getElementById("section-2"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("paragraph-2"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,12],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 12],
                   getAccessible(doc.getElementById("paragraph-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("cell-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,8],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 8],
                   getAccessible(doc.getElementById("cell-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,3],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 3],
                   getAccessible(doc.getElementById("cell-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [4,11],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [4, 11],
                   getAccessible(doc.getElementById("cell-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,6],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 6],
                   getAccessible(doc.getElementById("cell-4"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [7,13],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [7, 13],
                   getAccessible(doc.getElementById("cell-4"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("section-3"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("section-3"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("section-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [7,13],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [7, 13],
                   getAccessible(doc.getElementById("cell-4"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,6],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 6],
                   getAccessible(doc.getElementById("cell-4"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [4,11],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [4, 11],
                   getAccessible(doc.getElementById("cell-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,3],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 3],
                   getAccessible(doc.getElementById("cell-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,8],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 8],
                   getAccessible(doc.getElementById("cell-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("cell-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,12],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 12],
                   getAccessible(doc.getElementById("paragraph-2"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("paragraph-3"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("paragraph-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,8],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 8],
                   getAccessible(doc.getElementById("p3-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [8,10],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [8, 10],
                   getAccessible(doc.getElementById("paragraph-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 4],
                   getAccessible(doc.getElementById("p3-link-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,5],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 5],
                   getAccessible(doc.getElementById("p3-link-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [14,20],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [14, 20],
                   getAccessible(doc.getElementById("paragraph-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,5],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 5],
                   getAccessible(doc.getElementById("p3-link-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 4],
                   getAccessible(doc.getElementById("p3-link-2"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [8,10],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [8, 10],
                   getAccessible(doc.getElementById("paragraph-3"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,8],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 8],
                   getAccessible(doc.getElementById("p3-link-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,7],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 7],
                   getAccessible(doc.getElementById("paragraph-3"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("s1-link-2"))));
       // Start with the pivot in the middle of the paragraph
       gQueue.push(new setVCPosInvoker(docAcc, "moveNext", ObjectTraversalRule, " will traverse"));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [15,19],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [15, 19],
                   getAccessible(doc.getElementById("section-1"), nsIAccessibleText)));
-      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0,2],
+      gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, [0, 2],
                   getAccessible(doc.getElementById("s1-link-2"), nsIAccessibleText)));
 
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("end-block"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 4],
                   getAccessible(doc.getElementById("end-block"), nsIAccessibleText)));
       gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, null, false));
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("start-block"))));
-      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0,4],
+      gQueue.push(new setVCTextInvoker(docAcc, "moveNextByText", WORD_BOUNDARY, [0, 4],
                   getAccessible(doc.getElementById("start-block"), nsIAccessibleText)));
       gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, null, false));
       gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, null, false));
       gQueue.push(new setVCPosInvoker(docAcc, null, null,
                                       getAccessible(doc.getElementById("start-block"))));
       gQueue.push(new setVCTextInvoker(docAcc, "movePreviousByText", WORD_BOUNDARY, null, false));
 
       gQueue.invoke();
--- a/accessible/tests/mochitest/relations.js
+++ b/accessible/tests/mochitest/relations.js
@@ -60,44 +60,45 @@ function testRelation(aIdentifier, aRelT
     ok(false, "There are unexpected targets of " + relDescr);
     return;
   }
 
   var relatedIds = (aRelatedIdentifiers instanceof Array) ?
   aRelatedIdentifiers : [aRelatedIdentifiers];
 
   var targets = [];
-   for (var idx = 0; idx < relatedIds.length; idx++)
+   for (let idx = 0; idx < relatedIds.length; idx++)
      targets.push(getAccessible(relatedIds[idx]));
 
   if (targets.length != relatedIds.length)
     return;
 
   var actualTargets = relation.getTargets();
 
   // Check if all given related accessibles are targets of obtained relation.
-  for (var idx = 0; idx < targets.length; idx++) {
+  for (let idx = 0; idx < targets.length; idx++) {
     var isFound = false;
-    var enumerate = actualTargets.enumerate();
+    let enumerate = actualTargets.enumerate();
     while (enumerate.hasMoreElements()) {
-      var relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
+      let relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
       if (targets[idx] == relatedAcc) {
         isFound = true;
         break;
       }
     }
 
     ok(isFound, prettyName(relatedIds[idx]) + " is not a target of" + relDescr);
   }
 
   // Check if all obtained targets are given related accessibles.
-  var enumerate = actualTargets.enumerate();
+  let enumerate = actualTargets.enumerate();
   while (enumerate.hasMoreElements()) {
-    var relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
-    for (var idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++);
+    let relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
+    let idx;
+    for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++);
 
     if (idx == targets.length)
       ok(false, "There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr);
   }
 }
 
 /**
  * Test that the given accessible relations don't exist.
@@ -123,26 +124,26 @@ function testAbsentRelation(aIdentifier,
     ok(true, "No relations exist.");
     return;
   }
 
   var relatedIds = (aUnrelatedIdentifiers instanceof Array) ?
     aUnrelatedIdentifiers : [aUnrelatedIdentifiers];
 
   var targets = [];
-  for (var idx = 0; idx < relatedIds.length; idx++)
+  for (let idx = 0; idx < relatedIds.length; idx++)
     targets.push(getAccessible(relatedIds[idx]));
 
   if (targets.length != relatedIds.length)
     return;
 
   var actualTargets = relation.getTargets();
 
   // Any found targets that match given accessibles should be called out.
-  for (var idx = 0; idx < targets.length; idx++) {
+  for (let idx = 0; idx < targets.length; idx++) {
     var notFound = true;
     var enumerate = actualTargets.enumerate();
     while (enumerate.hasMoreElements()) {
       var relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
       if (targets[idx] == relatedAcc) {
         notFound = false;
         break;
       }
--- a/accessible/tests/mochitest/relations/test_ui_modalprompt.html
+++ b/accessible/tests/mochitest/relations/test_ui_modalprompt.html
@@ -29,17 +29,17 @@
         return false;
       }
     }
 
     function showAlert() {
       this.eventSeq = [
         {
           type: EVENT_SHOW,
-          match: function(aEvent) {
+          match(aEvent) {
             return aEvent.accessible.role == ROLE_DIALOG;
           }
         }
       ];
 
       this.invoke = function showAlert_invoke() {
         window.setTimeout(
           function() {
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -162,17 +162,17 @@ function getRole(aAccOrElmOrID) {
   return role;
 }
 
 /**
  * Analogy of SimpleTest.is function used to check the role.
  */
 function isRole(aIdentifier, aRole, aMsg) {
   var role = getRole(aIdentifier);
-  if (role == - 1)
+  if (role == -1)
     return;
 
   if (role == aRole) {
     ok(true, aMsg);
     return;
   }
 
   var got = roleToString(role);
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -112,17 +112,17 @@
         var id = weak_landmarks[l] + "_table";
         testRole(id, ROLE_TABLE);
     
         var accessibleTable = getAccessible(id, [nsIAccessibleTable], null,
                                             DONOTFAIL_IF_NO_INTERFACE);
         ok(!!accessibleTable, "landmarked table should have nsIAccessibleTable");
     
         if (accessibleTable)
-          is(accessibleTable.getCellAt(0,0).firstChild.name, "hi", "no cell");
+          is(accessibleTable.getCellAt(0, 0).firstChild.name, "hi", "no cell");
       }
 
       // ////////////////////////////////////////////////////////////////////////
       // test gEmptyRoleMap
       testRole("buttontable_row", ROLE_NOTHING);
       testRole("buttontable_cell", ROLE_NOTHING);
 
       // abstract roles
--- a/accessible/tests/mochitest/scroll/test_zoom.html
+++ b/accessible/tests/mochitest/scroll/test_zoom.html
@@ -16,37 +16,37 @@
           src="../role.js"></script>
   <script type="application/javascript"
           src="../layout.js"></script>
 
   <script type="application/javascript">
     function testScrollToPoint() {
       // scrollToPoint relative screen
       var anchor = getAccessible("bottom1");
-      var [x, /* y */] = getPos(anchor);
+      let [x, /* y */] = getPos(anchor);
       var [docX, docY] = getPos(document);
 
       anchor.scrollToPoint(COORDTYPE_SCREEN_RELATIVE, docX, docY);
       testPos(anchor, [x, docY]);
 
       // scrollToPoint relative window
       anchor = getAccessible("bottom2");
-      var [x, /* y */] = getPos(anchor);
+      [x, /* y */] = getPos(anchor);
       var wnd = getRootAccessible().DOMDocument.defaultView;
       var [screenX, screenY] = CSSToDevicePixels(wnd, wnd.screenX, wnd.screenY);
-      var scrollToX = docX - screenX, scrollToY = docY - screenY;
+      let scrollToX = docX - screenX, scrollToY = docY - screenY;
 
       anchor.scrollToPoint(COORDTYPE_WINDOW_RELATIVE, scrollToX, scrollToY);
       testPos(anchor, [x, docY]);
 
       // scrollToPoint relative parent
       anchor = getAccessible("bottom3");
-      var [x, /* y */] = getPos(anchor);
+      [x, /* y */] = getPos(anchor);
       var [parentX, parentY] = getPos(anchor.parent);
-      var scrollToX = parentX - docX, scrollToY = parentY - docY;
+      scrollToX = parentX - docX, scrollToY = parentY - docY;
 
       anchor.scrollToPoint(COORDTYPE_PARENT_RELATIVE, scrollToX, scrollToY);
       testPos(anchor, [x, docY]);
     }
 
     function doTest() {
       testScrollToPoint();
       zoomDocument(document, 2.0);
--- a/accessible/tests/mochitest/selectable.js
+++ b/accessible/tests/mochitest/selectable.js
@@ -13,32 +13,32 @@ function testSelectableSelection(aIdenti
   var len = aSelectedChildren.length;
 
   // getSelectedChildren
   var selectedChildren = acc.selectedItems;
   is(selectedChildren ? selectedChildren.length : 0, len,
      msg + "getSelectedChildren: wrong selected children count for " +
      prettyName(aIdentifier));
 
-  for (var idx = 0; idx < len; idx++) {
-    var expectedAcc = getAccessible(aSelectedChildren[idx]);
+  for (let idx = 0; idx < len; idx++) {
+    let expectedAcc = getAccessible(aSelectedChildren[idx]);
     var actualAcc = selectedChildren.queryElementAt(idx, nsIAccessible);
     is(actualAcc, expectedAcc,
        msg + "getSelectedChildren: wrong selected child at index " + idx +
        " for " + prettyName(aIdentifier) + " { actual : " +
        prettyName(actualAcc) + ", expected: " + prettyName(expectedAcc) + "}");
   }
 
   // selectedItemCount
   is(acc.selectedItemCount, aSelectedChildren.length,
      "selectedItemCount: wrong selected children count for " + prettyName(aIdentifier));
 
   // getSelectedItemAt
-  for (var idx = 0; idx < len; idx++) {
-    var expectedAcc = getAccessible(aSelectedChildren[idx]);
+  for (let idx = 0; idx < len; idx++) {
+    let expectedAcc = getAccessible(aSelectedChildren[idx]);
     is(acc.getSelectedItemAt(idx), expectedAcc,
        msg + "getSelectedItemAt: wrong selected child at index " + idx + " for " +
        prettyName(aIdentifier));
   }
 
   // isItemSelected
   testIsItemSelected(acc, acc, { value: 0 }, aSelectedChildren, msg);
 }
@@ -63,16 +63,16 @@ function testIsItemSelected(aSelectAcc, 
 
       // isItemSelected
       is(aSelectAcc.isItemSelected(aIndexObj.value++), isSelected,
          aMsg + "isItemSelected: wrong selected child " + prettyName(child) +
          " for " + prettyName(aSelectAcc));
 
       // selected state
       testStates(child, isSelected ? STATE_SELECTED : 0, 0,
-                 !isSelected ? STATE_SELECTED : 0 , 0);
+                 !isSelected ? STATE_SELECTED : 0, 0);
 
       continue;
     }
 
     testIsItemSelected(aSelectAcc, child, aIndexObj, aSelectedChildren);
   }
 }
--- a/accessible/tests/mochitest/selectable/test_select.html
+++ b/accessible/tests/mochitest/selectable/test_select.html
@@ -76,17 +76,17 @@
       testSelectableSelection(select, [ "cb2_item1" ]);
 
       select.unselectAll();
       testSelectableSelection(select, [ "cb2_item1" ]);
 
       // ////////////////////////////////////////////////////////////////////////
       // select@size="4" aka single selectable listbox
 
-      var id = "listbox";
+      id = "listbox";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
       // select 2nd item
       select.addItemToSelection(1);
@@ -151,17 +151,17 @@
                               "selectAll: ");
 
       select.unselectAll();
       testSelectableSelection(select, [ ], "unselectAll: ");
 
       // ////////////////////////////////////////////////////////////////////////
       // select@size="4" multiselect with optgroups
 
-      var id = "listbox4";
+      id = "listbox4";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
       select.addItemToSelection(0);
       testSelectableSelection(select, [ "lb4_item1" ]);
--- a/accessible/tests/mochitest/states/test_doc.html
+++ b/accessible/tests/mochitest/states/test_doc.html
@@ -18,19 +18,19 @@
   <script type="application/javascript">
     function doTest() {
       // Bug 566542: root accesible should expose active state when focused.
       testStates(getRootAccessible(), 0, EXT_STATE_ACTIVE);
 
       // Bug 509696, 607219.
       testStates(document, STATE_READONLY, 0); // role=""
 
-      document.body.setAttribute("role","banner"); // no platform mapping
+      document.body.setAttribute("role", "banner"); // no platform mapping
       testStates(document, STATE_READONLY);
-      document.body.setAttribute("role","foo"); // bogus role
+      document.body.setAttribute("role", "foo"); // bogus role
       testStates(document, STATE_READONLY);
       document.body.removeAttribute("role");
       testStates(document, STATE_READONLY);
 
       // Bugs 454997 and 467387
       testStates(document, STATE_READONLY);
       testStates("document", STATE_READONLY);
       testStates("editable_document", 0, EXT_STATE_EDITABLE, STATE_READONLY);
--- a/accessible/tests/mochitest/states/test_inputs.html
+++ b/accessible/tests/mochitest/states/test_inputs.html
@@ -26,18 +26,18 @@
 
     testStates("input_readonly", 0, EXT_STATE_EDITABLE);
     testStates("input_disabled", 0, EXT_STATE_EDITABLE);
     testStates("textarea_readonly", 0, EXT_STATE_EDITABLE);
     testStates("textarea_disabled", 0, EXT_STATE_EDITABLE);
 
     // //////////////////////////////////////////////////////////////////////////
     // 'required', 'readonly' and 'unavailable' states.
-    var maybe_required = ["input","search","radio","checkbox","textarea"];
-    var never_required = ["submit","button","reset","image"];
+    var maybe_required = ["input", "search", "radio", "checkbox", "textarea"];
+    var never_required = ["submit", "button", "reset", "image"];
 
     var i;
     for (i in maybe_required) {
       testStates(maybe_required[i],
                  STATE_FOCUSABLE, 0,
                  STATE_REQUIRED | STATE_READONLY | STATE_UNAVAILABLE);
 
       testStates(maybe_required[i] + "_required",
@@ -69,17 +69,17 @@
     // //////////////////////////////////////////////////////////////////////////
     // inherited from file control
     var fileBrowseButton = getAccessible("file").firstChild;
     testStates(fileBrowseButton, STATE_UNAVAILABLE | STATE_REQUIRED);
     // No states on the label.
 
     // //////////////////////////////////////////////////////////////////////////
     // 'invalid' state
-    var invalid = ["pattern","email","url"];
+    var invalid = ["pattern", "email", "url"];
     for (i in invalid) {
       testStates(invalid[i], STATE_INVALID);
       testStates(invalid[i] + "2", 0, 0, STATE_INVALID);
     }
 
     // //////////////////////////////////////////////////////////////////////////
     // not 'invalid' state
     // (per spec, min/maxlength are always valid until interactively edited)
@@ -90,17 +90,17 @@
        "input should be valid despite maxlength (no interactive edits)");
 
     var validInput2 = document.createElement("input");
     validInput2.minLength = "1";
     validInput2.value = "";
     ok(validInput2.validity.valid,
        "input should be valid despite minlength (no interactive edits)");
 
-    var valid = ["minlength","maxlength"];
+    var valid = ["minlength", "maxlength"];
     for (i in valid) {
       testStates(valid[i], 0, 0, STATE_INVALID);
       testStates(valid[i] + "2", 0, 0, STATE_INVALID);
     }
 
     // //////////////////////////////////////////////////////////////////////////
     // 'invalid' state
     // (per spec, min/maxlength validity is affected by interactive edits)
--- a/accessible/tests/mochitest/table.js
+++ b/accessible/tests/mochitest/table.js
@@ -90,17 +90,17 @@ function testTableStruct(aIdentifier, aC
 
   // special types of column headers handling
   if (aColHeaderType) {
     var headersObj = {
       role: ROLE_LIST,
       children: []
     };
 
-    for (var idx = 0; idx < colsCount; idx++) {
+    for (let idx = 0; idx < colsCount; idx++) {
       var headerCellObj = {
         role: ROLE_COLUMNHEADER
       };
       headersObj.children.push(headerCellObj);
     }
 
     if (aColHeaderType == kTreeColumnHeader) {
       var columnPickerObj = {
@@ -109,43 +109,41 @@ function testTableStruct(aIdentifier, aC
 
       headersObj.children.push(columnPickerObj);
     }
 
     tableObj.children.push(headersObj);
   }
 
   // rows and cells accessibles
-  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
-    var rowObj = {
+  for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    let rowObj = {
       role: aRowRoles ? aRowRoles[rowIdx] : ROLE_ROW,
       children: []
     };
 
-    for (var colIdx = 0; colIdx < colsCount; colIdx++) {
-      var celltype = aCellsArray[rowIdx][colIdx];
+    for (let colIdx = 0; colIdx < colsCount; colIdx++) {
+      let celltype = aCellsArray[rowIdx][colIdx];
 
       var role = ROLE_NOTHING;
       switch (celltype) {
         case kDataCell:
           role = (aTableType == kMathTable ? ROLE_MATHML_CELL :
                   (isGrid ? ROLE_GRID_CELL : ROLE_CELL));
           break;
         case kRowHeaderCell:
           role = ROLE_ROWHEADER;
           break;
         case kColHeaderCell:
           role = ROLE_COLUMNHEADER;
           break;
       }
 
       if (role != ROLE_NOTHING) {
-        var cellObj = {
-          role: role
-        };
+        var cellObj = { role };
         rowObj.children.push(cellObj);
       }
     }
 
     tableObj.children.push(rowObj);
   }
 
   testAccessibleTree(aIdentifier, tableObj);
@@ -160,35 +158,36 @@ function testTableStruct(aIdentifier, aC
 
   // rowCount and columnCount
   is(table.rowCount, rowCount,
      "Wrong rows count of " + prettyName(aIdentifier));
   is(table.columnCount, colsCount,
      "Wrong columns count of " + prettyName(aIdentifier));
 
   // rows and columns extents
-  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
-    for (var colIdx = 0; colIdx < colsCount; colIdx++) {
-      var celltype = aCellsArray[rowIdx][colIdx];
+  for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    for (let colIdx = 0; colIdx < colsCount; colIdx++) {
+      let celltype = aCellsArray[rowIdx][colIdx];
       if (celltype & kOrigin) {
 
         // table getRowExtentAt
         var rowExtent = table.getRowExtentAt(rowIdx, colIdx);
-        for (var idx = rowIdx + 1;
+        let idx;
+        for (idx = rowIdx + 1;
              idx < rowCount && (aCellsArray[idx][colIdx] & kRowSpanned);
              idx++);
 
         var expectedRowExtent = idx - rowIdx;
         is(rowExtent, expectedRowExtent,
            "getRowExtentAt: Wrong number of spanned rows at (" + rowIdx + ", " +
            colIdx + ") for " + prettyName(aIdentifier));
 
         // table getColumnExtentAt
         var colExtent = table.getColumnExtentAt(rowIdx, colIdx);
-        for (var idx = colIdx + 1;
+        for (idx = colIdx + 1;
              idx < colsCount && (aCellsArray[rowIdx][idx] & kColSpanned);
              idx++);
 
         var expectedColExtent = idx - colIdx;
         is(colExtent, expectedColExtent,
            "getColumnExtentAt: Wrong number of spanned columns at (" + rowIdx +
            ", " + colIdx + ") for " + prettyName(aIdentifier));
 
@@ -234,17 +233,17 @@ function testTableIndexes(aIdentifier, a
       try {
         cellAcc = null;
         cellAcc = tableAcc.getCellAt(rowIdx, colIdx);
       } catch (e) { }
 
       ok(idx != -1 && cellAcc || idx == -1 && !cellAcc,
          id + ": Can't get cell accessible at row = " + rowIdx + ", column = " + colIdx);
 
-      if (idx != - 1) {
+      if (idx != -1) {
 
         // getRowIndexAt
         var origRowIdx = rowIdx;
         while (origRowIdx > 0 &&
                aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
           origRowIdx--;
 
         try {
@@ -369,19 +368,19 @@ function testTableSelection(aIdentifier,
 
   var rowCount = aCellsArray.length;
   var colsCount = aCellsArray[0].length;
 
   // Columns selection tests.
   var selCols = [];
 
   // isColumnSelected test
-  for (var colIdx = 0; colIdx < colsCount; colIdx++) {
+  for (let colIdx = 0; colIdx < colsCount; colIdx++) {
     var isColSelected = true;
-    for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
       if (aCellsArray[rowIdx][colIdx] == false ||
           aCellsArray[rowIdx][colIdx] == undefined) {
         isColSelected = false;
         break;
       }
     }
 
     is(acc.isColumnSelected(colIdx), isColSelected,
@@ -400,28 +399,28 @@ function testTableSelection(aIdentifier,
   var actualSelColsCountObj = { value: null };
   var actualSelCols = acc.getSelectedColumnIndices(actualSelColsCountObj);
 
   var actualSelColsCount = actualSelColsCountObj.value;
   is(actualSelColsCount, selCols.length,
       msg + "Wrong count of selected columns for " + prettyName(aIdentifier) +
       "from getSelectedColumns.");
 
-  for (var i = 0; i < actualSelColsCount; i++) {
+  for (let i = 0; i < actualSelColsCount; i++) {
     is(actualSelCols[i], selCols[i],
         msg + "Column at index " + selCols[i] + " should be selected.");
   }
 
   // Rows selection tests.
   var selRows = [];
 
   // isRowSelected test
-  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+  for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
     var isRowSelected = true;
-    for (var colIdx = 0; colIdx < colsCount; colIdx++) {
+    for (let colIdx = 0; colIdx < colsCount; colIdx++) {
       if (aCellsArray[rowIdx][colIdx] == false ||
           aCellsArray[rowIdx][colIdx] == undefined) {
         isRowSelected = false;
         break;
       }
     }
 
     is(acc.isRowSelected(rowIdx), isRowSelected,
@@ -440,27 +439,27 @@ function testTableSelection(aIdentifier,
   var actualSelrowCountObj = { value: null };
   var actualSelRows = acc.getSelectedRowIndices(actualSelrowCountObj);
 
   var actualSelrowCount = actualSelrowCountObj.value;
   is(actualSelrowCount, selRows.length,
       msg + "Wrong count of selected rows for " + prettyName(aIdentifier) +
       "from getSelectedRows.");
 
-  for (var i = 0; i < actualSelrowCount; i++) {
+  for (let i = 0; i < actualSelrowCount; i++) {
     is(actualSelRows[i], selRows[i],
         msg + "Row at index " + selRows[i] + " should be selected.");
   }
 
   // Cells selection tests.
   var selCells = [];
 
   // isCellSelected test
-  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
-    for (var colIdx = 0; colIdx < colsCount; colIdx++) {
+  for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    for (let colIdx = 0; colIdx < colsCount; colIdx++) {
       if (aCellsArray[rowIdx][colIdx] & kSpanned)
         continue;
 
       var isSelected = aCellsArray[rowIdx][colIdx] == true;
       is(acc.isCellSelected(rowIdx, colIdx), isSelected,
          msg + "Wrong selection state of cell at " + rowIdx + " row and " +
          colIdx + " column for " + prettyName(aIdentifier));
 
@@ -477,43 +476,43 @@ function testTableSelection(aIdentifier,
   var actualSelCellsCountObj = { value: null };
   var actualSelCells = acc.getSelectedCellIndices(actualSelCellsCountObj);
 
   var actualSelCellsCount = actualSelCellsCountObj.value;
   is(actualSelCellsCount, selCells.length,
      msg + "Wrong count of selected cells for " + prettyName(aIdentifier) +
      "from getSelectedCells.");
 
-  for (var i = 0; i < actualSelCellsCount; i++) {
+  for (let i = 0; i < actualSelCellsCount; i++) {
     is(actualSelCells[i], selCells[i],
        msg + "getSelectedCellIndices: Cell at index " + selCells[i] +
        " should be selected.");
   }
 
   // selectedCells and isSelected tests
   var actualSelCellsArray = acc.selectedCells;
-  for (var i = 0; i < actualSelCellsCount; i++) {
+  for (let i = 0; i < actualSelCellsCount; i++) {
     var actualSelCellAccessible =
       actualSelCellsArray.queryElementAt(i, nsIAccessibleTableCell);
 
-    var colIdx = acc.getColumnIndexAt(selCells[i]);
-    var rowIdx = acc.getRowIndexAt(selCells[i]);
+    let colIdx = acc.getColumnIndexAt(selCells[i]);
+    let rowIdx = acc.getRowIndexAt(selCells[i]);
     var expectedSelCellAccessible = acc.getCellAt(rowIdx, colIdx);
 
     ok(actualSelCellAccessible, expectedSelCellAccessible,
        msg + "getSelectedCells: Cell at index " + selCells[i] +
        " should be selected.");
 
     ok(actualSelCellAccessible.isSelected(),
        "isSelected: Cell at index " + selCells[i] + " should be selected.");
   }
 
   // selected states tests
-  for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
-    for (var colIdx = 0; colIdx < colsCount; colIdx++) {
+  for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+    for (let colIdx = 0; colIdx < colsCount; colIdx++) {
       if (aCellsArray[rowIdx][colIdx] & kSpanned)
         continue;
 
       var cell = acc.getCellAt(rowIdx, colIdx);
       var isSel = aCellsArray[rowIdx][colIdx];
       if (isSel == undefined)
         testStates(cell, 0, 0, STATE_SELECTABLE | STATE_SELECTED);
       else if (isSel == true)
@@ -695,17 +694,17 @@ function testHeaderCells(aHeaderInfoMap)
     var actualRowHeaderCells = dataCell.rowHeaderCells;
     var actualRowHeaderCellsCount = actualRowHeaderCells.length;
 
     is(actualRowHeaderCellsCount, rowHeaderCellsCount,
        "Wrong number of row header cells for the cell " +
        prettyName(dataCellIdentifier));
 
     if (actualRowHeaderCellsCount == rowHeaderCellsCount) {
-      for (var idx = 0; idx < rowHeaderCellsCount; idx++) {
+      for (let idx = 0; idx < rowHeaderCellsCount; idx++) {
         var rowHeaderCell = getAccessible(rowHeaderCells[idx]);
         var actualRowHeaderCell =
           actualRowHeaderCells.queryElementAt(idx, nsIAccessible);
         isObject(actualRowHeaderCell, rowHeaderCell,
                  "Wrong row header cell at index " + idx + " for the cell " +
                  dataCellIdentifier);
       }
     }
@@ -716,17 +715,17 @@ function testHeaderCells(aHeaderInfoMap)
     var actualColHeaderCells = dataCell.columnHeaderCells;
     var actualColHeaderCellsCount = actualColHeaderCells.length;
 
     is(actualColHeaderCellsCount, colHeaderCellsCount,
        "Wrong number of column header cells for the cell " +
        prettyName(dataCellIdentifier));
 
     if (actualColHeaderCellsCount == colHeaderCellsCount) {
-      for (var idx = 0; idx < colHeaderCellsCount; idx++) {
+      for (let idx = 0; idx < colHeaderCellsCount; idx++) {
         var colHeaderCell = getAccessible(colHeaderCells[idx]);
         var actualColHeaderCell =
           actualColHeaderCells.queryElementAt(idx, nsIAccessible);
         isObject(actualColHeaderCell, colHeaderCell,
                  "Wrong column header cell at index " + idx + " for the cell " +
                  dataCellIdentifier);
       }
     }
@@ -740,27 +739,27 @@ function testHeaderCells(aHeaderInfoMap)
  * Return row and column of orig cell for the given spanned cell.
  */
 function getOrigRowAndColumn(aCellsArray, aRowIdx, aColIdx) {
   var cellState = aCellsArray[aRowIdx][aColIdx];
 
   var origRowIdx = aRowIdx, origColIdx = aColIdx;
   if (cellState & kRowSpanned) {
     for (var prevRowIdx = aRowIdx - 1; prevRowIdx >= 0; prevRowIdx--) {
-      var prevCellState = aCellsArray[prevRowIdx][aColIdx];
+      let prevCellState = aCellsArray[prevRowIdx][aColIdx];
       if (!(prevCellState & kRowSpanned)) {
         origRowIdx = prevRowIdx;
         break;
       }
     }
   }
 
   if (cellState & kColSpanned) {
     for (var prevColIdx = aColIdx - 1; prevColIdx >= 0; prevColIdx--) {
-      var prevCellState = aCellsArray[aRowIdx][prevColIdx];
+      let prevCellState = aCellsArray[aRowIdx][prevColIdx];
       if (!(prevCellState & kColSpanned)) {
         origColIdx = prevColIdx;
         break;
       }
     }
   }
 
   return [origRowIdx, origColIdx];
--- a/accessible/tests/mochitest/table/test_indexes_table.html
+++ b/accessible/tests/mochitest/table/test_indexes_table.html
@@ -37,17 +37,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         [6, 7, 7],
         [6, 8, 9]
       ];
 
       testTableIndexes("tableborder", idxes);
 
       // ////////////////////////////////////////////////////////////////////////
       // table
-      var idxes = [
+      idxes = [
         [ 0,  1,  2,  2,  3,  4,  5,  6],
         [ 7,  8,  9, 10, 11, 12, 13,  6],
         [14, 15, 15, 16, 17, 18, 19,  6],
         [20, 15, 15, 21, 22, 18, 23,  6]
       ];
 
       testTableIndexes("table2", idxes);
 
--- a/accessible/tests/mochitest/table/test_mtable.html
+++ b/accessible/tests/mochitest/table/test_mtable.html
@@ -49,19 +49,19 @@
         ROLE_MATHML_TABLE_ROW
       ];
       testTableStruct("complex", cellsArray, kNoColumnHeader,
                       "", "", kMathTable, rowsArray);
 
       // 'Simple' table with mlabeledtr
       // At the moment we do not implement mlabeledtr but just hide the label
       // with display: none. Thus we just test the role for now. See bug 689641.
-      var idxes = [[0]];
+      idxes = [[0]];
       testTableIndexes("simple_label", idxes);
-      var cellsArray = [[kDataCell]];
+      cellsArray = [[kDataCell]];
       rowsArray = [ROLE_MATHML_LABELED_ROW];
       testTableStruct("simple_label", cellsArray, kNoColumnHeader,
                       "", "", kMathTable, rowsArray);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
--- a/accessible/tests/mochitest/table/test_sels_table.html
+++ b/accessible/tests/mochitest/table/test_sels_table.html
@@ -30,29 +30,29 @@
         [false, false,       false,       false,       false, false,       false, kRowSpanned],
         [false, false,       kColSpanned, false,       false, false,       false, kRowSpanned],
         [false, kRowSpanned, kSpanned,    false,       false, kRowSpanned, false, kRowSpanned]
       ];
 
       testTableSelection("table", cellsArray);
 
       var rowCount = 4;
-      for (var rowIdx = 0; rowIdx < rowCount; rowIdx++)
+      for (let rowIdx = 0; rowIdx < rowCount; rowIdx++)
         testSelectTableRow("table", rowIdx, cellsArray);
 
-      for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
+      for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
         testSelectTableRow("table", rowIdx, cellsArray);
         testUnselectTableRow("table", rowIdx, cellsArray);
       }
 
       var columsCount = 8;
-      for (var colIdx = 0; colIdx < columsCount; colIdx++)
+      for (let colIdx = 0; colIdx < columsCount; colIdx++)
         testSelectTableColumn("table", colIdx, cellsArray);
 
-      for (var colIdx = 0; colIdx < columsCount; colIdx++) {
+      for (let colIdx = 0; colIdx < columsCount; colIdx++) {
         testSelectTableColumn("table", colIdx, cellsArray);
         testUnselectTableColumn("table", colIdx, cellsArray);
       }
 
       var accTable = getAccessible("table", [nsIAccessibleTable]);
       ok(!accTable.isProbablyForLayout(), "table is not for layout");
 
       // ////////////////////////////////////////////////////////////////////////
--- a/accessible/tests/mochitest/table/test_table_2.html
+++ b/accessible/tests/mochitest/table/test_table_2.html
@@ -19,38 +19,38 @@ function doTest() {
   var accTable3 = getAccessible("table3", [nsIAccessibleTable], null, DONOTFAIL_IF_NO_INTERFACE);
   if (!accTable3)
     tableInterfaceExposed = false;
   ok(tableInterfaceExposed, "table interface is not exposed");
 
   if (tableInterfaceExposed) {
     testRole(accTable3, ROLE_ALERT);
 
-    is(accTable3.getCellAt(0,0).firstChild.name, "cell0", "wrong cell");
-    is(accTable3.getCellAt(0,1).firstChild.name, "cell1", "wrong cell");
+    is(accTable3.getCellAt(0, 0).firstChild.name, "cell0", "wrong cell");
+    is(accTable3.getCellAt(0, 1).firstChild.name, "cell1", "wrong cell");
   }
 
   // Test table with role=log and aria property in tr. We create accessible for
   // tr in this case.
   tableInterfaceExposed = true;
   var accTable4 = getAccessible("table4", [nsIAccessibleTable], null, DONOTFAIL_IF_NO_INTERFACE);
   if (!accTable4)
     tableInterfaceExposed = false;
   ok(tableInterfaceExposed, "table interface is not exposed");
 
   if (tableInterfaceExposed) {
     accNotCreated = (!isAccessible("tr"));
     ok(!accNotCreated, "missed tr accessible");
 
     testRole(accTable4, ROLE_TABLE);
 
-    is(accTable4.getCellAt(0,0).firstChild.name, "cell0", "wrong cell");
-    is(accTable4.getCellAt(0,1).firstChild.name, "cell1", "wrong cell");
-    is(accTable4.getCellAt(1,0).firstChild.name, "cell2", "wrong cell");
-    is(accTable4.getCellAt(1,1).firstChild.name, "cell3", "wrong cell");
+    is(accTable4.getCellAt(0, 0).firstChild.name, "cell0", "wrong cell");
+    is(accTable4.getCellAt(0, 1).firstChild.name, "cell1", "wrong cell");
+    is(accTable4.getCellAt(1, 0).firstChild.name, "cell2", "wrong cell");
+    is(accTable4.getCellAt(1, 1).firstChild.name, "cell3", "wrong cell");
   }
 
   SimpleTest.finish();
 }
 SimpleTest.waitForExplicitFinish();
 addA11yLoadEvent(doTest);
   </script>
  </head>
--- a/accessible/tests/mochitest/test_aria_token_attrs.html
+++ b/accessible/tests/mochitest/test_aria_token_attrs.html
@@ -32,17 +32,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       testStates("button_pressed_empty", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
       testStates("button_pressed_undefined", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
       testStates("button_pressed_absent", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
 
       // test (checkbox) checkable and checked states
       testStates("checkbox_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("checkbox_checked_mixed", (STATE_CHECKABLE | STATE_MIXED), 0, STATE_CHECKED);
       testStates("checkbox_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
-      testStates("checkbox_checked_empty", STATE_CHECKABLE , 0, STATE_CHECKED);
+      testStates("checkbox_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("checkbox_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("checkbox_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
       // test native checkbox checked state and aria-checked state (if conflict, native wins)
       testStates("native_checkbox_nativechecked_ariatrue", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariafalse", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariaempty", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("native_checkbox_nativechecked_ariaundefined", (STATE_CHECKABLE | STATE_CHECKED));
@@ -87,17 +87,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       testStates("listbox_multiselectable_false", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE);
       testStates("listbox_multiselectable_empty", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE);
       testStates("listbox_multiselectable_undefined", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE);
       testStates("listbox_multiselectable_absent", 0, 0, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE);
 
       // test (option) checkable and checked states
       testStates("option_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("option_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
-      testStates("option_checked_empty", 0 , 0, STATE_CHECKABLE | STATE_CHECKED);
+      testStates("option_checked_empty", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
       testStates("option_checked_undefined", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
       testStates("option_checked_absent", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
 
       // test (menuitem) checkable and checked states, which are unsupported on this role
       testStates("menuitem_checked_true", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_mixed", 0, 0, (STATE_CHECKABLE | STATE_CHECKED | STATE_MIXED));
       testStates("menuitem_checked_false", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
--- a/accessible/tests/mochitest/test_nsIAccessibleImage.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleImage.html
@@ -110,17 +110,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       testThis("nonLinkedImage", "moz.png", 89, 38);
 
       // Test linked image
       var actionNamesArray = ["jump"];
       testThis("linkedImage", "moz.png", 89, 38, 1,
                actionNamesArray);
 
       // Image with long desc
-      var actionNamesArray = ["showlongdesc"];
+      actionNamesArray = ["showlongdesc"];
       testThis("longdesc", "moz.png", 89, 38, 1,
                actionNamesArray);
 
       // Image with invalid url in long desc
       testThis("invalidLongdesc", "moz.png", 89, 38, 0);
 
       // Image with click and long desc
       actionNamesArray = null;
--- a/accessible/tests/mochitest/text.js
+++ b/accessible/tests/mochitest/text.js
@@ -477,40 +477,40 @@ function testTextRange(aRange, aRangeDes
 }
 
 // //////////////////////////////////////////////////////////////////////////////
 // Private
 
 function testTextSuperHelper(aFuncName, aArgs) {
   // List of tests.
   if (aArgs[2] instanceof Array) {
-    var ids = (aArgs[0] instanceof Array) ? aArgs[0] : [ aArgs[0] ];
-    var boundaryType = aArgs[1];
-    var list = aArgs[2];
-    for (var i = 0; i < list.length; i++) {
-      var offset1 = list[i][0], offset2 = list[i][1];
-      var text = list[i][2], startOffset = list[i][3], endOffset = list[i][4];
-      var failureList = list[i][5];
-      for (var offset = offset1; offset <= offset2; offset++) {
-        for (var idIdx = 0; idIdx < ids.length; idIdx++) {
-          var id = ids[idIdx];
+    let ids = (aArgs[0] instanceof Array) ? aArgs[0] : [ aArgs[0] ];
+    let boundaryType = aArgs[1];
+    let list = aArgs[2];
+    for (let i = 0; i < list.length; i++) {
+      let offset1 = list[i][0], offset2 = list[i][1];
+      let text = list[i][2], startOffset = list[i][3], endOffset = list[i][4];
+      let failureList = list[i][5];
+      for (let offset = offset1; offset <= offset2; offset++) {
+        for (let idIdx = 0; idIdx < ids.length; idIdx++) {
+          let id = ids[idIdx];
 
-          var flagOk1 = kOk, flagOk2 = kOk, flagOk3 = kOk;
+          let flagOk1 = kOk, flagOk2 = kOk, flagOk3 = kOk;
           if (failureList) {
-            for (var fIdx = 0; fIdx < failureList.length; fIdx++) {
+            for (let fIdx = 0; fIdx < failureList.length; fIdx++) {
               if (offset == failureList[fIdx][0] && id == failureList[fIdx][1]) {
                 flagOk1 = failureList[fIdx][2];
                 flagOk2 = failureList[fIdx][3];
                 flagOk3 = failureList[fIdx][4];
                 break;
               }
             }
           }
 
-          var acc = getAccessible(id, nsIAccessibleText);
+          let acc = getAccessible(id, nsIAccessibleText);
           testTextHelper(id, offset, boundaryType,
                          text, startOffset, endOffset,
                          flagOk1, flagOk2, flagOk3,
                          acc[aFuncName], aFuncName + " ");
         }
       }
     }
     return;
@@ -518,35 +518,35 @@ function testTextSuperHelper(aFuncName, 
 
   // Test at single offset. List of IDs.
   var offset = aArgs[0];
   var boundaryType = aArgs[1];
   var text = aArgs[2];
   var startOffset = aArgs[3];
   var endOffset = aArgs[4];
   if (aArgs[5] instanceof Array) {
-    var ids = aArgs[5];
-    for (var i = 0; i < ids.length; i++) {
-      var acc = getAccessible(ids[i], nsIAccessibleText);
+    let ids = aArgs[5];
+    for (let i = 0; i < ids.length; i++) {
+      let acc = getAccessible(ids[i], nsIAccessibleText);
       testTextHelper(ids[i], offset, boundaryType,
                      text, startOffset, endOffset,
                      kOk, kOk, kOk,
                      acc[aFuncName], aFuncName + " ");
     }
 
     return;
   }
 
   // Each ID is tested separately.
-  for (var i = 5; i < aArgs.length; i = i + 4) {
-    var ID = aArgs[i];
-    var acc = getAccessible(ID, nsIAccessibleText);
-    var toDoFlag1 = aArgs[i + 1];
-    var toDoFlag2 = aArgs[i + 2];
-    var toDoFlag3 = aArgs[i + 3];
+  for (let i = 5; i < aArgs.length; i = i + 4) {
+    let ID = aArgs[i];
+    let acc = getAccessible(ID, nsIAccessibleText);
+    let toDoFlag1 = aArgs[i + 1];
+    let toDoFlag2 = aArgs[i + 2];
+    let toDoFlag3 = aArgs[i + 3];
 
     testTextHelper(ID, offset, boundaryType,
                    text, startOffset, endOffset,
                    toDoFlag1, toDoFlag2, toDoFlag3,
                    acc[aFuncName], aFuncName + " ");
   }
 }
 
--- a/accessible/tests/mochitest/text/test_atcaretoffset.html
+++ b/accessible/tests/mochitest/text/test_atcaretoffset.html
@@ -63,26 +63,26 @@
             this.mAtWrappedLineEnd = true;
           else
             this.mLine = nextLine;
         }
 
         return true;
       };
 
-      Object.defineProperty(this, "offset", { get: function() { return this.mOffset; }
+      Object.defineProperty(this, "offset", { get() { return this.mOffset; }
       });
 
-      Object.defineProperty(this, "offsetDescr", { get: function() {
+      Object.defineProperty(this, "offsetDescr", { get() {
           return this.mOffset + " offset (" + this.mLine.number + " line, " +
             (this.mOffset - this.mLine.start) + " offset on the line)";
         }
       });
 
-      Object.defineProperty(this, "tests", { get: function() {
+      Object.defineProperty(this, "tests", { get() {
           // Line boundary tests.
           var cLine = this.mLine;
           var pLine = cLine.prevLine;
           var ppLine = pLine.prevLine;
           var nLine = cLine.nextLine;
           var nnLine = nLine.nextLine;
 
           var lineTests = [
@@ -157,17 +157,17 @@
               this.mAtWrappedLineEnd ? this.offset : nextOffset,
               this.mAtWrappedLineEnd ? nextOffset : nextAfterNextOffset ]
           ];
 
           return lineTests.concat(wordTests.concat(charTests));
         }
       });
 
-      Object.defineProperty(this, "failures", { get: function() {
+      Object.defineProperty(this, "failures", { get() {
           if (this.mOffset == this.mLine.start)
             return this.mLine.lineStartFailures;
           if (this.mOffset == this.mLine.end)
             return this.mLine.lineEndFailures;
           return [];
         }
       });
 
@@ -176,133 +176,133 @@
       this.mAtWrappedLineEnd = false;
       this.mWord = this.mLine.firstWord;
     }
 
     /**
      * A line object. Allows to navigate by lines and by words.
      */
     function line(aWholeText, aLines, aIndex) {
-      Object.defineProperty(this, "prevLine", { get: function() {
+      Object.defineProperty(this, "prevLine", { get() {
           return new line(aWholeText, aLines, aIndex - 1);
         }
       });
-      Object.defineProperty(this, "nextLine", { get: function() {
+      Object.defineProperty(this, "nextLine", { get() {
           return new line(aWholeText, aLines, aIndex + 1);
         }
       });
 
-      Object.defineProperty(this, "start", { get: function() {
+      Object.defineProperty(this, "start", { get() {
           if (aIndex < 0)
             return 0;
 
           if (aIndex >= aLines.length)
             return aWholeText.length;
 
           return aLines[aIndex][2];
         }
       });
-      Object.defineProperty(this, "end", { get: function() {
+      Object.defineProperty(this, "end", { get() {
           if (aIndex < 0)
             return 0;
 
           if (aIndex >= aLines.length)
             return aWholeText.length;
 
           return aLines[aIndex][3];
         }
       });
 
-      Object.defineProperty(this, "number", { get: function() { return aIndex; }
+      Object.defineProperty(this, "number", { get() { return aIndex; }
       });
-      Object.defineProperty(this, "wholeText", { get: function() { return aWholeText; }
+      Object.defineProperty(this, "wholeText", { get() { return aWholeText; }
       });
       this.isFakeLine = function line_isFakeLine() {
         return aIndex < 0 || aIndex >= aLines.length;
       };
 
-      Object.defineProperty(this, "lastWord", { get: function() {
+      Object.defineProperty(this, "lastWord", { get() {
           if (aIndex < 0)
             return new word(this, [], -1);
           if (aIndex >= aLines.length)
             return new word(this, [], 0);
 
           var words = aLines[aIndex][4].words;
           return new word(this, words, words.length - 2);
         }
       });
-      Object.defineProperty(this, "firstWord", { get: function() {
+      Object.defineProperty(this, "firstWord", { get() {
           if (aIndex < 0)
             return new word(this, [], -1);
           if (aIndex >= aLines.length)
             return new word(this, [], 0);
 
           var words = aLines[aIndex][4].words;
           return new word(this, words, 0);
         }
       });
 
       this.isLastWord = function line_isLastWord(aWord) {
         var lastWord = this.lastWord;
         return lastWord.start == aWord.start && lastWord.end == aWord.end;
       };
 
-      Object.defineProperty(this, "lineStartFailures", { get: function() {
+      Object.defineProperty(this, "lineStartFailures", { get() {
           if (aIndex < 0 || aIndex >= aLines.length)
             return [];
 
           return aLines[aIndex][4].lsf || [];
         }
       });
-      Object.defineProperty(this, "lineEndFailures", { get: function() {
+      Object.defineProperty(this, "lineEndFailures", { get() {
           if (aIndex < 0 || aIndex >= aLines.length)
             return [];
 
           return aLines[aIndex][4].lef || [];
         }
       });
     }
 
     /**
      * A word object. Allows to navigate by words.
      */
     function word(aLine, aWords, aIndex) {
-      Object.defineProperty(this, "prevWord", { get: function() {
+      Object.defineProperty(this, "prevWord", { get() {
           if (aIndex >= 2)
             return new word(aLine, aWords, aIndex - 2);
 
           var prevLineLastWord = aLine.prevLine.lastWord;
           if (this.start == prevLineLastWord.start && !this.isFakeStartWord())
             return prevLineLastWord.prevWord;
           return prevLineLastWord;
         }
       });
-      Object.defineProperty(this, "nextWord", { get: function() {
+      Object.defineProperty(this, "nextWord", { get() {
           if (aIndex + 2 < aWords.length)
             return new word(aLine, aWords, aIndex + 2);
 
           var nextLineFirstWord = aLine.nextLine.firstWord;
           if (this.end == nextLineFirstWord.end && !this.isFakeEndWord())
             return nextLineFirstWord.nextWord;
           return nextLineFirstWord;
         }
       });
 
-      Object.defineProperty(this, "line", { get: function() { return aLine; } });
+      Object.defineProperty(this, "line", { get() { return aLine; } });
 
-      Object.defineProperty(this, "start", { get: function() {
+      Object.defineProperty(this, "start", { get() {
           if (this.isFakeStartWord())
             return 0;
 
           if (this.isFakeEndWord())
             return aLine.end;
            return aWords[aIndex];
         }
       });
-      Object.defineProperty(this, "end", { get: function() {
+      Object.defineProperty(this, "end", { get() {
           if (this.isFakeStartWord())
             return 0;
 
           return this.isFakeEndWord() ? aLine.end : aWords[aIndex + 1];
         }
       });
 
       this.toString = function word_toString() {
--- a/accessible/tests/mochitest/text/test_gettext.html
+++ b/accessible/tests/mochitest/text/test_gettext.html
@@ -52,17 +52,17 @@
       //
       // __o__n__e__w__o__r__d__\n
       //  0  1  2  3  4  5  6  7
       // __\n
       //  8
       // __t__w__o__ __w__o__r__d__s__\n
       //  9 10 11 12 13 14 15 16 17 18
 
-      var IDs = ["d3", "dbr3", "e3", "ebr3", "t3"];
+      IDs = ["d3", "dbr3", "e3", "ebr3", "t3"];
 
       testCharacterCount(IDs, 19);
 
       testText(IDs, 0, 19, "oneword\n\ntwo words\n");
       testText(IDs, 0, -1, "oneword\n\ntwo words\n");
 
       SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/text/test_wordboundary.html
+++ b/accessible/tests/mochitest/text/test_wordboundary.html
@@ -31,17 +31,17 @@
       testTextAfterOffset(ids, BOUNDARY_WORD_START,
                           [ [ 0, 5, "", 5, 5 ] ]);
       testTextAfterOffset(ids, BOUNDARY_WORD_END,
                           [ [ 0, 5, "", 5, 5 ] ]);
 
       // "hello "
       // __h__e__l__l__o__ __
       //  0  1  2  3  4  5  6
-      var ids = [ "i2", "d2", "e2", "t2" ];
+      ids = [ "i2", "d2", "e2", "t2" ];
       testTextBeforeOffset(ids, BOUNDARY_WORD_START,
                            [ [ 0, 6, "", 0, 0 ] ]);
       testTextBeforeOffset(ids, BOUNDARY_WORD_END,
                            [ [ 0, 5, "", 0, 0 ],
                              [ 6, 6, "hello", 0, 5 ]
                            ]);
 
       testTextAtOffset(ids, BOUNDARY_WORD_START,
--- a/accessible/tests/mochitest/textattrs/test_general.html
+++ b/accessible/tests/mochitest/textattrs/test_general.html
@@ -532,32 +532,32 @@
       testTextAttrs(ID, 39, attrs, defAttrs, 39, 44);
 
       // ////////////////////////////////////////////////////////////////////////
       // area18, "auto-generation text" tests
       ID = "area18";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       testDefaultTextAttrs(ID, defAttrs);
 
-      var attrs = {
+      attrs = {
         "auto-generated": "true"
       };
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 3);
       testTextAttrs(ID, 3, { }, defAttrs, 3, 7);
       testTextAttrs(ID, 7, attrs, defAttrs, 7, 8);
 
        // ////////////////////////////////////////////////////////////////////////
       // area19, "HTML5 mark tag" test
       // text enclosed in mark tag will have a different background color
       ID = "area19";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
 
       attrs = {};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 10);
-    
+
       tempElem = getNode(ID).firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "background-color": gComputedStyle.backgroundColor };
       testTextAttrs(ID, 11, attrs, defAttrs, 10, 17);
 
       attrs = {};
       testTextAttrs(ID, 18, attrs, defAttrs, 17, 28);
 
@@ -639,19 +639,19 @@
   </p>
   <!-- Green!*!RedNormal-->
   <p id="area5">
     <span style="color: green">Green</span>
     <img src="../moz.png" alt="image"/>
     <span style="color: red">Red</span>Normal
   </p>
   <p id="area6">
-    This <sup>sentence</sup> has the word 
-    <span style="vertical-align:super;">sentence</span> in 
-    <sub>superscript</sub> and 
+    This <sup>sentence</sup> has the word
+    <span style="vertical-align:super;">sentence</span> in
+    <sub>superscript</sub> and
     <span style="vertical-align:sub;">subscript</span> and
     <span style="vertical-align:20%;">superscript 20%</span> and
     <span style="vertical-align:-20%;">subscript 20%</span> and
     <span style="vertical-align:20px;">superscript 20px</span> and
     <span style="vertical-align:-20px;">subscript 20px</span>
   </p>
 
   <p lang="en" id="area7">
--- a/accessible/tests/mochitest/textcaret/test_general.html
+++ b/accessible/tests/mochitest/textcaret/test_general.html
@@ -98,17 +98,17 @@
             [ getNode("p2", p2Doc), 1 ],
             [ p2Doc, 0 ]
           ]
         },
         { // after 'b' (inside anchor)
           DOMPoint: [ getNode("p2_a", p2Doc).firstChild, 1 ],
           point: [ getNode("p2_a", p2Doc), 1 ],
           pointList: [
-            [ getNode("p2", p2Doc), 1 ] ,
+            [ getNode("p2", p2Doc), 1 ],
             [ p2Doc, 0 ]
           ]
         },
         { // before 'c' (after anchor)
           DOMPoint: [ getNode("p2", p2Doc).lastChild, 0 ],
           point: [ getNode("p2", p2Doc), 2 ],
           pointList: [ [ p2Doc, 0 ] ]
         },
--- a/accessible/tests/mochitest/textrange/test_selection.html
+++ b/accessible/tests/mochitest/textrange/test_selection.html
@@ -31,69 +31,69 @@
 
       testTextRange(a11yrange, "selection range #1", document, 3, document, 4);
 
       ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #1.");
       testTextRange(a11yrange, "cropped range #1", a, 0, a, 5);
 
       // the range is contained by the accessible
       range.selectNode(a);
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #2", p, 5, p, 6);
 
       ok(a11yrange.crop(getAccessible(p)), "Range failed to crop #2.");
       testTextRange(a11yrange, "cropped range #2", p, 5, p, 6);
 
       // the range starts before the accessible and ends inside it
       range.setStart(p, 0);
       range.setEndAfter(a.firstChild, 4);
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #3", p, 0, a, 4);
 
       ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #3.");
       testTextRange(a11yrange, "cropped range #3", a, 0, a, 4);
 
       // the range starts inside the accessible and ends after it
       range.setStart(a.firstChild, 1);
       range.setEndAfter(p);
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #4", a, 1, document, 4);
 
       ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #4.");
       testTextRange(a11yrange, "cropped range #4", a, 1, a, 5);
 
       // the range ends before the accessible
       range.setStart(p.firstChild, 0);
       range.setEnd(p.firstChild, 4);
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #5", p, 0, p, 4);
       ok(!a11yrange.crop(getAccessible(a)), "Crop #5 succeeded while it shouldn't");
 
       // the range starts after the accessible
       range.setStart(p.lastChild, 0);
       range.setEnd(p.lastChild, 4);
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #6", p, 6, p, 10);
 
       ok(!a11yrange.crop(getAccessible(a)), "Crop #6 succeeded while it shouldn't");
 
       // crop a range by a table
       range.selectNode(getNode("c2"));
-      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
-      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+      a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
 
       testTextRange(a11yrange, "selection range #7", document, 4, document, 5);
 
       ok(a11yrange.crop(getAccessible("table")), "Range failed to crop #7.");
       testTextRange(a11yrange, "cropped range #7", "c2", 5, "c2", 6);
 
       SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/tree/test_aria_globals.html
+++ b/accessible/tests/mochitest/tree/test_aria_globals.html
@@ -34,29 +34,29 @@
         "relevant"
       ];
 
       // Elements having ARIA global state or properties or referred by another
       // element must be accessible.
       ok(isAccessible("pawn"),
          "Must be accessible because referred by another element.");
 
-      for (var idx = 0; idx < globalIds.length; idx++) {
+      for (let idx = 0; idx < globalIds.length; idx++) {
         ok(isAccessible(globalIds[idx]),
            "Must be accessible becuase of aria-" + globalIds[idx] +
            " presence");
       }
 
       // Unfocusable elements, having ARIA global state or property with a valid
       // IDREF value, and an inherited presentation role. A generic accessible
       // is created (to prevent table cells text jamming).
       ok(!isAccessible("td_nothing", nsIAccessibleTableCell),
          "inherited presentation role takes a place");
 
-      for (var idx = 0; idx < globalIds.length; idx++) {
+      for (let idx = 0; idx < globalIds.length; idx++) {
         ok(isAccessible("td_" + globalIds[idx]),
            "Inherited presentation role must be ignored becuase of " +
            "aria-" + globalIds[idx] + " presence");
       }
 
       SimpleTest.finish();
     }
 
--- a/accessible/tests/mochitest/tree/test_aria_grid.html
+++ b/accessible/tests/mochitest/tree/test_aria_grid.html
@@ -168,17 +168,17 @@
         ]
       };
 
       testAccessibleTree("crazy_grid4", accTree);
 
       // ////////////////////////////////////////////////////////////////////////
       // grids that could contain whitespace accessibles but shouldn't.
 
-      var accTree =
+      accTree =
         { TREE_TABLE: [
           { ROW: [
             { GRID_CELL: [
               { TEXT_LEAF: [ ] }
             ] },
             { GRID_CELL: [
               { TEXT_LEAF: [ ] }
             ] },
--- a/accessible/tests/mochitest/tree/test_canvas.html
+++ b/accessible/tests/mochitest/tree/test_canvas.html
@@ -42,13 +42,13 @@ https://bugzilla.mozilla.org/show_bug.cg
   </pre>
 
   <canvas id="canvas" tabindex="0"><input type="checkbox"><input></canvas>
 
   <script type="text/javascript">
     var c = document.getElementById("canvas");
     var cxt = c.getContext("2d");
     cxt.fillStyle = "#005500";
-    cxt.fillRect(0,0,150,75);
+    cxt.fillRect(0, 0, 150, 75);
   </script>  
 
 </body>
 </html>
--- a/accessible/tests/mochitest/tree/test_list.html
+++ b/accessible/tests/mochitest/tree/test_list.html
@@ -117,29 +117,29 @@
               ] }
             ] }
           ] }
         ] };
 
       testAccessibleTree("list6", tree);
 
       // li having no display:list-item style
-      var tree =
+      tree =
         { LIST: [ // ul
           { LISTITEM: [ // li
             { TEXT_LEAF: [] },
           ] },
           { TEXT_LEAF: [] },
           { LISTITEM: [ // li
             { TEXT_LEAF: [] }
           ] }
         ] };
       testAccessibleTree("list7", tree);
 
-      var tree =
+      tree =
         { LIST: [ // ul
           { LISTITEM: [ // li
             { TEXT_LEAF: [] },
           ] },
           { LISTITEM: [ // li
             { TEXT_LEAF: [] }
           ] }
         ] };
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -401,21 +401,21 @@
 
       this.getID = function showHiddenElement_getID() {
         return "Show hidden ARIA owns referred element";
       };
     }
 
     function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList) {
       this.eventSeq = [];
-      for (var id of aIdList) {
+      for (let id of aIdList) {
         this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
       }
 
-      for (var id of aIdList) {
+      for (let id of aIdList) {
         this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
       }
       this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));
 
       this.invoke = function rearrangeARIAOwns_invoke() {
         getNode(aContainer).setAttribute("aria-owns", aAttr);
       };
 
--- a/accessible/tests/mochitest/treeupdate/test_bug1040735.html
+++ b/accessible/tests/mochitest/treeupdate/test_bug1040735.html
@@ -9,17 +9,17 @@
   <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">
     function doTest() {
       document.body.appendChild(document.getElementById("mw_a"));
-      setTimeout(function() { ok(true, "no crash and assertions"); SimpleTest.finish(); } , 0);
+      setTimeout(function() { ok(true, "no crash and assertions"); SimpleTest.finish(); }, 0);
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 
 <body>
--- a/accessible/tests/mochitest/treeview.js
+++ b/accessible/tests/mochitest/treeview.js
@@ -1,34 +1,34 @@
 /**
  * Helper method to start a single XUL tree test.
  */
 function loadXULTreeAndDoTest(aDoTestFunc, aTreeID, aTreeView) {
   var doTestFunc = aDoTestFunc ? aDoTestFunc : gXULTreeLoadContext.doTestFunc;
   var treeID = aTreeID ? aTreeID : gXULTreeLoadContext.treeID;
   var treeView = aTreeView ? aTreeView : gXULTreeLoadContext.treeView;
 
-  function loadXULTree(aTreeID, aTreeView) {
-    this.treeNode = getNode(aTreeID);
-
-    this.eventSeq = [
-      new invokerChecker(EVENT_REORDER, this.treeNode)
-    ];
-
-    this.invoke = function loadXULTree_invoke() {
-      this.treeNode.view = aTreeView;
-    };
-
-    this.getID = function loadXULTree_getID() {
-      return "Load XUL tree " + prettyName(aTreeID);
-    };
-  }
+  let treeNode = getNode(treeID);
 
   gXULTreeLoadContext.queue = new eventQueue();
-  gXULTreeLoadContext.queue.push(new loadXULTree(treeID, treeView));
+  gXULTreeLoadContext.queue.push({
+    treeNode,
+
+    eventSeq: [
+        new invokerChecker(EVENT_REORDER, treeNode)
+    ],
+
+    invoke() {
+      this.treeNode.view = treeView;
+    },
+
+    getID() {
+      return "Load XUL tree " + prettyName(treeID);
+    }
+  });
   gXULTreeLoadContext.queue.onFinish = function() {
     SimpleTest.executeSoon(doTestFunc);
     return DO_NOT_FINISH_TEST;
   };
   gXULTreeLoadContext.queue.invoke();
 }
 
 /**
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -27,16 +27,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   AutoCompletePopup: "resource://gre/modules/AutoCompletePopup.jsm",
   BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.jsm",
   BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
   BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
   BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
   ContentClick: "resource:///modules/ContentClick.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
+  CustomizableUI: "resource:///modules/CustomizableUI.jsm",
   DateTimePickerHelper: "resource://gre/modules/DateTimePickerHelper.jsm",
   DirectoryLinksProvider: "resource:///modules/DirectoryLinksProvider.jsm",
   ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
   Feeds: "resource:///modules/Feeds.jsm",
   FileUtils: "resource://gre/modules/FileUtils.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
   FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
   Integration: "resource://gre/modules/Integration.jsm",
@@ -1164,16 +1165,20 @@ BrowserGlue.prototype = {
       Services.tm.idleDispatchToMainThread(() => {
         JawsScreenReaderVersionCheck.onWindowsRestored();
       });
     }
 
     Services.tm.idleDispatchToMainThread(() => {
       LanguagePrompt.init();
     });
+
+    Services.tm.idleDispatchToMainThread(() => {
+      this._urlbarMatchBuckets.init();
+    });
   },
 
   /**
    * Use this function as an entry point to schedule tasks that need
    * to run once per session, at any arbitrary point in time.
    * This function will be called from an idle observer. Check the value of
    * LATE_TASKS_IDLE_TIME_SEC to see the current value for this idle
    * observer.
@@ -2336,16 +2341,59 @@ BrowserGlue.prototype = {
                         .add(promptCount);
     } catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
 
     if (willPrompt) {
       DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
     }
   },
 
+  // This keeps the browser.urlbar.matchBuckets pref updated depending on the
+  // placement of the searchbar.
+  _urlbarMatchBuckets: {
+    searchbarWidgetID: "search-container",
+    prefName: "browser.urlbar.matchBuckets",
+    searchbarPresentPrefValue: "general:5,suggestion:Infinity",
+
+    init() {
+      this._updatePref();
+      let checkWidget = widgetID => {
+        if (widgetID == this.searchbarWidgetID) {
+          this._updatePref();
+        }
+      };
+      CustomizableUI.addListener({
+        onWidgetAdded: checkWidget,
+        onWidgetRemoved: checkWidget,
+      });
+    },
+
+    _checkWidget(widgetID) {
+      if (widgetID == this.searchbarWidgetID) {
+        this._updatePref();
+      }
+    },
+
+    _updatePref() {
+      let pref = Services.prefs.getCharPref(this.prefName, "");
+      if (pref && pref != this.searchbarPresentPrefValue) {
+        // The user has customized the pref.  Don't touch it.
+        return;
+      }
+      let placement =
+        CustomizableUI.getPlacementOfWidget(this.searchbarWidgetID);
+      if (placement) {
+        Services.prefs.setCharPref(this.prefName,
+                                   this.searchbarPresentPrefValue);
+      } else {
+        Services.prefs.clearUserPref(this.prefName);
+      }
+    },
+  },
+
   // ------------------------------
   // public nsIBrowserGlue members
   // ------------------------------
 
   sanitize: function BG_sanitize(aParentWindow) {
     this._sanitizer.sanitize(aParentWindow);
   },
 
--- a/browser/components/tests/browser/browser.ini
+++ b/browser/components/tests/browser/browser.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 
 [browser_bug538331.js]
 skip-if = !updater
 reason = test depends on update channel
 [browser_contentpermissionprompt.js]
 [browser_default_bookmark_toolbar_visibility.js]
+[browser_urlbar_matchBuckets.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/tests/browser/browser_urlbar_matchBuckets.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Makes sure the browser.urlbar.matchBuckets pref is correct and updated when
+// the searchbar is added to or removed from the UI.
+
+const SEARCHBAR_WIDGET_ID = "search-container";
+const PREF_NAME = "browser.urlbar.matchBuckets";
+const SEARCHBAR_PRESENT_PREF_VALUE = "general:5,suggestion:Infinity";
+
+// nsBrowserGlue initializes the relevant code via idleDispatchToMainThread(),
+// so to make sure this test runs after that happens, first run a dummy task
+// that queues an idle callback.
+add_task(async function waitForIdle() {
+  await TestUtils.waitForIdle();
+});
+
+add_task(async function test() {
+  // Initial checks.
+  Assert.equal(CustomizableUI.getPlacementOfWidget(SEARCHBAR_WIDGET_ID), null,
+               "Sanity check: searchbar should not be placed initially");
+  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
+               "Sanity check: pref should be cleared initially");
+
+  // Add the searchbar.  The pref should be set.
+  let widgetPromise = promiseWidget("onWidgetAdded");
+  CustomizableUI.addWidgetToArea(SEARCHBAR_WIDGET_ID,
+                                 CustomizableUI.AREA_NAVBAR);
+  info("Waiting for searchbar to be added");
+  await widgetPromise;
+  Assert.equal(Services.prefs.getCharPref(PREF_NAME),
+               SEARCHBAR_PRESENT_PREF_VALUE,
+               "Pref should be set after adding searchbar");
+
+  // Remove the searchbar.  The pref should be cleared.
+  widgetPromise = promiseWidget("onWidgetRemoved");
+  CustomizableUI.removeWidgetFromArea(SEARCHBAR_WIDGET_ID);
+  info("Waiting for searchbar to be removed");
+  await widgetPromise;
+  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
+               "Pref should be cleared after removing searchbar");
+
+  // Customize the pref.
+  let customizedPref = "extension:1," + SEARCHBAR_PRESENT_PREF_VALUE;
+  Services.prefs.setCharPref(PREF_NAME, customizedPref);
+
+  // Add the searchbar again.  Since the pref is customized, it shouldn't be
+  // changed.
+  widgetPromise = promiseWidget("onWidgetAdded");
+  CustomizableUI.addWidgetToArea(SEARCHBAR_WIDGET_ID,
+                                 CustomizableUI.AREA_NAVBAR);
+  info("Waiting for searchbar to be added");
+  await widgetPromise;
+  Assert.equal(Services.prefs.getCharPref(PREF_NAME), customizedPref,
+               "Customized pref should remain same after adding searchbar");
+
+  // Remove the searchbar again.  Since the pref is customized, it shouldn't be
+  // changed.
+  widgetPromise = promiseWidget("onWidgetRemoved");
+  CustomizableUI.removeWidgetFromArea(SEARCHBAR_WIDGET_ID);
+  info("Waiting for searchbar to be removed");
+  await widgetPromise;
+  Assert.equal(Services.prefs.getCharPref(PREF_NAME), customizedPref,
+               "Customized pref should remain same after removing searchbar");
+
+  Services.prefs.clearUserPref(PREF_NAME);
+});
+
+function promiseWidget(observerName) {
+  return new Promise(resolve => {
+    let listener = {};
+    listener[observerName] = widgetID => {
+      if (widgetID == SEARCHBAR_WIDGET_ID) {
+        CustomizableUI.removeListener(listener);
+        executeSoon(resolve);
+      }
+    };
+    CustomizableUI.addListener(listener);
+  });
+}
--- a/browser/extensions/formautofill/content/manageDialog.js
+++ b/browser/extensions/formautofill/content/manageDialog.js
@@ -345,17 +345,17 @@ class ManageCreditCards extends ManageRe
    * Open the edit address dialog to create/edit a credit card.
    *
    * @param  {object} creditCard [optional]
    */
   async openEditDialog(creditCard) {
     // If master password is set, ask for password if user is trying to edit an
     // existing credit card.
     if (!creditCard || !this._hasMasterPassword || await MasterPassword.ensureLoggedIn(true)) {
-      this.prefWin.gSubDialog.open(EDIT_CREDIT_CARD_URL, null, creditCard);
+      this.prefWin.gSubDialog.open(EDIT_CREDIT_CARD_URL, "resizable=no", creditCard);
     }
   }
 
   /**
    * Get credit card display label. It should display masked numbers and the
    * cardholder's name, separated by a comma. If `showCreditCards` is set to
    * true, decrypted credit card numbers are shown instead.
    *
--- a/browser/extensions/formautofill/skin/shared/editAddress.css
+++ b/browser/extensions/formautofill/skin/shared/editAddress.css
@@ -4,16 +4,17 @@
 
 
 label > span {
   flex: 0 0 9.5em;
 }
 
 input,
 select {
+  flex: 1 0 auto;
   width: calc(50% - 9.5em);
   margin: 0;
 }
 
 #given-name-container,
 #additional-name-container,
 #address-level1-container,
 #postal-code-container,
--- a/browser/extensions/formautofill/skin/shared/editCreditCard.css
+++ b/browser/extensions/formautofill/skin/shared/editCreditCard.css
@@ -8,18 +8,21 @@ form {
 
 form > label,
 form > div {
   flex: 1 0 100%;
   align-self: center;
   margin: 0 0 0.5em !important;
 }
 
+input {
+  flex: 1 0 auto;
+}
+
 select {
-  flex: 0 0 5em;
   margin: 0;
   margin-inline-end: 0.7em;
 }
 
 label > span,
 div > span {
   flex: 0 0 9.5em;
 }
--- a/browser/extensions/formautofill/skin/shared/editDialog.css
+++ b/browser/extensions/formautofill/skin/shared/editDialog.css
@@ -44,16 +44,15 @@ textarea {
 button {
   padding-right: 10px;
   padding-left: 10px;
 }
 
 input,
 select {
   box-sizing: border-box;
-  flex: 1 0 auto;
 }
 
 #controls-container {
   flex: 0 1 100%;
   justify-content: end;
   margin: 1em 0 0;
 }
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -200,19 +200,20 @@ this.TestRunner = {
     if (!selectors.length) {
       throw "No selectors specified.";
     }
 
     // Set window type, default "navigator:browser"
     windowType = windowType || "navigator:browser";
     let browserWindow = Services.wm.getMostRecentWindow(windowType);
     // Scale for high-density displays
-    const scale = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIBaseWindow)
-                        .devicePixelsPerDesktopPixel;
+    const scale = Cc["@mozilla.org/gfx/screenmanager;1"]
+                    .getService(Ci.nsIScreenManager)
+                    .screenForRect(browserWindow.screenX, browserWindow.screenY, 1, 1)
+                    .defaultCSSScaleFactor;
 
     const windowLeft = browserWindow.screenX * scale;
     const windowTop = browserWindow.screenY * scale;
     const windowWidth = browserWindow.outerWidth * scale;
     const windowHeight = browserWindow.outerHeight * scale;
 
     let bounds;
     const rects = [];
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
@@ -8,16 +8,17 @@ this.EXPORTED_SYMBOLS = ["ControlCenter"
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://testing-common/BrowserTestUtils.jsm");
 Cu.import("resource:///modules/SitePermissions.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 let {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
 
 const RESOURCE_PATH = "browser/browser/tools/mozscreenshots/mozscreenshots/extension/mozscreenshots/browser/chrome/mozscreenshots/lib/controlCenter";
 const HTTP_PAGE = "http://example.com/";
 const HTTPS_PAGE = "https://example.com/";
 const PERMISSIONS_PAGE = "https://test1.example.com/";
 const HTTP_PASSWORD_PAGE = `http://test2.example.org/${RESOURCE_PATH}/password.html`;
@@ -254,15 +255,19 @@ async function loadPage(url) {
   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, url);
 }
 
 async function openIdentityPopup(expand) {
   let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
   let gBrowser = browserWindow.gBrowser;
   let { gIdentityHandler } = gBrowser.ownerGlobal;
   gIdentityHandler._identityPopup.hidePopup();
+  // Disable the popup shadow on OSX until we have figured out bug 1425253.
+  if (AppConstants.platform == "macosx") {
+    gIdentityHandler._identityPopup.style["-moz-window-shadow"] = "none";
+  }
   gIdentityHandler._identityBox.querySelector("#identity-icon").click();
   if (expand) {
     // give some time for opening to avoid weird style issues
     await new Promise((c) => setTimeout(c, 500));
     gIdentityHandler._identityPopup.querySelector("#identity-popup-security-expander").click();
   }
 }
--- a/devtools/client/locales/en-US/aboutdebugging.properties
+++ b/devtools/client/locales/en-US/aboutdebugging.properties
@@ -105,17 +105,17 @@ temporaryID = This WebExtension has a te
 # This string is displayed as a link next to the temporaryID message and leads
 # the user to MDN.
 temporaryID.learnMore = Learn more
 
 # LOCALIZATION NOTE (legacyExtensionWarning):
 # This string is displayed as a warning message when loading a temporary legacy extension.
 legacyExtensionWarning = This is a legacy extension, be aware that these are no longer fully supported.  Please read the linked documentation and then proceed with caution.
 
-# LOCALIZATION NOTE (temporaryID.learnMore):
+# LOCALIZATION NOTE (legacyExtensionWarning.learnMore):
 # This string is displayed as a link next to the legacyExtensionWarning message and leads
 # the user to https://wiki.mozilla.org/Add-ons/Future_of_Bootstrap.
 legacyExtensionWarning.learnMore = Learn more
 
 # LOCALIZATION NOTE (selectAddonFromFile2):
 # This string is displayed as the title of the file picker that appears when
 # the user clicks the 'Load Temporary Add-on' button
 selectAddonFromFile2 = Select Manifest File or Package (.xpi)
--- a/devtools/client/netmonitor/src/components/CookiesPanel.js
+++ b/devtools/client/netmonitor/src/components/CookiesPanel.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { L10N } = require("../utils/l10n");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 const { sortObjectKeys } = require("../utils/sort-utils");
 
 // Component
 const PropertiesView = createFactory(require("./PropertiesView"));
 
 const { div } = dom;
 
 const COOKIES_EMPTY_TEXT = L10N.getStr("cookiesEmptyText");
@@ -33,34 +34,29 @@ class CookiesPanel extends Component {
     return {
       connector: PropTypes.object.isRequired,
       openLink: PropTypes.func,
       request: PropTypes.object.isRequired,
     };
   }
 
   componentDidMount() {
-    this.maybeFetchCookies(this.props);
+    let { connector, request } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestCookies",
+      "responseCookies",
+    ]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchCookies(nextProps);
-  }
-
-  /**
-   * When switching to another request, lazily fetch request cookies
-   * from the backend. The panel will first be empty and then display the content.
-   */
-  maybeFetchCookies(props) {
-    if (props.request.requestCookiesAvailable && !props.request.requestCookies) {
-      props.connector.requestData(props.request.id, "requestCookies");
-    }
-    if (props.request.responseCookiesAvailable && !props.request.responseCookies) {
-      props.connector.requestData(props.request.id, "responseCookies");
-    }
+    let { connector, request } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestCookies",
+      "responseCookies",
+    ]);
   }
 
   /**
    * Mapping array to dict for TreeView usage.
    * Since TreeView only support Object(dict) format.
    *
    * @param {Object[]} arr - key-value pair array like cookies or params
    * @returns {Object}
--- a/devtools/client/netmonitor/src/components/CustomRequestPanel.js
+++ b/devtools/client/netmonitor/src/components/CustomRequestPanel.js
@@ -4,16 +4,17 @@
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { L10N } = require("../utils/l10n");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 const Actions = require("../actions/index");
 const { getSelectedRequest } = require("../selectors/index");
 const {
   getUrlQuery,
   parseQueryString,
   writeHeaderText,
 } = require("../utils/request-utils");
 
@@ -43,35 +44,31 @@ class CustomRequestPanel extends Compone
       removeSelectedCustomRequest: PropTypes.func.isRequired,
       request: PropTypes.object,
       sendCustomRequest: PropTypes.func.isRequired,
       updateRequest: PropTypes.func.isRequired,
     };
   }
 
   componentDidMount() {
-    this.maybeFetchPostData(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestHeaders",
+      "responseHeaders",
+      "requestPostData",
+    ]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchPostData(nextProps);
-  }
-
-  /**
-   * When switching to another request, lazily fetch request post data
-   * from the backend. The panel will first be empty and then display the content.
-   */
-  maybeFetchPostData(props) {
-    if (props.request.requestPostDataAvailable &&
-      (!props.request.requestPostData ||
-        !props.request.requestPostData.postData.text)) {
-      // This method will set `props.request.requestPostData`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "requestPostData");
-    }
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestHeaders",
+      "responseHeaders",
+      "requestPostData",
+    ]);
   }
 
   /**
    * Parse a text representation of a name[divider]value list with
    * the given name regex and divider character.
    *
    * @param {string} text - Text of list
    * @return {array} array of headers info {name, value}
--- a/devtools/client/netmonitor/src/components/HeadersPanel.js
+++ b/devtools/client/netmonitor/src/components/HeadersPanel.js
@@ -11,17 +11,20 @@ const {
   getFormattedIPAndPort,
   getFormattedSize,
 } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const {
   getHeadersURL,
   getHTTPStatusCodeURL,
 } = require("../utils/mdn-utils");
-const { writeHeaderText } = require("../utils/request-utils");
+const {
+  fetchNetworkUpdatePacket,
+  writeHeaderText,
+} = require("../utils/request-utils");
 const { sortObjectKeys } = require("../utils/sort-utils");
 
 // Components
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const MDNLink = createFactory(require("./MdnLink"));
 const PropertiesView = createFactory(require("./PropertiesView"));
 
 const { Rep } = REPS;
@@ -63,40 +66,34 @@ class HeadersPanel extends Component {
     this.state = {
       rawHeadersOpened: false,
     };
 
     this.getProperties = this.getProperties.bind(this);
     this.toggleRawHeaders = this.toggleRawHeaders.bind(this);
     this.renderSummary = this.renderSummary.bind(this);
     this.renderValue = this.renderValue.bind(this);
-    this.maybeFetchPostData = this.maybeFetchPostData.bind(this);
   }
 
   componentDidMount() {
-    this.maybeFetchPostData(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestHeaders",
+      "responseHeaders",
+      "requestPostData",
+    ]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchPostData(nextProps);
-  }
-
-  /**
-   * When switching to another request, lazily fetch request post data
-   * from the backend. The panel will first be empty and then display the content.
-   * Fetching post data is used for updating requestHeadersFromUploadStream section,
-   */
-  maybeFetchPostData(props) {
-    if (props.request.requestPostDataAvailable &&
-        (!props.request.requestPostData ||
-        !props.request.requestPostData.postData.text)) {
-      // This method will set `props.request.requestPostData`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "requestPostData");
-    }
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, [
+      "requestHeaders",
+      "responseHeaders",
+      "requestPostData",
+    ]);
   }
 
   getProperties(headers, title) {
     if (headers && headers.headers.length) {
       let headerKey = `${title} (${getFormattedSize(headers.headersSize, 3)})`;
       let propertiesResult = {
         [headerKey]:
           headers.headers.reduce((acc, { name, value }) =>
--- a/devtools/client/netmonitor/src/components/ParamsPanel.js
+++ b/devtools/client/netmonitor/src/components/ParamsPanel.js
@@ -4,17 +4,22 @@
 
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { L10N } = require("../utils/l10n");
-const { getUrlQuery, parseQueryString, parseFormData } = require("../utils/request-utils");
+const {
+  fetchNetworkUpdatePacket,
+  getUrlQuery,
+  parseQueryString,
+  parseFormData,
+} = require("../utils/request-utils");
 const { sortObjectKeys } = require("../utils/sort-utils");
 const { updateFormDataSections } = require("../utils/request-utils");
 const Actions = require("../actions/index");
 
 // Components
 const PropertiesView = createFactory(require("./PropertiesView"));
 
 const { div } = dom;
@@ -46,40 +51,28 @@ class ParamsPanel extends Component {
     };
   }
 
   constructor(props) {
     super(props);
   }
 
   componentDidMount() {
-    this.maybeFetchPostData(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["requestPostData"]);
     updateFormDataSections(this.props);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchPostData(nextProps);
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["requestPostData"]);
     updateFormDataSections(nextProps);
   }
 
   /**
-   * When switching to another request, lazily fetch request post data
-   * from the backend. The panel will first be empty and then display the content.
-   */
-  maybeFetchPostData(props) {
-    if (props.request.requestPostDataAvailable &&
-        (!props.request.requestPostData ||
-        !props.request.requestPostData.postData.text)) {
-      // This method will set `props.request.requestPostData`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "requestPostData");
-    }
-  }
-
-  /**
    * Mapping array to dict for TreeView usage.
    * Since TreeView only support Object(dict) format.
    * This function also deal with duplicate key case
    * (for multiple selection and query params with same keys)
    *
    * @param {Object[]} arr - key-value pair array like query or form params
    * @returns {Object} Rep compatible object
    */
--- a/devtools/client/netmonitor/src/components/RequestListColumnCookies.js
+++ b/devtools/client/netmonitor/src/components/RequestListColumnCookies.js
@@ -2,52 +2,46 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 const { div } = dom;
 
 class RequestListColumnCookies extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       item: PropTypes.object.isRequired,
     };
   }
 
   componentDidMount() {
-    this.maybeFetchRequestCookies(this.props);
+    let { item, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["requestCookies"]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchRequestCookies(nextProps);
+    let { item, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["requestCookies"]);
   }
 
   shouldComponentUpdate(nextProps) {
     let { requestCookies: currRequestCookies = { cookies: [] } } = this.props.item;
     let { requestCookies: nextRequestCookies = { cookies: [] } } = nextProps.item;
     currRequestCookies = currRequestCookies.cookies || currRequestCookies;
     nextRequestCookies = nextRequestCookies.cookies || nextRequestCookies;
     return currRequestCookies !== nextRequestCookies;
   }
 
-  /**
-   * Lazily fetch request cookies from the backend.
-   */
-  maybeFetchRequestCookies(props) {
-    if (props.item.requestCookiesAvailable && !props.requestCookies) {
-      props.connector.requestData(props.item.id, "requestCookies");
-    }
-  }
-
   render() {
     let { requestCookies = { cookies: [] } } = this.props.item;
     requestCookies = requestCookies.cookies || requestCookies;
     let requestCookiesLength = requestCookies.length > 0 ? requestCookies.length : "";
     return (
       div({
         className: "requests-list-column requests-list-cookies",
         title: requestCookiesLength
--- a/devtools/client/netmonitor/src/components/RequestListColumnSetCookies.js
+++ b/devtools/client/netmonitor/src/components/RequestListColumnSetCookies.js
@@ -2,52 +2,46 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 const { div } = dom;
 
 class RequestListColumnSetCookies extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       item: PropTypes.object.isRequired,
     };
   }
 
   componentDidMount() {
-    this.maybeFetchResponseCookies(this.props);
+    let { item, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["responseCookies"]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchResponseCookies(nextProps);
+    let { item, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["responseCookies"]);
   }
 
   shouldComponentUpdate(nextProps) {
     let { responseCookies: currResponseCookies = { cookies: [] } } = this.props.item;
     let { responseCookies: nextResponseCookies = { cookies: [] } } = nextProps.item;
     currResponseCookies = currResponseCookies.cookies || currResponseCookies;
     nextResponseCookies = nextResponseCookies.cookies || nextResponseCookies;
     return currResponseCookies !== nextResponseCookies;
   }
 
-  /**
-   * Lazily fetch response cookies from the backend.
-   */
-  maybeFetchResponseCookies(props) {
-    if (props.item.responseCookiesAvailable && !props.responseCookies) {
-      props.connector.requestData(props.item.id, "responseCookies");
-    }
-  }
-
   render() {
     let { responseCookies = { cookies: [] } } = this.props.item;
     responseCookies = responseCookies.cookies || responseCookies;
     let responseCookiesLength = responseCookies.length > 0 ? responseCookies.length : "";
     return (
       div({
         className: "requests-list-column requests-list-set-cookies",
         title: responseCookiesLength
--- a/devtools/client/netmonitor/src/components/RequestListContent.js
+++ b/devtools/client/netmonitor/src/components/RequestListContent.js
@@ -237,16 +237,17 @@ class RequestListContent extends Compone
       connector,
       columns,
       displayedRequests,
       firstRequestStartedMillis,
       onCauseBadgeMouseDown,
       onItemMouseDown,
       onSecurityIconMouseDown,
       onWaterfallMouseDown,
+      requestFilterTypes,
       scale,
       selectedRequest,
     } = this.props;
 
     return (
       div({ className: "requests-list-wrapper" },
         div({ className: "requests-list-table" },
           div({
@@ -267,16 +268,17 @@ class RequestListContent extends Compone
               isSelected: item.id === (selectedRequest && selectedRequest.id),
               key: item.id,
               onContextMenu: this.onContextMenu,
               onFocusedNodeChange: this.onFocusedNodeChange,
               onMouseDown: () => onItemMouseDown(item.id),
               onCauseBadgeMouseDown: () => onCauseBadgeMouseDown(item.cause),
               onSecurityIconMouseDown: () => onSecurityIconMouseDown(item.securityState),
               onWaterfallMouseDown: () => onWaterfallMouseDown(),
+              requestFilterTypes,
             }))
           )
         )
       )
     );
   }
 }
 
--- a/devtools/client/netmonitor/src/components/RequestListItem.js
+++ b/devtools/client/netmonitor/src/components/RequestListItem.js
@@ -2,17 +2,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const { propertiesEqual } = require("../utils/request-utils");
+const {
+  fetchNetworkUpdatePacket,
+  propertiesEqual,
+} = require("../utils/request-utils");
 const { RESPONSE_HEADERS } = require("../constants");
 
 // Components
 const RequestListColumnCause = createFactory(require("./RequestListColumnCause"));
 const RequestListColumnContentSize = createFactory(require("./RequestListColumnContentSize"));
 const RequestListColumnCookies = createFactory(require("./RequestListColumnCookies"));
 const RequestListColumnDomain = createFactory(require("./RequestListColumnDomain"));
 const RequestListColumnDuration = createFactory(require("./RequestListColumnDuration"));
@@ -52,23 +55,26 @@ const UPDATED_REQ_ITEM_PROPS = [
   "url",
   "remoteAddress",
   "cause",
   "contentSize",
   "transferredSize",
   "startedMillis",
   "totalTime",
   "requestCookies",
+  "requestHeaders",
   "responseCookies",
+  "responseHeaders",
 ];
 
 const UPDATED_REQ_PROPS = [
   "firstRequestStartedMillis",
   "index",
   "isSelected",
+  "requestFilterTypes",
   "waterfallWidth",
 ];
 
 /**
  * Render one row in the request list.
  */
 class RequestListItem extends Component {
   static get propTypes() {
@@ -81,24 +87,45 @@ class RequestListItem extends Component 
       firstRequestStartedMillis: PropTypes.number.isRequired,
       fromCache: PropTypes.bool,
       onCauseBadgeMouseDown: PropTypes.func.isRequired,
       onContextMenu: PropTypes.func.isRequired,
       onFocusedNodeChange: PropTypes.func,
       onMouseDown: PropTypes.func.isRequired,
       onSecurityIconMouseDown: PropTypes.func.isRequired,
       onWaterfallMouseDown: PropTypes.func.isRequired,
+      requestFilterTypes: PropTypes.string.isRequired,
       waterfallWidth: PropTypes.number,
     };
   }
 
   componentDidMount() {
     if (this.props.isSelected) {
       this.refs.listItem.focus();
     }
+
+    let { connector, item, requestFilterTypes } = this.props;
+    // Filtering XHR & WS require to lazily fetch requestHeaders & responseHeaders
+    if (requestFilterTypes.get("xhr") || requestFilterTypes.get("ws")) {
+      fetchNetworkUpdatePacket(connector.requestData, item, [
+        "requestHeaders",
+        "responseHeaders",
+      ]);
+    }
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let { connector, item, requestFilterTypes } = nextProps;
+    // Filtering XHR & WS require to lazily fetch requestHeaders & responseHeaders
+    if (requestFilterTypes.get("xhr") || requestFilterTypes.get("ws")) {
+      fetchNetworkUpdatePacket(connector.requestData, item, [
+        "requestHeaders",
+        "responseHeaders",
+      ]);
+    }
   }
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_REQ_ITEM_PROPS, this.props.item, nextProps.item) ||
       !propertiesEqual(UPDATED_REQ_PROPS, this.props, nextProps) ||
       this.props.columns !== nextProps.columns;
   }
 
--- a/devtools/client/netmonitor/src/components/ResponsePanel.js
+++ b/devtools/client/netmonitor/src/components/ResponsePanel.js
@@ -5,16 +5,17 @@
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { L10N } = require("../utils/l10n");
 const {
   decodeUnicodeBase64,
+  fetchNetworkUpdatePacket,
   formDataURI,
   getUrlBaseName,
 } = require("../utils/request-utils");
 const { Filters } = require("../utils/filter-predicates");
 
 // Components
 const PropertiesView = createFactory(require("./PropertiesView"));
 
@@ -52,36 +53,23 @@ class ResponsePanel extends Component {
       },
     };
 
     this.updateImageDimemsions = this.updateImageDimemsions.bind(this);
     this.isJSON = this.isJSON.bind(this);
   }
 
   componentDidMount() {
-    this.maybeFetchResponseContent(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["responseContent"]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchResponseContent(nextProps);
-  }
-
-  /**
-   * When switching to another request, lazily fetch response content
-   * from the backend. The Response Panel will first be empty and then
-   * display the content.
-   */
-  maybeFetchResponseContent(props) {
-    if (props.request.responseContentAvailable &&
-        (!props.request.responseContent ||
-         !props.request.responseContent.content)) {
-      // This method will set `props.request.responseContent.content`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "responseContent");
-    }
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["responseContent"]);
   }
 
   updateImageDimemsions({ target }) {
     this.setState({
       imageDimensions: {
         width: target.naturalWidth,
         height: target.naturalHeight,
       },
--- a/devtools/client/netmonitor/src/components/SecurityPanel.js
+++ b/devtools/client/netmonitor/src/components/SecurityPanel.js
@@ -6,17 +6,20 @@
 
 const {
   Component,
   createFactory,
 } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { L10N } = require("../utils/l10n");
-const { getUrlHost } = require("../utils/request-utils");
+const {
+  fetchNetworkUpdatePacket,
+  getUrlHost,
+} = require("../utils/request-utils");
 
 // Components
 const TreeViewClass = require("devtools/client/shared/components/tree/TreeView");
 const PropertiesView = createFactory(require("./PropertiesView"));
 
 const { div, input, span } = dom;
 const NOT_AVAILABLE = L10N.getStr("netmonitor.security.notAvailable");
 const ERROR_LABEL = L10N.getStr("netmonitor.security.error");
@@ -55,34 +58,23 @@ class SecurityPanel extends Component {
     return {
       connector: PropTypes.object.isRequired,
       openLink: PropTypes.func,
       request: PropTypes.object.isRequired,
     };
   }
 
   componentDidMount() {
-    this.maybeFetchSecurityInfo(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["securityInfo"]);
   }
 
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchSecurityInfo(nextProps);
-  }
-
-  /**
-   * When switching to another request, lazily fetch securityInfo
-   * from the backend. The Security Panel will first be empty and then
-   * display the content.
-   */
-  maybeFetchSecurityInfo(props) {
-    if (!props.request.securityInfo) {
-      // This method will set `props.request.securityInfo`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "securityInfo");
-    }
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["securityInfo"]);
   }
 
   renderValue(props, weaknessReasons = []) {
     const { member, value } = props;
 
     // Hide object summary
     if (typeof member.value === "object") {
       return null;
--- a/devtools/client/netmonitor/src/components/StackTracePanel.js
+++ b/devtools/client/netmonitor/src/components/StackTracePanel.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 const { div } = dom;
 
 // Components
 const StackTrace = createFactory(require("devtools/client/shared/components/StackTrace"));
 
 /**
  * This component represents a side panel responsible for
@@ -27,45 +28,29 @@ class StackTracePanel extends Component 
     };
   }
 
   /**
    * `componentDidMount` is called when opening the StackTracePanel
    * for the first time
    */
   componentDidMount() {
-    this.maybeFetchStackTrace(this.props);
+    let { request, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["stackTrace"]);
   }
 
   /**
    * `componentWillReceiveProps` is the only method called when
    * switching between two requests while this panel is displayed.
    */
   componentWillReceiveProps(nextProps) {
-    this.maybeFetchStackTrace(nextProps);
+    let { request, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["stackTrace"]);
   }
 
-  /**
-   * When switching to another request, lazily fetch stack-trace
-   * from the backend. This Panel will first be empty and then
-   * display the content.
-   */
-  maybeFetchStackTrace(props) {
-    // Fetch stack trace only if it's available and not yet
-    // on the client.
-    if (!props.request.stacktrace &&
-      props.request.cause.stacktraceAvailable) {
-      // This method will set `props.request.stacktrace`
-      // asynchronously and force another render.
-      props.connector.requestData(props.request.id, "stackTrace");
-    }
-  }
-
-  // Rendering
-
   render() {
     let {
       connector,
       openLink,
       request,
       sourceMapService,
     } = this.props;
 
--- a/devtools/client/netmonitor/src/components/StatisticsPanel.js
+++ b/devtools/client/netmonitor/src/components/StatisticsPanel.js
@@ -12,16 +12,17 @@ const PropTypes = require("devtools/clie
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { Chart } = require("devtools/client/shared/widgets/Chart");
 const { PluralForm } = require("devtools/shared/plural-form");
 const Actions = require("../actions/index");
 const { Filters } = require("../utils/filter-predicates");
 const { getSizeWithDecimals, getTimeWithDecimals } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 // Components
 const MDNLink = createFactory(require("./MdnLink"));
 
 const { button, div } = dom;
 const MediaQueryList = window.matchMedia("(min-width: 700px)");
 
 const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
@@ -58,16 +59,30 @@ class StatisticsPanel extends Component 
     this.responseIsFresh = this.responseIsFresh.bind(this);
     this.onLayoutChange = this.onLayoutChange.bind(this);
   }
 
   componentWillMount() {
     this.mdnLinkContainerNodes = new Map();
   }
 
+  componentDidMount() {
+    let { requests, connector } = this.props;
+    requests.forEach((request) => {
+      fetchNetworkUpdatePacket(connector.requestData, request, ["responseHeaders"]);
+    });
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let { requests, connector } = nextProps;
+    requests.forEach((request) => {
+      fetchNetworkUpdatePacket(connector.requestData, request, ["responseHeaders"]);
+    });
+  }
+
   componentDidUpdate(prevProps) {
     MediaQueryList.addListener(this.onLayoutChange);
 
     const { requests } = this.props;
     let ready = requests && requests.length && requests.every((req) =>
       req.contentSize !== undefined && req.mimeType && req.responseHeaders &&
       req.status !== undefined && req.totalTime !== undefined
     );
--- a/devtools/client/netmonitor/src/components/Toolbar.js
+++ b/devtools/client/netmonitor/src/components/Toolbar.js
@@ -13,19 +13,19 @@ const I = require("devtools/client/share
 
 const Actions = require("../actions/index");
 const { FILTER_SEARCH_DELAY, FILTER_TAGS } = require("../constants");
 const {
   getRecordingState,
   getTypeFilteredRequests,
   isNetworkDetailsToggleButtonDisabled,
 } = require("../selectors/index");
-
 const { autocompleteProvider } = require("../utils/filter-autocomplete-provider");
 const { L10N } = require("../utils/l10n");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 // Components
 const SearchBox = createFactory(require("devtools/client/shared/components/SearchBox"));
 
 const { button, div, input, label, span } = dom;
 
 // Localization
 const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
@@ -130,19 +130,22 @@ class Toolbar extends Component {
 
   autocompleteProvider(filter) {
     return autocompleteProvider(filter, this.props.filteredRequests);
   }
 
   onSearchBoxFocus() {
     let { connector, filteredRequests } = this.props;
 
-    // Fetch responseCookies for building autocomplete list
+    // Fetch responseCookies & responseHeaders for building autocomplete list
     filteredRequests.forEach((request) => {
-      connector.requestData(request.id, "responseCookies");
+      fetchNetworkUpdatePacket(connector.requestData, request, [
+        "responseCookies",
+        "responseHeaders",
+      ]);
     });
   }
 
   render() {
     let {
       toggleRecording,
       clearRequests,
       requestFilterTypes,
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -66,26 +66,28 @@ class FirefoxConnector {
   }
 
   async disconnect() {
     this.actions.batchReset();
 
     this.removeListeners();
 
     if (this.tabTarget) {
+      // Unregister `will-navigate` needs to be done before `this.timelineFront.destroy()`
+      // since this.tabTarget might be nullified after timelineFront.destroy().
+      this.tabTarget.off("will-navigate");
       // The timeline front wasn't initialized and started if the server wasn't
       // recent enough to emit the markers we were interested in.
       if (this.tabTarget.getTrait("documentLoadingMarkers") && this.timelineFront) {
         this.timelineFront.off("doc-loading", this.onDocLoadingMarker);
         await this.timelineFront.destroy();
       }
-
-      this.tabTarget.off("will-navigate");
       this.tabTarget = null;
     }
+
     this.webConsoleClient = null;
     this.timelineFront = null;
     this.dataProvider = null;
     this.panel = null;
   }
 
   pause() {
     this.removeListeners();
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -19,26 +19,24 @@ const { fetchHeaders } = require("../uti
  */
 class FirefoxDataProvider {
   constructor({webConsoleClient, actions}) {
     // Options
     this.webConsoleClient = webConsoleClient;
     this.actions = actions;
 
     // Internal properties
-    this.payloadQueue = [];
-    this.rdpRequestMap = new Map();
+    this.payloadQueue = new Map();
 
     // Map[key string => Promise] used by `requestData` to prevent requesting the same
     // request data twice.
     this.lazyRequestData = new Map();
 
     // Fetching data from the backend
     this.getLongString = this.getLongString.bind(this);
-    this.getRequestFromQueue = this.getRequestFromQueue.bind(this);
 
     // Event handlers
     this.onNetworkEvent = this.onNetworkEvent.bind(this);
     this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
   }
 
   /**
    * Add a new network request to application state.
@@ -67,33 +65,31 @@ class FirefoxDataProvider {
         cause,
 
         // Compatibility code to support Firefox 58 and earlier that always
         // send stack-trace immediately on networkEvent message.
         // FF59+ supports fetching the traces lazily via requestData.
         stacktrace: cause.stacktrace,
 
         fromCache,
-        fromServiceWorker},
-        true,
-      );
+        fromServiceWorker,
+      }, true);
     }
 
     emit(EVENTS.REQUEST_ADDED, id);
   }
 
   /**
    * Update a network request if it already exists in application state.
    *
    * @param {string} id request id
    * @param {object} data data payload will be updated to application state
    */
   async updateRequest(id, data) {
     let {
-      mimeType,
       responseContent,
       responseCookies,
       responseHeaders,
       requestCookies,
       requestHeaders,
       requestPostData,
     } = data;
 
@@ -101,17 +97,17 @@ class FirefoxDataProvider {
     let [
       responseContentObj,
       requestHeadersObj,
       responseHeadersObj,
       postDataObj,
       requestCookiesObj,
       responseCookiesObj,
     ] = await Promise.all([
-      this.fetchResponseContent(mimeType, responseContent),
+      this.fetchResponseContent(responseContent),
       this.fetchRequestHeaders(requestHeaders),
       this.fetchResponseHeaders(responseHeaders),
       this.fetchPostData(requestPostData),
       this.fetchRequestCookies(requestCookies),
       this.fetchResponseCookies(responseCookies),
     ]);
 
     let payload = Object.assign({},
@@ -119,50 +115,64 @@ class FirefoxDataProvider {
       responseContentObj,
       requestHeadersObj,
       responseHeadersObj,
       postDataObj,
       requestCookiesObj,
       responseCookiesObj
     );
 
-    this.pushRequestToQueue(id, payload);
+    if (this.actions.updateRequest) {
+      await this.actions.updateRequest(id, payload, true);
+    }
 
     return payload;
   }
 
-  async fetchResponseContent(mimeType, responseContent) {
+  async fetchResponseContent(responseContent) {
     let payload = {};
-    if (mimeType && responseContent && responseContent.content) {
+    if (responseContent && responseContent.content) {
       let { text } = responseContent.content;
       let response = await this.getLongString(text);
       responseContent.content.text = response;
       payload.responseContent = responseContent;
+
+      // Lock down responseContentAvailable once we fetch data from back-end.
+      // Using this as flag to prevent fetching arrived data again.
+      payload.responseContentAvailable = false;
     }
     return payload;
   }
 
   async fetchRequestHeaders(requestHeaders) {
     let payload = {};
     if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
       let headers = await fetchHeaders(requestHeaders, this.getLongString);
       if (headers) {
         payload.requestHeaders = headers;
       }
+
+      // Lock down requestHeadersAvailable once we fetch data from back-end.
+      // Using this as flag to prevent fetching arrived data again.
+      payload.requestHeadersAvailable = false;
     }
     return payload;
   }
 
   async fetchResponseHeaders(responseHeaders) {
     let payload = {};
     if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
       let headers = await fetchHeaders(responseHeaders, this.getLongString);
       if (headers) {
         payload.responseHeaders = headers;
       }
+
+      // Lock down responseHeadersAvailable once we fetch data from back-end.
+      // Using this as flag to prevent fetching arrived data again.
+      payload.responseHeadersAvailable = false;
     }
     return payload;
   }
 
   async fetchPostData(requestPostData) {
     let payload = {};
     if (requestPostData && requestPostData.postData) {
       let { text } = requestPostData.postData;
@@ -181,16 +191,42 @@ class FirefoxDataProvider {
 
       // Lock down requestPostDataAvailable once we fetch data from back-end.
       // Using this as flag to prevent fetching arrived data again.
       payload.requestPostDataAvailable = false;
     }
     return payload;
   }
 
+  async fetchRequestCookies(requestCookies) {
+    let payload = {};
+    if (requestCookies) {
+      let reqCookies = [];
+      // request store cookies in requestCookies or requestCookies.cookies
+      let cookies = requestCookies.cookies ?
+        requestCookies.cookies : requestCookies;
+      // make sure cookies is iterable
+      if (typeof cookies[Symbol.iterator] === "function") {
+        for (let cookie of cookies) {
+          reqCookies.push(Object.assign({}, cookie, {
+            value: await this.getLongString(cookie.value),
+          }));
+        }
+        if (reqCookies.length) {
+          payload.requestCookies = reqCookies;
+        }
+      }
+
+      // Lock down requestCookiesAvailable once we fetch data from back-end.
+      // Using this as flag to prevent fetching arrived data again.
+      payload.requestCookiesAvailable = false;
+    }
+    return payload;
+  }
+
   async fetchResponseCookies(responseCookies) {
     let payload = {};
     if (responseCookies) {
       let resCookies = [];
       // response store cookies in responseCookies or responseCookies.cookies
       let cookies = responseCookies.cookies ?
         responseCookies.cookies : responseCookies;
       // make sure cookies is iterable
@@ -207,103 +243,38 @@ class FirefoxDataProvider {
 
       // Lock down responseCookiesAvailable once we fetch data from back-end.
       // Using this as flag to prevent fetching arrived data again.
       payload.responseCookiesAvailable = false;
     }
     return payload;
   }
 
-  async fetchRequestCookies(requestCookies) {
-    let payload = {};
-    if (requestCookies) {
-      let reqCookies = [];
-      // request store cookies in requestCookies or requestCookies.cookies
-      let cookies = requestCookies.cookies ?
-        requestCookies.cookies : requestCookies;
-      // make sure cookies is iterable
-      if (typeof cookies[Symbol.iterator] === "function") {
-        for (let cookie of cookies) {
-          reqCookies.push(Object.assign({}, cookie, {
-            value: await this.getLongString(cookie.value),
-          }));
-        }
-        if (reqCookies.length) {
-          payload.requestCookies = reqCookies;
-        }
-      }
-
-      // Lock down requestCookiesAvailable once we fetch data from back-end.
-      // Using this as flag to prevent fetching arrived data again.
-      payload.requestCookiesAvailable = false;
-    }
-    return payload;
-  }
-
-  /**
-   * Access a payload item from payload queue.
-   *
-   * @param {string} id request id
-   * @return {boolean} return a queued payload item from queue.
-   */
-  getRequestFromQueue(id) {
-    return this.payloadQueue.find((item) => item.id === id);
-  }
-
   /**
    * Public API used by the Toolbox: Tells if there is still any pending request.
    *
    * @return {boolean} returns true if the payload queue is empty
    */
   isPayloadQueueEmpty() {
-    return this.payloadQueue.length === 0;
-  }
-
-  /**
-   * Return true if payload is ready (all data fetched from the backend)
-   *
-   * @param {string} id request id
-   * @return {boolean} return whether a specific networkEvent has been updated completely.
-   */
-  isRequestPayloadReady(id) {
-    let record = this.rdpRequestMap.get(id);
-    if (!record) {
-      return false;
-    }
-
-    let { payload } = this.getRequestFromQueue(id);
-
-    // The payload is ready when all values in the record are true.
-    // Note that we never fetch response header/cookies for request with security issues.
-    // Bug 1404917 should simplify this heuristic by making all these field be lazily
-    // fetched, only on-demand.
-    return record.requestHeaders && record.eventTimings &&
-      (record.responseHeaders || payload.securityState === "broken" ||
-        (!payload.status && payload.responseContentAvailable));
+    return this.payloadQueue.size === 0;
   }
 
   /**
    * Merge upcoming networkEventUpdate payload into existing one.
    *
-   * @param {string} id request id
+   * @param {string} id request actor id
    * @param {object} payload request data payload
    */
   pushRequestToQueue(id, payload) {
-    let request = this.getRequestFromQueue(id);
-    if (!request) {
-      this.payloadQueue.push({ id, payload });
-    } else {
-      // Merge upcoming networkEventUpdate payload into existing one
-      request.payload = Object.assign({}, request.payload, payload);
+    let payloadFromQueue = this.payloadQueue.get(id);
+    if (!payloadFromQueue) {
+      payloadFromQueue = {};
+      this.payloadQueue.set(id, payloadFromQueue);
     }
-  }
-
-  cleanUpQueue(id) {
-    this.payloadQueue = this.payloadQueue.filter(
-      request => request.id != id);
+    Object.assign(payloadFromQueue, payload);
   }
 
   /**
    * Fetches the network information packet from actor server
    *
    * @param {string} id request id
    * @return {object} networkInfo data packet
    */
@@ -327,38 +298,31 @@ class FirefoxDataProvider {
   }
 
   /**
    * The "networkEvent" message type handler.
    *
    * @param {string} type message type
    * @param {object} networkInfo network request information
    */
-  onNetworkEvent(type, networkInfo) {
+  async onNetworkEvent(type, networkInfo) {
     let {
       actor,
       cause,
       fromCache,
       fromServiceWorker,
       isXHR,
       request: {
         method,
         url,
       },
       startedDateTime,
     } = networkInfo;
 
-    // Create tracking record for this request.
-    this.rdpRequestMap.set(actor, {
-      requestHeaders: false,
-      responseHeaders: false,
-      eventTimings: false,
-    });
-
-    this.addRequest(actor, {
+    await this.addRequest(actor, {
       cause,
       fromCache,
       fromServiceWorker,
       isXHR,
       method,
       startedDateTime,
       url,
     });
@@ -368,126 +332,82 @@ class FirefoxDataProvider {
 
   /**
    * The "networkEventUpdate" message type handler.
    *
    * @param {string} type message type
    * @param {object} packet the message received from the server.
    * @param {object} networkInfo the network request information.
    */
-  onNetworkEventUpdate(type, data) {
+  async onNetworkEventUpdate(type, data) {
     let { packet, networkInfo } = data;
     let { actor } = networkInfo;
     let { updateType } = packet;
 
-    // When we pause and resume, we may receive `networkEventUpdate` for a request
-    // that started during the pause and we missed its `networkEvent`.
-    if (!this.rdpRequestMap.has(actor)) {
-      return;
-    }
-
     switch (updateType) {
-      case "requestHeaders":
-      case "responseHeaders":
-        this.requestPayloadData(actor, updateType);
-        break;
-      case "requestCookies":
-      case "responseCookies":
-      case "requestPostData":
-        // This field helps knowing when/if updateType property is available
-        // and can be requested via `requestData`
-        this.updateRequest(actor, { [`${updateType}Available`]: true });
-        break;
       case "securityInfo":
-        this.updateRequest(actor, { securityState: networkInfo.securityInfo });
+        this.pushRequestToQueue(actor, { securityState: networkInfo.securityInfo });
         break;
       case "responseStart":
-        this.updateRequest(actor, {
+        this.pushRequestToQueue(actor, {
           httpVersion: networkInfo.response.httpVersion,
           remoteAddress: networkInfo.response.remoteAddress,
           remotePort: networkInfo.response.remotePort,
           status: networkInfo.response.status,
           statusText: networkInfo.response.statusText,
           headersSize: networkInfo.response.headersSize
-        }).then(() => {
-          emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
         });
+        emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
         break;
       case "responseContent":
-        this.updateRequest(actor, {
+        this.pushRequestToQueue(actor, {
           contentSize: networkInfo.response.bodySize,
           transferredSize: networkInfo.response.transferredSize,
           mimeType: networkInfo.response.content.mimeType,
-          // This field helps knowing when/if responseContent property is available
-          // and can be requested via `requestData`
-          responseContentAvailable: true,
         });
         break;
       case "eventTimings":
         this.pushRequestToQueue(actor, { totalTime: networkInfo.totalTime });
-        this.requestPayloadData(actor, updateType);
+        await this._requestData(actor, updateType);
         break;
     }
 
+    // This available field helps knowing when/if updateType property is arrived
+    // and can be requested via `requestData`
+    this.pushRequestToQueue(actor, { [`${updateType}Available`]: true });
+
+    this.onPayloadDataReceived(actor);
+
     emit(EVENTS.NETWORK_EVENT_UPDATED, actor);
   }
 
   /**
-   * Wrapper method for requesting HTTP details data for the payload.
-   *
-   * It is specific to all requests done from `onNetworkEventUpdate`, for data that are
-   * immediately fetched whenever the data is available.
-   *
-   * All these requests are cached into `rdpRequestMap`. All requests related to a given
-   * actor will be collected in the same record.
-   *
-   * Once bug 1404917 is completed, we should no longer use this method.
-   * All request fields should be loaded only on-demand, via `requestData` method.
-   *
-   * @param {string} actor actor id (used as request id)
-   * @param {string} method identifier of the data we want to fetch
+   * Notify actions when messages from onNetworkEventUpdate are done, networkEventUpdate
+   * messages contain initial network info for each updateType and then we can invoke
+   * requestData to fetch its corresponded data lazily.
+   * Once all updateTypes of networkEventUpdate message are arrived, we flush merged
+   * request payload from pending queue and then update component.
    */
-  requestPayloadData(actor, method) {
-    let record = this.rdpRequestMap.get(actor);
+  async onPayloadDataReceived(actor) {
+    let payload = this.payloadQueue.get(actor) || {};
 
-    // If data has been already requested, do nothing.
-    if (record[method]) {
+    if (!payload.requestHeadersAvailable || !payload.requestCookiesAvailable ||
+        !payload.eventTimingsAvailable || !payload.responseContentAvailable) {
       return;
     }
 
-    let promise = this._requestData(actor, method);
-    promise.then(() => {
-      // Once we got the data toggle the Map item to `true` in order to
-      // make isRequestPayloadReady return `true` once all the data is fetched.
-      record[method] = true;
-      this.onPayloadDataReceived(actor, method, !record);
-    });
-  }
+    this.payloadQueue.delete(actor);
 
-  /**
-   * Executed when new data are received from the backend.
-   */
-  async onPayloadDataReceived(actor, type) {
-    // Notify actions when all the sync request from onNetworkEventUpdate are done,
-    // or, everytime requestData is called for fetching data lazily.
-    if (this.isRequestPayloadReady(actor)) {
-      let payloadFromQueue = this.getRequestFromQueue(actor).payload;
+    if (this.actions.updateRequest) {
+      await this.actions.updateRequest(actor, payload, true);
+    }
 
-      // Clean up
-      this.cleanUpQueue(actor);
-      this.rdpRequestMap.delete(actor);
-
-      if (this.actions.updateRequest) {
-        await this.actions.updateRequest(actor, payloadFromQueue, true);
-      }
-
-      // This event is fired only once per request, once all the properties are fetched
-      // from `onNetworkEventUpdate`. There should be no more RDP requests after this.
-      emit(EVENTS.PAYLOAD_READY, actor);
-    }
+    // This event is fired only once per request, once all the properties are fetched
+    // from `onNetworkEventUpdate`. There should be no more RDP requests after this.
+    emit(EVENTS.PAYLOAD_READY, actor);
   }
 
   /**
    * Public connector API to lazily request HTTP details from the backend.
    *
    * The method focus on:
    * - calling the right actor method,
    * - emitting an event to tell we start fetching some request data,
@@ -503,31 +423,30 @@ class FirefoxDataProvider {
     // the same data twice at the same time.
     let key = `${actor}-${method}`;
     let promise = this.lazyRequestData.get(key);
     // If a request is pending, reuse it.
     if (promise) {
       return promise;
     }
     // Fetch the data
-    promise = this._requestData(actor, method);
-    this.lazyRequestData.set(key, promise);
-    promise.then(async () => {
+    promise = this._requestData(actor, method).then(async (payload) => {
       // Remove the request from the cache, any new call to requestData will fetch the
       // data again.
-      this.lazyRequestData.delete(key, promise);
+      this.lazyRequestData.delete(key);
 
       if (this.actions.updateRequest) {
-        await this.actions.updateRequest(
-          actor,
-          this.getRequestFromQueue(actor).payload,
-          true,
-        );
+        await this.actions.updateRequest(actor, payload, true);
       }
+
+      return payload;
     });
+
+    this.lazyRequestData.set(key, promise);
+
     return promise;
   }
 
   /**
    * Internal helper used to request HTTP details from the backend.
    *
    * This is internal method that focus on:
    * - calling the right actor method,
@@ -552,17 +471,17 @@ class FirefoxDataProvider {
 
     let response = await new Promise((resolve, reject) => {
       // Do a RDP request to fetch data from the actor.
       if (typeof this.webConsoleClient[clientMethodName] === "function") {
         // Make sure we fetch the real actor data instead of cloned actor
         // e.g. CustomRequestPanel will clone a request with additional '-clone' actor id
         this.webConsoleClient[clientMethodName](actor.replace("-clone", ""), (res) => {
           if (res.error) {
-            console.error(res.message);
+            reject(new Error(res.message));
           }
           resolve(res);
         });
       } else {
         reject(new Error(`Error: No such client method '${clientMethodName}'!`));
       }
     });
 
@@ -576,22 +495,35 @@ class FirefoxDataProvider {
     return this[callbackMethodName](response);
   }
 
   /**
    * Handles additional information received for a "requestHeaders" packet.
    *
    * @param {object} response the message received from the server.
    */
-  onRequestHeaders(response) {
-    return this.updateRequest(response.from, {
+  async onRequestHeaders(response) {
+    let payload = await this.updateRequest(response.from, {
       requestHeaders: response
-    }).then(() => {
-      emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
     });
+    emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
+    return payload.requestHeaders;
+  }
+
+  /**
+   * Handles additional information received for a "responseHeaders" packet.
+   *
+   * @param {object} response the message received from the server.
+   */
+  async onResponseHeaders(response) {
+    let payload = await this.updateRequest(response.from, {
+      responseHeaders: response
+    });
+    emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
+    return payload.responseHeaders;
   }
 
   /**
    * Handles additional information received for a "requestCookies" packet.
    *
    * @param {object} response the message received from the server.
    */
   async onRequestCookies(response) {
@@ -615,35 +547,22 @@ class FirefoxDataProvider {
     return payload;
   }
 
   /**
    * Handles additional information received for a "securityInfo" packet.
    *
    * @param {object} response the message received from the server.
    */
-  onSecurityInfo(response) {
-    return this.updateRequest(response.from, {
+  async onSecurityInfo(response) {
+    let payload = await this.updateRequest(response.from, {
       securityInfo: response.securityInfo
-    }).then(() => {
-      emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
     });
-  }
-
-  /**
-   * Handles additional information received for a "responseHeaders" packet.
-   *
-   * @param {object} response the message received from the server.
-   */
-  onResponseHeaders(response) {
-    return this.updateRequest(response.from, {
-      responseHeaders: response
-    }).then(() => {
-      emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
-    });
+    emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
+    return payload.securityInfo;
   }
 
   /**
    * Handles additional information received for a "responseCookies" packet.
    *
    * @param {object} response the message received from the server.
    */
   async onResponseCookies(response) {
@@ -671,22 +590,22 @@ class FirefoxDataProvider {
     return payload.responseContent;
   }
 
   /**
    * Handles additional information received for a "eventTimings" packet.
    *
    * @param {object} response the message received from the server.
    */
-  onEventTimings(response) {
-    return this.updateRequest(response.from, {
+  async onEventTimings(response) {
+    let payload = await this.updateRequest(response.from, {
       eventTimings: response
-    }).then(() => {
-      emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
     });
+    emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
+    return payload.eventTimings;
   }
 
   /**
    * Handles information received for a "stackTrace" packet.
    *
    * @param {object} response the message received from the server.
    */
   async onStackTrace(response) {
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -68,18 +68,18 @@ const EVENTS = {
   UPDATING_REQUEST_COOKIES: "NetMonitor:NetworkEventUpdating:RequestCookies",
   RECEIVED_REQUEST_COOKIES: "NetMonitor:NetworkEventUpdated:RequestCookies",
 
   // When request post data begins and finishes receiving.
   UPDATING_REQUEST_POST_DATA: "NetMonitor:NetworkEventUpdating:RequestPostData",
   RECEIVED_REQUEST_POST_DATA: "NetMonitor:NetworkEventUpdated:RequestPostData",
 
   // When security information begins and finishes receiving.
-  UPDATING_SECURITY_INFO: "NetMonitor::NetworkEventUpdating:SecurityInfo",
-  RECEIVED_SECURITY_INFO: "NetMonitor::NetworkEventUpdated:SecurityInfo",
+  UPDATING_SECURITY_INFO: "NetMonitor:NetworkEventUpdating:SecurityInfo",
+  RECEIVED_SECURITY_INFO: "NetMonitor:NetworkEventUpdated:SecurityInfo",
 
   // When response headers begin and finish receiving.
   UPDATING_RESPONSE_HEADERS: "NetMonitor:NetworkEventUpdating:ResponseHeaders",
   RECEIVED_RESPONSE_HEADERS: "NetMonitor:NetworkEventUpdated:ResponseHeaders",
 
   // When response cookies begin and finish receiving.
   UPDATING_RESPONSE_COOKIES: "NetMonitor:NetworkEventUpdating:ResponseCookies",
   RECEIVED_RESPONSE_COOKIES: "NetMonitor:NetworkEventUpdated:ResponseCookies",
@@ -108,30 +108,33 @@ const UPDATE_PROPS = [
   "url",
   "remotePort",
   "remoteAddress",
   "status",
   "statusText",
   "httpVersion",
   "securityState",
   "securityInfo",
+  "securityInfoAvailable",
   "mimeType",
   "contentSize",
   "transferredSize",
   "totalTime",
   "eventTimings",
   "headersSize",
   "customQueryValue",
   "requestHeaders",
+  "requestHeadersAvailable",
   "requestHeadersFromUploadStream",
   "requestCookies",
   "requestCookiesAvailable",
   "requestPostData",
   "requestPostDataAvailable",
   "responseHeaders",
+  "responseHeadersAvailable",
   "responseCookies",
   "responseCookiesAvailable",
   "responseContent",
   "responseContentAvailable",
   "formDataSections",
   "stacktrace",
 ];
 
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -148,28 +148,41 @@ HarBuilder.prototype = {
       onContentLoad: -1,
       onLoad: -1
     };
 
     return timings;
   },
 
   buildRequest: async function (file) {
+    // When using HarAutomation, HarCollector will automatically fetch requestHeaders
+    // and requestCookies, but when we use it from netmonitor, FirefoxDataProvider
+    // should fetch it itself lazily, via requestData.
+
+    let requestHeaders = file.requestHeaders;
+    if (!requestHeaders && this._options.requestData) {
+      requestHeaders = await this._options.requestData(file.id, "requestHeaders");
+    }
+
+    let requestCookies = file.requestCookies;
+    if (!requestCookies && this._options.requestData) {
+      requestCookies = await this._options.requestData(file.id, "requestCookies");
+    }
+
     let request = {
       bodySize: 0
     };
-
     request.method = file.method;
     request.url = file.url;
     request.httpVersion = file.httpVersion || "";
-    request.headers = this.buildHeaders(file.requestHeaders);
+    request.headers = this.buildHeaders(requestHeaders);
     request.headers = this.appendHeadersPostData(request.headers, file);
-    request.cookies = this.buildCookies(file.requestCookies);
+    request.cookies = this.buildCookies(requestCookies);
     request.queryString = parseQueryString(getUrlQuery(file.url)) || [];
-    request.headersSize = file.requestHeaders.headersSize;
+    request.headersSize = requestHeaders.headersSize;
     request.postData = await this.buildPostData(file);
 
     if (request.postData && request.postData.text) {
       request.bodySize = request.postData.text.length;
     }
 
     return request;
   },
@@ -229,33 +242,37 @@ HarBuilder.prototype = {
         });
       });
     });
 
     return result;
   },
 
   buildPostData: async function (file) {
-    // When using HarAutomation, HarCollector will automatically fetch requestPostData,
-    // but when we use it from netmonitor, FirefoxDataProvider should fetch it itself
-    // lazily, via requestData.
+    // When using HarAutomation, HarCollector will automatically fetch requestPostData
+    // and requestHeaders, but when we use it from netmonitor, FirefoxDataProvider
+    // should fetch it itself lazily, via requestData.
     let requestPostData = file.requestPostData;
     let requestHeaders = file.requestHeaders;
     let requestHeadersFromUploadStream;
 
     if (!requestPostData && this._options.requestData) {
       let payload = await this._options.requestData(file.id, "requestPostData");
       requestPostData = payload.requestPostData;
       requestHeadersFromUploadStream = payload.requestHeadersFromUploadStream;
     }
 
     if (!requestPostData.postData.text) {
       return undefined;
     }
 
+    if (!requestHeaders && this._options.requestData) {
+      requestHeaders = await this._options.requestData(file.id, "requestHeaders");
+    }
+
     let postData = {
       mimeType: findValue(requestHeaders.headers, "content-type"),
       params: [],
       text: requestPostData.postData.text,
     };
 
     if (requestPostData.postDataDiscarded) {
       postData.comment = L10N.getStr("har.requestBodyNotIncluded");
@@ -283,32 +300,43 @@ HarBuilder.prototype = {
         }
       });
     }
 
     return postData;
   },
 
   buildResponse: async function (file) {
+    // When using HarAutomation, HarCollector will automatically fetch responseHeaders
+    // and responseCookies, but when we use it from netmonitor, FirefoxDataProvider
+    // should fetch it itself lazily, via requestData.
+
+    let responseHeaders = file.responseHeaders;
+    if (!responseHeaders && this._options.requestData) {
+      responseHeaders = await this._options.requestData(file.id, "responseHeaders");
+    }
+
+    let responseCookies = file.responseCookies;
+    if (!responseCookies && this._options.requestData) {
+      responseCookies = await this._options.requestData(file.id, "responseCookies");
+    }
+
     let response = {
       status: 0
     };
 
     // Arbitrary value if it's aborted to make sure status has a number
     if (file.status) {
       response.status = parseInt(file.status, 10);
     }
-
-    let responseHeaders = file.responseHeaders;
-
     response.statusText = file.statusText || "";
     response.httpVersion = file.httpVersion || "";
 
     response.headers = this.buildHeaders(responseHeaders);
-    response.cookies = this.buildCookies(file.responseCookies);
+    response.cookies = this.buildCookies(responseCookies);
     response.content = await this.buildContent(file);
 
     let headers = responseHeaders ? responseHeaders.headers : null;
     let headersSize = responseHeaders ? responseHeaders.headersSize : -1;
 
     response.redirectURL = findValue(headers, "Location");
     response.headersSize = headersSize;
 
--- a/devtools/client/netmonitor/src/har/test/browser.ini
+++ b/devtools/client/netmonitor/src/har/test/browser.ini
@@ -2,15 +2,14 @@
 tags = devtools
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 support-files =
   head.js
   html_har_post-data-test-page.html
   !/devtools/client/netmonitor/test/head.js
   !/devtools/client/framework/test/shared-head.js
-  !/devtools/client/netmonitor/test/shared-head.js
   !/devtools/client/netmonitor/test/html_simple-test-page.html
 
 [browser_net_har_copy_all_as_har.js]
 [browser_net_har_post_data.js]
 [browser_net_har_throttle_upload.js]
 [browser_net_har_post_data_on_get.js]
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
@@ -42,21 +42,23 @@ function* throttleUploadTest(actuallyThr
   info("sending throttle request");
   yield new Promise((resolve) => {
     connector.setPreferences(request, (response) => {
       resolve(response);
     });
   });
 
   // Execute one POST request on the page and wait till its done.
+  let onEventTimings = monitor.panelWin.once(EVENTS.RECEIVED_EVENT_TIMINGS);
   let wait = waitForNetworkEvents(monitor, 1);
   yield ContentTask.spawn(tab.linkedBrowser, { size }, function* (args) {
     content.wrappedJSObject.executeTest2(args.size);
   });
   yield wait;
+  yield onEventTimings;
 
   // Copy HAR into the clipboard (asynchronous).
   let contextMenu = new RequestListContextMenu({ connector });
   let jsonString = yield contextMenu.copyAllAsHar(getSortedRequests(store.getState()));
   let har = JSON.parse(jsonString);
 
   // Check out the HAR log.
   isnot(har.log, null, "The HAR log must exist");
--- a/devtools/client/netmonitor/src/utils/filter-autocomplete-provider.js
+++ b/devtools/client/netmonitor/src/utils/filter-autocomplete-provider.js
@@ -51,18 +51,18 @@ function getAutocompleteValuesForFlag(fl
       values = responseCookies.map(c => c.hasOwnProperty("domain") ?
           c.domain : request.urlDetails.host);
       break;
     case "is":
       values = ["cached", "from-cache", "running"];
       break;
     case "has-response-header":
       // Some requests not having responseHeaders..?
-      values = request.responseHeaders &&
-        request.responseHeaders.headers.map(h => h.name);
+      values = request.responseHeaders ?
+        request.responseHeaders.headers.map(h => h.name) : [];
       break;
     case "protocol":
       values.push(request.httpVersion);
       break;
     case "method":
     default:
       values.push(request[flag]);
   }
@@ -103,20 +103,21 @@ function getLastTokenFlagValues(lastToke
 
   let values = [];
   for (let request of requests) {
     values.push(...getAutocompleteValuesForFlag(flag, request));
   }
   values = [...new Set(values)];
 
   return values
+    .filter(value => value)
     .filter(value => {
-      if (typedFlagValue) {
-        let lowerTyped = typedFlagValue.toLowerCase(),
-          lowerValue = value.toLowerCase();
+      if (typedFlagValue && value) {
+        let lowerTyped = typedFlagValue.toLowerCase();
+        let lowerValue = value.toLowerCase();
         return lowerValue.includes(lowerTyped) && lowerValue !== lowerTyped;
       }
       return typeof value !== "undefined" && value !== "" && value !== "undefined";
     })
     .sort()
     .map(value => isNegativeFlag ? `-${flag}:${value}` : `${flag}:${value}`);
 }
 
--- a/devtools/client/netmonitor/src/utils/request-utils.js
+++ b/devtools/client/netmonitor/src/utils/request-utils.js
@@ -65,16 +65,40 @@ async function getFormDataSections(heade
 async function fetchHeaders(headers, getLongString) {
   for (let { value } of headers.headers) {
     headers.headers.value = await getLongString(value);
   }
   return headers;
 }
 
 /**
+ * Fetch network event update packets from actor server
+ * Expect to fetch a couple of network update packets from a given request.
+ *
+ * @param {function} requestData - requestData function for lazily fetch data
+ * @param {object} request - request object
+ * @param {array} updateTypes - a list of network event update types
+ */
+function fetchNetworkUpdatePacket(requestData, request, updateTypes) {
+  updateTypes.forEach((updateType) => {
+    // Only stackTrace will be handled differently
+    if (updateType === "stackTrace") {
+      if (request.cause.stacktraceAvailable && !request.stacktrace) {
+        requestData(request.id, updateType);
+      }
+      return;
+    }
+
+    if (request[`${updateType}Available`] && !request[updateType]) {
+      requestData(request.id, updateType);
+    }
+  });
+}
+
+/**
  * Form a data: URI given a mime type, encoding, and some text.
  *
  * @param {string} mimeType - mime type
  * @param {string} encoding - encoding to use; if not set, the
  *                            text will be base64-encoded.
  * @param {string} text - text of the URI.
  * @return {string} a data URI
  */
@@ -391,52 +415,59 @@ function getResponseHeader(item, header)
     }
   }
   return null;
 }
 
 /**
  * Extracts any urlencoded form data sections from a POST request.
  */
-function updateFormDataSections(props) {
+async function updateFormDataSections(props) {
   let {
     connector,
     request = {},
     updateRequest,
   } = props;
   let {
+    id,
     formDataSections,
     requestHeaders,
+    requestHeadersAvailable,
     requestHeadersFromUploadStream,
     requestPostData,
+    requestPostDataAvailable,
   } = request;
 
-  if (!formDataSections && requestHeaders &&
-      requestHeadersFromUploadStream && requestPostData) {
-    getFormDataSections(
+  if (requestHeadersAvailable && !requestHeaders) {
+    requestHeaders = await connector.requestData(id, "requestHeaders");
+  }
+
+  if (requestPostDataAvailable && !requestPostData) {
+    requestPostData = await connector.requestData(id, "requestPostData");
+  }
+
+  if (!formDataSections && requestHeaders && requestPostData &&
+      requestHeadersFromUploadStream) {
+    formDataSections = await getFormDataSections(
       requestHeaders,
       requestHeadersFromUploadStream,
       requestPostData,
       connector.getLongString,
-    ).then((newFormDataSections) => {
-      updateRequest(
-        request.id,
-        { formDataSections: newFormDataSections },
-        true,
-      );
-    });
+    );
+
+    updateRequest(request.id, { formDataSections }, true);
   }
 }
 
 /**
  * This helper function is used for additional processing of
  * incoming network update packets. It's used by Network and
  * Console panel reducers.
  */
-function processNetworkUpdates(request) {
+function processNetworkUpdates(request = {}) {
   let result = {};
   for (let [key, value] of Object.entries(request)) {
     if (UPDATE_PROPS.includes(key)) {
       result[key] = value;
 
       switch (key) {
         case "securityInfo":
           result.securityState = value.state;
@@ -455,16 +486,17 @@ function processNetworkUpdates(request) 
   }
   return result;
 }
 
 module.exports = {
   decodeUnicodeBase64,
   getFormDataSections,
   fetchHeaders,
+  fetchNetworkUpdatePacket,
   formDataURI,
   writeHeaderText,
   decodeUnicodeUrl,
   getAbbreviatedMimeType,
   getEndTime,
   getFormattedProtocol,
   getResponseHeader,
   getResponseTime,
--- a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
+++ b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
@@ -29,19 +29,21 @@ class RequestListContextMenu {
     let {
       id,
       isCustom,
       formDataSections,
       method,
       mimeType,
       httpVersion,
       requestHeaders,
+      requestHeadersAvailable,
       requestPostData,
       requestPostDataAvailable,
       responseHeaders,
+      responseHeadersAvailable,
       responseContentAvailable,
       url,
     } = selectedRequest;
     let {
       cloneSelectedRequest,
       openStatistics,
     } = this.props;
     let menu = [];
@@ -62,53 +64,63 @@ class RequestListContextMenu {
       visible: !!(selectedRequest && getUrlQuery(url)),
       click: () => this.copyUrlParams(url),
     });
 
     copySubmenu.push({
       id: "request-list-context-copy-post-data",
       label: L10N.getStr("netmonitor.context.copyPostData"),
       accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
+      // Menu item will be visible even if data hasn't arrived, so we need to check
+      // *Available property and then fetch data lazily once user triggers the action.
       visible: !!(selectedRequest && (requestPostDataAvailable || requestPostData)),
       click: () => this.copyPostData(id, formDataSections),
     });
 
     copySubmenu.push({
       id: "request-list-context-copy-as-curl",
       label: L10N.getStr("netmonitor.context.copyAsCurl"),
       accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
-      visible: !!selectedRequest,
+      // Menu item will be visible even if data hasn't arrived, so we need to check
+      // *Available property and then fetch data lazily once user triggers the action.
+      visible: !!(selectedRequest && (requestHeadersAvailable || requestHeaders)),
       click: () => this.copyAsCurl(id, url, method, requestHeaders, httpVersion),
     });
 
     copySubmenu.push({
       type: "separator",
       visible: copySubmenu.slice(0, 4).some((subMenu) => subMenu.visible),
     });
 
     copySubmenu.push({
       id: "request-list-context-copy-request-headers",
       label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
       accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
-      visible: !!(selectedRequest && requestHeaders && requestHeaders.rawHeaders),
-      click: () => this.copyRequestHeaders(requestHeaders.rawHeaders.trim()),
+      // Menu item will be visible even if data hasn't arrived, so we need to check
+      // *Available property and then fetch data lazily once user triggers the action.
+      visible: !!(selectedRequest && (requestHeadersAvailable || requestHeaders)),
+      click: () => this.copyRequestHeaders(id, requestHeaders),
     });
 
     copySubmenu.push({
       id: "response-list-context-copy-response-headers",
       label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
       accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
-      visible: !!(selectedRequest && responseHeaders && responseHeaders.rawHeaders),
-      click: () => this.copyResponseHeaders(responseHeaders.rawHeaders.trim()),
+      // Menu item will be visible even if data hasn't arrived, so we need to check
+      // *Available property and then fetch data lazily once user triggers the action.
+      visible: !!(selectedRequest && (responseHeadersAvailable || responseHeaders)),
+      click: () => this.copyResponseHeaders(id, responseHeaders),
     });
 
     copySubmenu.push({
       id: "request-list-context-copy-response",
       label: L10N.getStr("netmonitor.context.copyResponse"),
       accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
+      // Menu item will be visible even if data hasn't arrived, so we need to check
+      // *Available property and then fetch data lazily once user triggers the action.
       visible: !!(selectedRequest && responseContentAvailable),
       click: () => this.copyResponse(id),
     });
 
     copySubmenu.push({
       id: "request-list-context-copy-image-as-data-uri",
       label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
       accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
@@ -275,43 +287,56 @@ class RequestListContextMenu {
     }
     copyString(string);
   }
 
   /**
    * Copy a cURL command from the currently selected item.
    */
   async copyAsCurl(id, url, method, requestHeaders, httpVersion) {
+    if (!requestHeaders) {
+      requestHeaders = await this.props.connector.requestData(id, "requestHeaders");
+    }
     let { requestPostData } = await this.props.connector
       .requestData(id, "requestPostData");
     // Create a sanitized object for the Curl command generator.
     let data = {
       url,
       method,
       headers: requestHeaders.headers,
       httpVersion: httpVersion,
       postDataText: requestPostData ? requestPostData.postData.text : "",
     };
     copyString(Curl.generateCommand(data));
   }
 
   /**
    * Copy the raw request headers from the currently selected item.
    */
-  copyRequestHeaders(rawHeaders) {
+  async copyRequestHeaders(id, requestHeaders) {
+    if (!requestHeaders) {
+      requestHeaders = await this.props.connector.requestData(id, "requestHeaders");
+    }
+    let rawHeaders = requestHeaders.rawHeaders.trim();
+
     if (Services.appinfo.OS !== "WINNT") {
       rawHeaders = rawHeaders.replace(/\r/g, "");
     }
     copyString(rawHeaders);
   }
 
   /**
    * Copy the raw response headers from the currently selected item.
    */
-  copyResponseHeaders(rawHeaders) {
+  async copyResponseHeaders(id, responseHeaders) {
+    if (!responseHeaders) {
+      responseHeaders = await this.props.connector.requestData(id, "responseHeaders");
+    }
+    let rawHeaders = responseHeaders.rawHeaders.trim();
+
     if (Services.appinfo.OS !== "WINNT") {
       rawHeaders = rawHeaders.replace(/\r/g, "");
     }
     copyString(rawHeaders);
   }
 
   /**
    * Copy image as data uri.
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -1,15 +1,14 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   dropmarker.svg
   head.js
-  shared-head.js
   html_cause-test-page.html
   html_content-type-without-cache-test-page.html
   html_brotli-test-page.html
   html_image-tooltip-test-page.html
   html_cors-test-page.html
   html_custom-get-page.html
   html_cyrillic-test-page.html
   html_frame-test-page.html
--- a/devtools/client/netmonitor/test/browser_net_cause_redirect.js
+++ b/devtools/client/netmonitor/test/browser_net_cause_redirect.js
@@ -28,19 +28,21 @@ add_task(function* () {
   store.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
   yield performRequests(2, HSTS_SJS);
   yield wait;
 
   // Fetch stack-trace data from the backend and wait till
   // all packets are received.
-  let requests = getSortedRequests(store.getState());
-  yield Promise.all(requests.map(requestItem =>
-    connector.requestData(requestItem.id, "stackTrace")));
+  let requests = getSortedRequests(store.getState())
+    .filter((req) => !req.stacktrace)
+    .map((req) => connector.requestData(req.id, "stackTrace"));
+
+  yield Promise.all(requests);
 
   EXPECTED_REQUESTS.forEach(({status, hasStack}, i) => {
     let item = getSortedRequests(store.getState()).get(i);
 
     is(item.status, status, `Request #${i} has the expected status`);
 
     let { stacktrace } = item;
     let stackLen = stacktrace ? stacktrace.length : 0;
--- a/devtools/client/netmonitor/test/browser_net_copy_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_headers.js
@@ -27,18 +27,16 @@ add_task(function* () {
   let requestItem = getSortedRequests(store.getState()).get(0);
   let { method, httpVersion, status, statusText } = requestItem;
 
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[0]);
 
   let selectedRequest = getSelectedRequest(store.getState());
   is(selectedRequest, requestItem, "Proper request is selected");
-  ok(selectedRequest.requestHeaders, "Selected request should have request headers");
-  ok(selectedRequest.responseHeaders, "Selected request should have response headers");
 
   const EXPECTED_REQUEST_HEADERS = [
     `${method} ${SIMPLE_URL} ${httpVersion}`,
     "Host: example.com",
     "User-Agent: " + navigator.userAgent + "",
     "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
     "Accept-Language: " + navigator.languages.join(",") + ";q=0.5",
     "Accept-Encoding: gzip, deflate",
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js
+++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js
@@ -230,34 +230,35 @@ function testEscapeStringWin() {
 
   let newLines = "line1\r\nline2\r\nline3";
   is(CurlUtils.escapeStringWin(newLines),
     '"line1"^\u000d\u000A"line2"^\u000d\u000A"line3"',
     "Newlines should be escaped.");
 }
 
 function* createCurlData(selected, getLongString, requestData) {
-  let { url, method, httpVersion } = selected;
+  let { id, url, method, httpVersion } = selected;
 
   // Create a sanitized object for the Curl command generator.
   let data = {
     url,
     method,
     headers: [],
     httpVersion,
     postDataText: null
   };
 
+  let requestHeaders = yield requestData(id, "requestHeaders");
   // Fetch header values.
-  for (let { name, value } of selected.requestHeaders.headers) {
+  for (let { name, value } of requestHeaders.headers) {
     let text = yield getLongString(value);
     data.headers.push({ name: name, value: text });
   }
 
-  let { requestPostData } = yield requestData(selected.id, "requestPostData");
+  let { requestPostData } = yield requestData(id, "requestPostData");
   // Fetch the request payload.
   if (requestPostData) {
     let postData = requestPostData.postData.text;
     data.postDataText = yield getLongString(postData);
   }
 
   return data;
 }
--- a/devtools/client/netmonitor/test/browser_net_filter-01.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-01.js
@@ -312,18 +312,25 @@ add_task(function* () {
       yield waitUntil(() => requestsListStatus.title);
     }
 
     isnot(getSelectedRequest(store.getState()), undefined,
       "There should still be a selected item after filtering.");
     is(getSelectedIndex(store.getState()), 0,
       "The first item should be still selected after filtering.");
 
-    const items = getSortedRequests(store.getState());
-    const visibleItems = getDisplayedRequests(store.getState());
+    let items = getSortedRequests(store.getState());
+    let visibleItems;
+
+    // Filter results will be updated asynchronously, so we should wait until
+    // displayed requests reach final state.
+    yield waitUntil(() => {
+      visibleItems = getDisplayedRequests(store.getState());
+      return visibleItems.size === visibility.filter(e => e).length;
+    });
 
     is(items.size, visibility.length,
        "There should be a specific amount of items in the requests menu.");
     is(visibleItems.size, visibility.filter(e => e).length,
        "There should be a specific amount of visible items in the requests menu.");
 
     for (let i = 0; i < visibility.length; i++) {
       let itemId = items.get(i).id;
--- a/devtools/client/netmonitor/test/browser_net_filter-flags.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-flags.js
@@ -140,18 +140,30 @@ add_task(function* () {
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let {
     getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
+  function type(string) {
+    for (let ch of string) {
+      EventUtils.synthesizeKey(ch, {}, monitor.panelWin);
+    }
+  }
+
+  // Filtering network request will start fetching data lazily
+  // (fetching requestHeaders & responseHeaders for filtering WS & XHR)
+  // Lazy fetching will be executed when user focuses on filter box.
   function setFreetextFilter(value) {
-    store.dispatch(Actions.setRequestFilterText(value));
+    let filterBox = document.querySelector(".devtools-filterinput");
+    filterBox.focus();
+    filterBox.value = "";
+    type(value);
   }
 
   info("Starting test... ");
 
   let waitNetwork = waitForNetworkEvents(monitor, REQUESTS.length);
   loadCommonFrameScript();
   yield performRequestsInContent(REQUESTS);
   yield waitNetwork;
@@ -345,28 +357,44 @@ add_task(function* () {
     let requestItems = document.querySelectorAll(".request-list-item");
     for (let requestItem of requestItems) {
       requestItem.scrollIntoView();
       let requestsListStatus = requestItem.querySelector(".requests-list-status");
       EventUtils.sendMouseEvent({ type: "mouseover" }, requestsListStatus);
       yield waitUntil(() => requestsListStatus.title);
     }
 
-    const items = getSortedRequests(store.getState());
-    const visibleItems = getDisplayedRequests(store.getState());
+    let items = getSortedRequests(store.getState());
+    let visibleItems = getDisplayedRequests(store.getState());
+
+    // Filter results will be updated asynchronously, so we should wait until
+    // displayed requests reach final state.
+    yield waitUntil(() => {
+      visibleItems = getDisplayedRequests(store.getState());
+      return visibleItems.size === visibility.filter(e => e).length;
+    });
 
     is(items.size, visibility.length,
       "There should be a specific amount of items in the requests menu.");
     is(visibleItems.size, visibility.filter(e => e).length,
       "There should be a specific amount of visible items in the requests menu.");
 
     for (let i = 0; i < visibility.length; i++) {
       let itemId = items.get(i).id;
       let shouldBeVisible = !!visibility[i];
       let isThere = visibleItems.some(r => r.id == itemId);
+
+      // Filter results will be updated asynchronously, so we should wait until
+      // displayed requests reach final state.
+      yield waitUntil(() => {
+        visibleItems = getDisplayedRequests(store.getState());
+        isThere = visibleItems.some(r => r.id == itemId);
+        return isThere === shouldBeVisible;
+      });
+
       is(isThere, shouldBeVisible,
         `The item at index ${i} has visibility=${shouldBeVisible}`);
 
       if (shouldBeVisible) {
         let { method, url, data } = EXPECTED_REQUESTS[i];
         verifyRequestItemTarget(
           document,
           getDisplayedRequests(store.getState()),
--- a/devtools/client/netmonitor/test/browser_net_headers_sorted.js
+++ b/devtools/client/netmonitor/test/browser_net_headers_sorted.js
@@ -7,29 +7,36 @@
  * Tests if Request-Headers and Response-Headers are sorted in Headers tab.
  */
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SIMPLE_SJS);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  let {
+    getSortedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
+  let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
-
-  let wait = waitForNetworkEvents(monitor, 1);
   yield wait;
 
   wait = waitForDOM(document, ".headers-overview");
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   yield wait;
 
+  yield waitUntil(() => {
+    let request = getSortedRequests(store.getState()).get(0);
+    return request.requestHeaders && request.responseHeaders;
+  });
+
   info("Check if Request-Headers and Response-Headers are sorted");
   let expectedResponseHeaders = ["cache-control", "connection", "content-length",
                                  "content-type", "date", "expires", "foo-bar",
                                  "pragma", "server", "set-cookie"];
   let expectedRequestHeaders = ["Accept", "Accept-Encoding", "Accept-Language",
                                 "Cache-Control", "Connection", "Cookie", "Host",
                                 "Pragma", "Upgrade-Insecure-Requests", "User-Agent"];
 
--- a/devtools/client/netmonitor/test/browser_net_persistent_logs.js
+++ b/devtools/client/netmonitor/test/browser_net_persistent_logs.js
@@ -7,36 +7,46 @@
  * Tests if the network monitor leaks on initialization and sudden destruction.
  * You can also use this initialization format as a template for other tests.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SINGLE_GET_URL);
   info("Starting test... ");
 
-  let { document } = monitor.panelWin;
+  let { document, store, windowRequire } = monitor.panelWin;
+  let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
 
   Services.prefs.setBoolPref("devtools.netmonitor.persistlog", false);
 
   yield reloadAndWait();
 
+  // Using waitUntil in the test is necessary to ensure all requests are added correctly.
+  // Because reloadAndWait call may catch early uncaught requests from initNetMonitor, so
+  // the actual number of requests after reloadAndWait could be wrong since all requests
+  // haven't finished.
+  yield waitUntil(() => document.querySelectorAll(".request-list-item").length === 2);
   is(document.querySelectorAll(".request-list-item").length, 2,
     "The request list should have two items at this point.");
 
   yield reloadAndWait();
 
+  yield waitUntil(() => document.querySelectorAll(".request-list-item").length === 2);
   // Since the reload clears the log, we still expect two requests in the log
   is(document.querySelectorAll(".request-list-item").length, 2,
     "The request list should still have two items at this point.");
 
   // Now we toggle the persistence logs on
   Services.prefs.setBoolPref("devtools.netmonitor.persistlog", true);
 
   yield reloadAndWait();
 
+  yield waitUntil(() => document.querySelectorAll(".request-list-item").length === 4);
   // Since we togged the persistence logs, we expect four items after the reload
   is(document.querySelectorAll(".request-list-item").length, 4,
     "The request list should now have four items at this point.");
 
   Services.prefs.setBoolPref("devtools.netmonitor.persistlog", false);
   return teardown(monitor);
 
   /**
--- a/devtools/client/netmonitor/test/browser_net_raw_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_raw_headers.js
@@ -20,17 +20,17 @@ add_task(function* () {
   store.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 2);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
-  wait = waitForDOM(document, ".headers-overview");
+  wait = waitForDOM(document, "#headers-panel .tree-section", 2);
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   yield wait;
 
   wait = waitForDOM(document, ".raw-headers-container textarea", 2);
   EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersButton());
   yield wait;
 
--- a/devtools/client/netmonitor/test/browser_net_resend.js
+++ b/devtools/client/netmonitor/test/browser_net_resend.js
@@ -12,17 +12,16 @@ const ADD_HEADER = "Test-header: true";
 const ADD_UA_HEADER = "User-Agent: Custom-Agent";
 const ADD_POSTDATA = "&t3=t4";
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire, connector } = monitor.panelWin;
-  let { requestData } = connector;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let {
     getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
@@ -51,17 +50,25 @@ add_task(function* () {
   customItem = getSelectedRequest(store.getState());
   testCustomItemChanged(customItem, origItem);
 
   // send the new request
   wait = waitForNetworkEvents(monitor, 1);
   store.dispatch(Actions.sendCustomRequest(connector));
   yield wait;
 
-  let sentItem = getSelectedRequest(store.getState());
+  let sentItem;
+  // Testing sent request will require updated requestHeaders and requestPostData,
+  // we must wait for both properties get updated before starting test.
+  yield waitUntil(() => {
+    sentItem = getSelectedRequest(store.getState());
+    origItem = getSortedRequests(store.getState()).get(0);
+    return sentItem.requestHeaders && sentItem.requestPostData &&
+      origItem.requestHeaders && origItem.requestPostData;
+  });
 
   yield testSentRequest(sentItem, origItem);
 
   // Ensure the UI shows the new request, selected, and that the detail panel was closed.
   is(getSortedRequests(store.getState()).length, 3, "There are 3 requests shown");
   is(document.querySelector(".request-list-item.selected").getAttribute("data-id"),
     sentItem.id, "The sent request is selected");
   is(document.querySelector(".network-details-panel"), null,
@@ -159,23 +166,18 @@ add_task(function* () {
 
     let { headers } = data.requestHeaders;
     let hasHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_HEADER);
     ok(hasHeader, "new header added to sent request");
 
     let hasUAHeader = headers.some(h => `${h.name}: ${h.value}` == ADD_UA_HEADER);
     ok(hasUAHeader, "User-Agent header added to sent request");
 
-    let { requestPostData: clonedRequestPostData } = yield requestData(data.id,
-      "requestPostData");
-    let { requestPostData: origRequestPostData } = yield requestData(origData.id,
-      "requestPostData");
-
-    is(clonedRequestPostData.postData.text,
-      origRequestPostData.postData.text + ADD_POSTDATA,
+    is(data.requestPostData.postData.text,
+      origData.requestPostData.postData.text + ADD_POSTDATA,
       "post data added to sent request");
   }
 
   function type(string) {
     for (let ch of string) {
       EventUtils.synthesizeKey(ch, {}, monitor.panelWin);
     }
   }
--- a/devtools/client/netmonitor/test/browser_net_resend_cors.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_cors.js
@@ -10,16 +10,17 @@
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CORS_URL);
   info("Starting test... ");
 
   let { store, windowRequire, connector } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let {
+    getRequestById,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   let requestUrl = "http://test1.example.com" + CORS_SJS_PATH;
 
   info("Waiting for OPTIONS, then POST");
@@ -36,45 +37,68 @@ add_task(function* () {
   ITEMS.forEach((item, i) => {
     is(item.method, METHODS[i], `The ${item.method} request has the right method`);
     is(item.url, requestUrl, `The ${item.method} request has the right URL`);
   });
 
   // Resend both requests without modification. Wait for resent OPTIONS, then POST.
   // POST is supposed to have no preflight OPTIONS request this time (CORS is disabled)
   let onRequests = waitForNetworkEvents(monitor, 1);
-  ITEMS.forEach((item) => {
+  for (let item of ITEMS) {
     info(`Selecting the ${item.method} request`);
     store.dispatch(Actions.selectRequest(item.id));
 
+    // Wait for requestHeaders and responseHeaders are required when fetching data
+    // from back-end.
+    yield waitUntil(() => {
+      item = getRequestById(store.getState(), item.id);
+      return item.requestHeaders && item.responseHeaders;
+    });
+
+    let { size } = getSortedRequests(store.getState());
+
     info("Cloning the selected request into a custom clone");
     store.dispatch(Actions.cloneSelectedRequest());
 
     info("Sending the cloned request (without change)");
     store.dispatch(Actions.sendCustomRequest(connector));
-  });
+
+    yield waitUntil(() => getSortedRequests(store.getState()).size === size + 1);
+  }
 
   info("Waiting for both resent requests");
   yield onRequests;
 
   // Check the resent requests
   for (let i = 0; i < ITEMS.length; i++) {
     let item = ITEMS[i];
     is(item.method, METHODS[i], `The ${item.method} request has the right method`);
     is(item.url, requestUrl, `The ${item.method} request has the right URL`);
     is(item.status, 200, `The ${item.method} response has the right status`);
 
     if (item.method === "POST") {
-      // Force fetching lazy load data
-      let responseContent = yield connector.requestData(item.id, "responseContent");
-      let { requestPostData } = yield connector.requestData(item.id, "requestPostData");
+      is(item.method, "POST", `The ${item.method} request has the right method`);
 
-      is(requestPostData.postData.text, "post-data",
+      // Trigger responseContent update requires to wait until
+      // responseContentAvailable set true
+      yield waitUntil(() => {
+        item = getRequestById(store.getState(), item.id);
+        return item.responseContentAvailable;
+      });
+      yield connector.requestData(item.id, "responseContent");
+
+      // Wait for both requestPostData & responseContent payloads arrived.
+      yield waitUntil(() => {
+        item = getRequestById(store.getState(), item.id);
+        return item.responseContent && item.requestPostData;
+      });
+
+      is(item.requestPostData.postData.text, "post-data",
         "The POST request has the right POST data");
       // eslint-disable-next-line mozilla/no-cpows-in-tests
-      is(responseContent.content.text, "Access-Control-Allow-Origin: *",
+      is(item.responseContent.content.text, "Access-Control-Allow-Origin: *",
         "The POST response has the right content");
     }
   }
 
   info("Finishing the test");
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_resend_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_headers.js
@@ -8,17 +8,17 @@
  */
 
 add_task(function* () {
   let { monitor } = yield initNetMonitor(SIMPLE_SJS);
   info("Starting test... ");
 
   let { store, windowRequire, connector } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let { sendHTTPRequest } = connector;
+  let { requestData, sendHTTPRequest } = connector;
   let {
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   let requestUrl = SIMPLE_SJS;
   let requestHeaders = [
@@ -35,16 +35,29 @@ add_task(function* () {
     url: requestUrl,
     method: "POST",
     headers: requestHeaders,
     body: "Hello"
   });
   yield wait;
 
   let item = getSortedRequests(store.getState()).get(0);
+
+  ok(item.requestHeadersAvailable, "headers are available for lazily fetching");
+
+  if (item.requestHeadersAvailable && !item.requestHeaders) {
+    requestData(item.id, "requestHeaders");
+  }
+
+  // Wait until requestHeaders packet gets updated.
+  yield waitUntil(() => {
+    item = getSortedRequests(store.getState()).get(0);
+    return item.requestHeaders;
+  });
+
   is(item.method, "POST", "The request has the right method");
   is(item.url, requestUrl, "The request has the right URL");
 
   for (let { name, value } of item.requestHeaders.headers) {
     info(`Request header: ${name}: ${value}`);
   }
 
   function hasRequestHeader(name, value) {
--- a/devtools/client/netmonitor/test/browser_net_security-error.js
+++ b/devtools/client/netmonitor/test/browser_net_security-error.js
@@ -6,23 +6,22 @@
 /**
  * Test that Security details tab shows an error message with broken connections.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
 
   store.dispatch(Actions.batchEnable(false));
 
   info("Requesting a resource that has a certificate problem.");
 
-  let requestsDone = waitForSecurityBrokenNetworkEvent();
+  let requestsDone = waitForNetworkEvents(monitor, 1);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests(1, "https://nocert.example.com");
   });
   yield requestsDone;
 
   let securityInfoLoaded = waitForDOM(document, ".security-info-value");
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".network-details-panel-toggle"));
@@ -31,30 +30,9 @@ add_task(function* () {
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#security-tab"));
   yield securityInfoLoaded;
 
   let errormsg = document.querySelector(".security-info-value");
   isnot(errormsg.textContent, "", "Error message is not empty.");
 
   return teardown(monitor);
-
-  /**
-   * Returns a promise that's resolved once a request with security issues is
-   * completed.
-   */
-  function waitForSecurityBrokenNetworkEvent() {
-    let awaitedEvents = [
-      "UPDATING_REQUEST_HEADERS",
-      "RECEIVED_REQUEST_HEADERS",
-      "UPDATING_REQUEST_COOKIES",
-      "RECEIVED_REQUEST_COOKIES",
-      "UPDATING_EVENT_TIMINGS",
-      "RECEIVED_EVENT_TIMINGS",
-    ];
-
-    let promises = awaitedEvents.map((event) => {
-      return monitor.panelWin.once(EVENTS[event]);
-    });
-
-    return Promise.all(promises);
-  }
 });
--- a/devtools/client/netmonitor/test/browser_net_security-state.js
+++ b/devtools/client/netmonitor/test/browser_net_security-state.js
@@ -51,20 +51,17 @@ add_task(function* () {
    */
   function* performRequests() {
     function executeRequests(count, url) {
       return ContentTask.spawn(tab.linkedBrowser, {count, url}, function* (args) {
         content.wrappedJSObject.performRequests(args.count, args.url);
       });
     }
 
-    // waitForNetworkEvents does not work for requests with security errors as
-    // those only emit 9/13 events of a successful request.
-    let done = waitForSecurityBrokenNetworkEvent();
-
+    let done = waitForNetworkEvents(monitor, 1);
     info("Requesting a resource that has a certificate problem.");
     yield executeRequests(1, "https://nocert.example.com");
 
     // Wait for the request to complete before firing another request. Otherwise
     // the request with security issues interfere with waitForNetworkEvents.
     info("Waiting for request to complete.");
     yield done;
 
@@ -75,40 +72,19 @@ add_task(function* () {
     yield executeRequests(1, "http://test1.example.com" + CORS_SJS_PATH);
     yield done;
 
     done = waitForNetworkEvents(monitor, 1);
     info("Requesting a resource over HTTPS.");
     yield executeRequests(1, "https://example.com" + CORS_SJS_PATH);
     yield done;
 
-    done = waitForSecurityBrokenNetworkEvent();
+    done = waitForNetworkEvents(monitor, 1);
     info("Requesting a resource over HTTP to localhost.");
     yield executeRequests(1, "http://localhost" + CORS_SJS_PATH);
     yield done;
 
     const expectedCount = Object.keys(EXPECTED_SECURITY_STATES).length;
     is(store.getState().requests.requests.size,
       expectedCount,
       expectedCount + " events logged.");
   }
-
-  /**
-   * Returns a promise that's resolved once a request with security issues is
-   * completed.
-   */
-  function waitForSecurityBrokenNetworkEvent() {
-    let awaitedEvents = [
-      "UPDATING_REQUEST_HEADERS",
-      "RECEIVED_REQUEST_HEADERS",
-      "UPDATING_REQUEST_COOKIES",
-      "RECEIVED_REQUEST_COOKIES",
-      "UPDATING_EVENT_TIMINGS",
-      "RECEIVED_EVENT_TIMINGS",
-    ];
-
-    let promises = awaitedEvents.map((event) => {
-      return monitor.panelWin.once(EVENTS[event]);
-    });
-
-    return Promise.all(promises);
-  }
 });
--- a/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
+++ b/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
@@ -96,20 +96,16 @@ add_task(function* () {
   return teardown(monitor);
 
   /**
    * Returns a promise that's resolved once a request with security issues is
    * completed.
    */
   function waitForSecurityBrokenNetworkEvent() {
     let awaitedEvents = [
-      "UPDATING_REQUEST_HEADERS",
-      "RECEIVED_REQUEST_HEADERS",
-      "UPDATING_REQUEST_COOKIES",
-      "RECEIVED_REQUEST_COOKIES",
       "UPDATING_EVENT_TIMINGS",
       "RECEIVED_EVENT_TIMINGS",
     ];
 
     let promises = awaitedEvents.map((event) => {
       return monitor.panelWin.once(EVENTS[event]);
     });
 
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js
@@ -22,17 +22,17 @@ function test() {
   // number of response headers will vary depending on the platform.
   Services.prefs.setBoolPref("network.tcp.tcp_fastopen_enable", false);
 
   let { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
 
   initNetMonitor(SIMPLE_SJS).then(async ({ tab, monitor }) => {
     info("Starting test... ");
 
-    let { document, store, windowRequire } = monitor.panelWin;
+    let { document, store, windowRequire, connector } = monitor.panelWin;
     let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
     let { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
     let {
       getDisplayedRequests,
       getSelectedRequest,
       getSortedRequests,
     } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
@@ -342,15 +342,26 @@ function test() {
         "GET",
         SIMPLE_SJS,
         {
           time: true
         }
       );
     });
 
+    let wait = waitForNetworkEvents(monitor, 1);
     tab.linkedBrowser.reload();
+    await wait;
+
+    let requestItem = getSortedRequests(store.getState()).get(0);
+
+    if (!requestItem.requestHeaders) {
+      connector.requestData(requestItem.id, "requestHeaders");
+    }
+    if (!requestItem.responseHeaders) {
+      connector.requestData(requestItem.id, "responseHeaders");
+    }
 
     await Promise.all(promiseList);
     await teardown(monitor);
     finish();
   });
 }
--- a/devtools/client/netmonitor/test/browser_net_status-codes.js
+++ b/devtools/client/netmonitor/test/browser_net_status-codes.js
@@ -167,16 +167,19 @@ add_task(function* () {
 
   /**
    * A function that tests "Headers" panel contains correct information.
    */
   function* testHeaders(data, index) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
 
+    yield waitUntil(() => document.querySelector(
+      "#headers-panel .tabpanel-summary-value.textbox-input"));
+
     let panel = document.querySelector("#headers-panel");
     let summaryValues = panel.querySelectorAll(".tabpanel-summary-value.textbox-input");
     let { method, correctUri, details: { status, statusText } } = data;
 
     is(summaryValues[0].value, correctUri,
       "The url summary value is incorrect.");
     is(summaryValues[1].value, method, "The method summary value is incorrect.");
     is(panel.querySelector(".requests-list-status-icon").dataset.code, status,
--- a/devtools/client/netmonitor/test/browser_net_timing-division.js
+++ b/devtools/client/netmonitor/test/browser_net_timing-division.js
@@ -8,20 +8,16 @@
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let {
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
-
   store.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 2);
   // Timeout needed for having enough divisions on the time scale.
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests(2, null, 3000);
   });
   yield wait;
@@ -39,23 +35,15 @@ add_task(function* () {
 
   milDivs.forEach(div => info(`Millisecond division: ${div.textContent}`));
   secDivs.forEach(div => info(`Second division: ${div.textContent}`));
   minDivs.forEach(div => info(`Minute division: ${div.textContent}`));
 
   is(store.getState().requests.requests.size, 2,
      "There should be only two requests made.");
 
-  let firstRequest = getSortedRequests(store.getState()).get(0);
-  let lastRequest = getSortedRequests(store.getState()).get(1);
-
-  info("First request happened at: " +
-       firstRequest.responseHeaders.headers.find(e => e.name == "date").value);
-  info("Last request happened at: " +
-       lastRequest.responseHeaders.headers.find(e => e.name == "date").value);
-
   ok(secDivs.length,
      "There should be at least one division on the seconds time scale.");
   ok(secDivs[0].textContent.match(/\d+\.\d{2}\s\w+/),
      "The division on the seconds time scale looks legit.");
 
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_waterfall-click.js
+++ b/devtools/client/netmonitor/test/browser_net_waterfall-click.js
@@ -6,31 +6,27 @@
 /**
  * Test that clicking on the waterfall opens the timing sidebar panel.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   let { document } = monitor.panelWin;
 
-  yield performRequestsAndWait();
-
-  let wait = waitForDOM(document, "#timings-panel");
-  let timing = document.querySelectorAll(".requests-list-timings")[0];
+  let onAllEvents = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
+  yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
+    content.wrappedJSObject.performRequests();
+  });
+  yield onAllEvents;
 
   info("Clicking waterfall and waiting for panel update.");
-  EventUtils.synthesizeMouseAtCenter(timing, {}, monitor.panelWin);
+  let wait = waitForDOM(document, "#timings-panel");
+
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+    document.querySelectorAll(".requests-list-timings")[0]);
 
   yield wait;
 
   ok(document.querySelector("#timings-tab[aria-selected=true]"),
      "Timings tab is selected.");
 
   return teardown(monitor);
-
-  function* performRequestsAndWait() {
-    let onAllEvents = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
-    yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
-      content.wrappedJSObject.performRequests();
-    });
-    yield onAllEvents;
-  }
 });
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -1,40 +1,36 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* import-globals-from ../../framework/test/shared-head.js */
-/* import-globals-from shared-head.js */
 /* exported Toolbox, restartNetMonitor, teardown, waitForExplicitFinish,
    verifyRequestItemTarget, waitFor, testFilterButtons, loadCommonFrameScript,
    performRequestsInContent, waitForNetworkEvents, selectIndexAndWaitForSourceEditor */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js",
-  this);
-
 const {
   getFormattedIPAndPort,
   getFormattedTime,
 } = require("devtools/client/netmonitor/src/utils/format-utils");
 const {
   decodeUnicodeUrl,
   getFormattedProtocol,
   getUrlBaseName,
   getUrlHost,
   getUrlQuery,
   getUrlScheme,
 } = require("devtools/client/netmonitor/src/utils/request-utils");
+const { EVENTS } = require("devtools/client/netmonitor/src/constants");
 
 /* eslint-disable no-unused-vars, max-len */
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
 const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
 
 const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
@@ -220,33 +216,45 @@ function waitForAllRequestsFinished(moni
     window.on(EVENTS.PAYLOAD_READY, onTimings);
   });
 }
 
 let finishedQueue = {};
 let updatingTypes = [
   "NetMonitor:NetworkEventUpdating:RequestCookies",
   "NetMonitor:NetworkEventUpdating:ResponseCookies",
+  "NetMonitor:NetworkEventUpdating:RequestHeaders",
+  "NetMonitor:NetworkEventUpdating:ResponseHeaders",
+  "NetMonitor:NetworkEventUpdating:RequestPostData",
+  "NetMonitor:NetworkEventUpdating:ResponseContent",
+  "NetMonitor:NetworkEventUpdating:SecurityInfo",
+  "NetMonitor:NetworkEventUpdating:EventTimings",
 ];
 let updatedTypes = [
   "NetMonitor:NetworkEventUpdated:RequestCookies",
   "NetMonitor:NetworkEventUpdated:ResponseCookies",
+  "NetMonitor:NetworkEventUpdated:RequestHeaders",
+  "NetMonitor:NetworkEventUpdated:ResponseHeaders",
+  "NetMonitor:NetworkEventUpdated:RequestPostData",
+  "NetMonitor:NetworkEventUpdated:ResponseContent",
+  "NetMonitor:NetworkEventUpdated:SecurityInfo",
+  "NetMonitor:NetworkEventUpdated:EventTimings",
 ];
 
 // Start collecting all networkEventUpdate event when panel is opened.
 // removeTab() should be called once all corresponded RECEIVED_* events finished.
 function startNetworkEventUpdateObserver(panelWin) {
   updatingTypes.forEach((type) => panelWin.on(type, (event, actor) => {
-    let key = actor + "-" + event.replace("NetMonitor:NetworkEventUpdating:", "");
+    let key = actor + "-" + updatedTypes[updatingTypes.indexOf(event)];
     finishedQueue[key] = finishedQueue[key] ? finishedQueue[key] + 1 : 1;
   }));
 
   updatedTypes.forEach((type) => panelWin.on(type, (event, actor) => {
-    let key = actor + "-" + event.replace("NetMonitor:NetworkEventUpdated:", "");
-    finishedQueue[key]--;
+    let key = actor + "-" + event;
+    finishedQueue[key] = finishedQueue[key] ? finishedQueue[key] - 1 : -1;
   }));
 }
 
 function* waitForAllNetworkUpdateEvents() {
   function checkNetworkEventUpdateState() {
     for (let key in finishedQueue) {
       if (finishedQueue[key] > 0) {
         return false;
@@ -324,113 +332,74 @@ function restartNetMonitor(monitor, newU
 }
 
 function teardown(monitor) {
   info("Destroying the specified network monitor.");
 
   return Task.spawn(function* () {
     let tab = monitor.toolbox.target.tab;
 
-    // Ensure that there is no pending RDP requests related to payload request
-    // done from FirefoxDataProvider.
-    info("Wait for completion of all pending RDP requests...");
-    yield waitForExistingRequests(monitor);
     yield waitForAllNetworkUpdateEvents();
     info("All pending requests finished.");
 
     let onDestroyed = monitor.once("destroyed");
     yield removeTab(tab);
     yield onDestroyed;
   });
 }
 
 function waitForNetworkEvents(monitor, getRequests) {
   return new Promise((resolve) => {
     let panel = monitor.panelWin;
     let { getNetworkRequest } = panel.connector;
-    let progress = {};
-    let genericEvents = 0;
+    let networkEvent = 0;
     let payloadReady = 0;
-    let awaitedEventsToListeners = [
-      ["UPDATING_REQUEST_HEADERS", onGenericEvent],
-      ["RECEIVED_REQUEST_HEADERS", onGenericEvent],
-      ["UPDATING_RESPONSE_HEADERS", onGenericEvent],
-      ["RECEIVED_RESPONSE_HEADERS", onGenericEvent],
-      ["UPDATING_EVENT_TIMINGS", onGenericEvent],
-      ["RECEIVED_EVENT_TIMINGS", onGenericEvent],
-      ["PAYLOAD_READY", onPayloadReady]
-    ];
-    let expectedGenericEvents = awaitedEventsToListeners
-      .filter(([, listener]) => listener == onGenericEvent).length;
 
-    function initProgressForURL(url) {
-      if (progress[url]) {
-        return;
-      }
-      progress[url] = {};
-      awaitedEventsToListeners.forEach(function ([e]) {
-        progress[url][e] = 0;
-      });
-    }
-
-    function updateProgressForURL(url, event) {
-      initProgressForURL(url);
-      progress[url][Object.keys(EVENTS).find(e => EVENTS[e] == event)] = 1;
-    }
-
-    function onGenericEvent(event, actor) {
+    function onNetworkEvent(event, actor) {
       let networkInfo = getNetworkRequest(actor);
       if (!networkInfo) {
         // Must have been related to reloading document to disable cache.
         // Ignore the event.
         return;
       }
-      genericEvents++;
+      networkEvent++;
       maybeResolve(event, actor, networkInfo);
     }
 
     function onPayloadReady(event, actor) {
       let networkInfo = getNetworkRequest(actor);
       if (!networkInfo) {
         // Must have been related to reloading document to disable cache.
         // Ignore the event.
         return;
       }
-
       payloadReady++;
       maybeResolve(event, actor, networkInfo);
     }
 
     function maybeResolve(event, actor, networkInfo) {
       info("> Network event progress: " +
-        "Payload: " + payloadReady + "/" + getRequests + ", " +
-        "Generic: " + genericEvents + "/" + (getRequests * expectedGenericEvents) + ", " +
+        "NetworkEvent: " + networkEvent + "/" + getRequests + ", " +
+        "PayloadReady: " + payloadReady + "/" + getRequests + ", " +
         "got " + event + " for " + actor);
 
-      let url = networkInfo.request.url;
-      updateProgressForURL(url, event);
-
-      // Uncomment this to get a detailed progress logging (when debugging a test)
-      // info("> Current state: " + JSON.stringify(progress, null, 2));
-
-      // There are `expectedGenericEvents` updates which need to be fired for a request
-      // to be considered finished. The "requestPostData" packet isn't fired for non-POST
-      // requests.
-      if (payloadReady >= getRequests &&
-        genericEvents >= getRequests * expectedGenericEvents) {
-        awaitedEventsToListeners.forEach(([e, l]) => panel.off(EVENTS[e], l));
+      // Wait until networkEvent & payloadReady finish for each request.
+      if (networkEvent >= getRequests && payloadReady >= getRequests) {
+        panel.off(EVENTS.NETWORK_EVENT, onNetworkEvent);
+        panel.off(EVENTS.PAYLOAD_READY, onPayloadReady);
         executeSoon(resolve);
       }
     }
 
-    awaitedEventsToListeners.forEach(([e, l]) => panel.on(EVENTS[e], l));
+    panel.on(EVENTS.NETWORK_EVENT, onNetworkEvent);
+    panel.on(EVENTS.PAYLOAD_READY, onPayloadReady);
   });
 }
 
-function verifyRequestItemTarget(document, requestList, requestItem, method,
+function* verifyRequestItemTarget(document, requestList, requestItem, method,
                                  url, data = {}) {
   info("> Verifying: " + method + " " + url + " " + data.toSource());
 
   let visibleIndex = requestList.indexOf(requestItem);
 
   info("Visible index of item: " + visibleIndex);
 
   let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
deleted file mode 100644
--- a/devtools/client/netmonitor/test/shared-head.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/* exported EVENTS, waitForExistingRequests */
-
-"use strict";
-
-const { EVENTS } = require("devtools/client/netmonitor/src/constants");
-
-async function waitForExistingRequests(monitor) {
-  let { store } = monitor.panelWin;
-  function getRequests() {
-    return store.getState().requests.requests;
-  }
-  function areAllRequestsFullyLoaded() {
-    let requests = getRequests().valueSeq();
-    for (let request of requests) {
-      // Ignore cloned request as we don't lazily fetch data for them
-      // and have arbitrary number of field set.
-      if (request.id.includes("-clone")) {
-        continue;
-      }
-      // Do same check than FirefoxDataProvider.isRequestPayloadReady,
-      // in order to ensure there is no more pending payload requests to be done.
-      if (!request.requestHeaders || !request.eventTimings ||
-          (!request.responseHeaders && request.securityState !== "broken" &&
-          (!request.responseContentAvailable || request.status))) {
-        return false;
-      }
-    }
-    return true;
-  }
-  // If there is no request, we are good to go.
-  if (getRequests().size == 0) {
-    return;
-  }
-  while (!areAllRequestsFullyLoaded()) {
-    await monitor.panelWin.once(EVENTS.PAYLOAD_READY);
-  }
-}
--- a/devtools/client/styleeditor/test/browser.ini
+++ b/devtools/client/styleeditor/test/browser.ini
@@ -56,17 +56,16 @@ support-files =
   doc_xulpage.xul
   sync.html
   utf-16.css
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/inspector/shared/test/head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
-  !/devtools/client/netmonitor/test/shared-head.js
   !/devtools/client/responsive.html/test/browser/devices.json
   !/devtools/client/shared/test/test-actor-registry.js
   !/devtools/client/shared/test/test-actor.js
 
 [browser_styleeditor_add_stylesheet.js]
 [browser_styleeditor_autocomplete.js]
 [browser_styleeditor_autocomplete-disabled.js]
 [browser_styleeditor_bom.js]
--- a/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-cache.js
+++ b/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-cache.js
@@ -1,21 +1,16 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
-/* import-globals-from ../../netmonitor/test/shared-head.js */
-
 // A test to ensure Style Editor doesn't bybass cache when loading style sheet
 // contents (bug 978688).
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
-
 const TEST_URL = TEST_BASE_HTTP + "doc_uncached.html";
 
 add_task(function* () {
   // Disable rcwn to make cache behavior deterministic.
   yield pushPref("network.http.rcwn.enabled", false);
 
   info("Opening netmonitor");
   let tab = yield addTab("about:blank");
@@ -34,18 +29,16 @@ add_task(function* () {
   yield navigateTo(TEST_URL);
 
   info("Opening Style Editor");
   let styleeditor = yield toolbox.selectTool("styleeditor");
 
   info("Waiting for the source to be loaded.");
   yield styleeditor.UI.editors[0].getSourceEditor();
 
-  yield waitForExistingRequests(monitor);
-
   info("Checking Netmonitor contents.");
   let items = [];
   for (let item of getSortedRequests(store.getState())) {
     if (item.url.endsWith("doc_uncached.css")) {
       items.push(item);
     }
   }
 
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -160,17 +160,16 @@ support-files =
   test-subresource-security-error.js
   test-subresource-security-error.js^headers^
   test-trackingprotection-securityerrors.html
   test-webconsole-error-observer.html
   testscript.js
   !/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
   !/image/test/mochitest/blue.png
   !/devtools/client/framework/test/shared-head.js
-  !/devtools/client/netmonitor/test/shared-head.js
 [browser_console.js]
 skip-if = true # Bug 1406060
 [browser_console_addonsdk_loader_exception.js]
 skip-if = true # Bug 1406060
 [browser_console_clear_method.js]
 skip-if = true # Bug 1406060
 [browser_console_consolejsm_output.js]
 skip-if = true # Bug 1406060
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_netmonitor_shows_reqs_in_webconsole.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_netmonitor_shows_reqs_in_webconsole.js
@@ -59,11 +59,9 @@ async function testNetmonitor(toolbox) {
   await waitUntil(() => store.getState().requests.requests.size > 0);
 
   is(store.getState().requests.requests.size, 1,
     "Network request appears in the network panel");
 
   let item = getSortedRequests(store.getState()).get(0);
   is(item.method, "GET", "The attached method is correct.");
   is(item.url, TEST_PATH, "The attached url is correct.");
-
-  await waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
@@ -42,24 +42,39 @@ add_task(async function task() {
   let consoleReady = ui.jsterm.hud.once("network-request-payload-ready");
 
   // Expand network log
   urlNode.click();
 
   await consoleReady;
 
   info("network-request-payload-ready received");
-
   await testNetworkMessage(messageNode);
-
-  await waitForExistingRequests(monitor);
+  await waitForLazyRequests(toolbox);
 });
 
 async function testNetworkMessage(messageNode) {
   let headersTab = messageNode.querySelector("#headers-tab");
 
   ok(headersTab, "Headers tab is available");
 
   // Headers tab should be selected by default, so just check its content.
-  let headersContent = messageNode.querySelector(
-    "#headers-panel .headers-overview");
+  let headersContent;
+  await waitUntil(() => {
+    headersContent = messageNode.querySelector(
+      "#headers-panel .headers-overview");
+    return headersContent;
+  });
+
   ok(headersContent, "Headers content is available");
 }
+
+/**
+ * Wait until all lazily fetch requests in netmonitor get finsished.
+ * Otherwise test will be shutdown too early and cause failure.
+ */
+async function waitForLazyRequests(toolbox) {
+  let { ui } = toolbox.getCurrentPanel().hud;
+  let proxy = ui.jsterm.hud.proxy;
+  return waitUntil(() => {
+    return !proxy.networkDataProvider.lazyRequestData.size;
+  });
+}
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_expand.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_expand.js
@@ -242,16 +242,20 @@ function testEmptyTimings(messageNode) {
 }
 
 async function testTimings(messageNode) {
   let timingsTab = messageNode.querySelector("#timings-tab");
   ok(timingsTab, "Timings tab is available");
 
   // Select Timings tab and check the content.
   timingsTab.click();
+  await waitUntil(() => {
+    return !!messageNode.querySelector(
+      "#timings-panel .timings-container .timings-label");
+  });
   let timingsContent = messageNode.querySelector(
     "#timings-panel .timings-container .timings-label");
   ok(timingsContent, "Timings content is available");
   ok(timingsContent.textContent, "Timings text is available");
 }
 
 // Stack Trace
 
@@ -294,15 +298,19 @@ async function waitForRequestUpdates(too
   return new Promise(resolve => {
     ui.jsterm.hud.on("network-message-updated", () => {
       info("network-message-updated received");
       resolve();
     });
   });
 }
 
+/**
+ * Wait until all lazily fetch requests in netmonitor get finsished.
+ * Otherwise test will be shutdown too early and cause failure.
+ */
 async function waitForLazyRequests(toolbox) {
   let {ui} = toolbox.getCurrentPanel().hud;
   let proxy = ui.jsterm.hud.proxy;
   return waitUntil(() => {
     return !proxy.networkDataProvider.lazyRequestData.size;
   });
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_openinnet.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_openinnet.js
@@ -70,12 +70,9 @@ async function testNetmonitorLink(toolbo
   store.dispatch(actions.batchEnable(false));
 
   await waitUntil(() => {
     const selected = getSelectedRequest(store.getState());
     return selected && selected.url === url;
   });
 
   ok(true, "The attached url is correct.");
-
-  let monitor = toolbox.getCurrentPanel();
-  await waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js
@@ -1,27 +1,23 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 /* import-globals-from ../../../../framework/test/shared-head.js */
-/* import-globals-from ../../../../netmonitor/test/shared-head.js */
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 // Load the shared-head file first.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
-
 var {HUDService} = require("devtools/client/webconsole/hudservice");
 var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
 const DOCS_GA_PARAMS = "?utm_source=mozilla" +
                        "&utm_medium=firefox-console-errors" +
                        "&utm_campaign=default";
 
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
 registerCleanupFunction(function* () {
--- a/devtools/client/webconsole/test/browser_netmonitor_shows_reqs_in_webconsole.js
+++ b/devtools/client/webconsole/test/browser_netmonitor_shows_reqs_in_webconsole.js
@@ -1,18 +1,15 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
-
 const TEST_URI = "data:text/html;charset=utf8,Test that the netmonitor " +
                  "displays requests that have been recorded in the " +
                  "web console, even if the netmonitor hadn't opened yet.";
 
 const TEST_FILE = "test-network-request.html";
 const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/" +
                   "test/" + TEST_FILE;
 
@@ -63,22 +60,22 @@ function loadDocument(browser) {
   return deferred.promise;
 }
 
 function* testNetmonitor(toolbox) {
   let monitor = toolbox.getCurrentPanel();
 
   let { store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let { getSortedRequests } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+  let { getSortedRequests } =
+    windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   yield waitUntil(() => store.getState().requests.requests.size > 0);
 
-  is(store.getState().requests.requests.size, 1, "Network request appears in the network panel");
+  is(store.getState().requests.requests.size, 1,
+    "Network request appears in the network panel");
 
   let item = getSortedRequests(store.getState()).get(0);
   is(item.method, "GET", "The attached method is correct.");
   is(item.url, TEST_PATH, "The attached url is correct.");
-
-  yield waitForExistingRequests(monitor);
 }
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
@@ -1,41 +1,35 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from ../../netmonitor/test/shared-head.js */
-
 // Tests that network log messages bring up the network panel.
 
 "use strict";
 
 const TEST_NETWORK_REQUEST_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network-request.html";
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
-
 add_task(function* () {
   let finishedRequest = waitForFinishedRequest(({ request }) => {
     return request.url.endsWith("test-network-request.html");
   });
 
   const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   yield hud.ui.openNetworkPanel(request.actor);
   let toolbox = gDevTools.getToolbox(hud.target);
   is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
   let monitor = toolbox.getCurrentPanel();
 
   let { store, windowRequire } = monitor.panelWin;
-  let { getSelectedRequest } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+  let { getSelectedRequest } =
+    windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   let selected = getSelectedRequest(store.getState());
   is(selected.method, request.request.method,
      "The correct request is selected");
   is(selected.url, request.request.url,
      "The correct request is definitely selected");
-
-  yield waitForExistingRequests(monitor);
 });
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js
@@ -1,28 +1,23 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from ../../netmonitor/test/shared-head.js */
-
 // Tests that network log messages bring up the network panel and select the
 // right request even if it was previously filtered off.
 
 "use strict";
 
 const TEST_FILE_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network.html";
 const TEST_URI = "data:text/html;charset=utf8,<p>test file URI";
 
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/netmonitor/test/shared-head.js", this);
-
 var hud;
 
 add_task(function* () {
   let requests = [];
   let { browser } = yield loadTab(TEST_URI);
 
   yield pushPrefEnv();
   hud = yield openConsole();
@@ -64,18 +59,16 @@ add_task(function* () {
   is(selected.method, htmlRequest.request.method,
      "The correct request is selected");
   is(selected.url, htmlRequest.request.url,
      "The correct request is definitely selected");
 
   // All tests are done. Shutdown.
   HUDService.lastFinishedRequest.callback = null;
   htmlRequest = browser = requests = hud = null;
-
-  yield waitForExistingRequests(monitor);
 });
 
 function testMessages() {
   return waitForMessages({
     webconsole: hud,
     messages: [{
       text: "running network console logging tests",
       category: CATEGORY_WEBDEV,
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -119,22 +119,16 @@ KeyframeEffect::SetTarget(const Nullable
 
     RequestRestyle(EffectCompositor::RestyleType::Layer);
 
     nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
     if (mAnimation) {
       nsNodeUtils::AnimationAdded(mAnimation);
     }
   }
-
-  // If the new target frame is also oversized we should probably record that
-  // too so we have a more complete picture of the type of frame sizes we
-  // encounter, hence we reset the telemetry flag here.
-  mRecordedContentTooLarge = false;
-  mRecordedFrameSize = false;
 }
 
 void
 KeyframeEffect::SetIterationComposite(
   const IterationCompositeOperation& aIterationComposite,
   CallerType aCallerType)
 {
   // Ignore iterationComposite if the Web Animations API is not enabled,
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -2,33 +2,31 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/KeyframeEffectReadOnly.h"
 
 #include "FrameLayerBuilder.h"
-#include "gfxPrefs.h"
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions;
 #include "mozilla/dom/CSSPseudoElement.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/AnimValuesStyleRule.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/FloatingPoint.h" // For IsFinite
 #include "mozilla/GeckoStyleContext.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/ServoBindings.h"
-#include "mozilla/Telemetry.h"
 #include "mozilla/TypeTraits.h"
 #include "Layers.h" // For Layer
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContext
 #include "nsContentUtils.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled
@@ -1678,41 +1676,16 @@ KeyframeEffectReadOnly::HasGeometricProp
   return false;
 }
 
 void
 KeyframeEffectReadOnly::SetPerformanceWarning(
   nsCSSPropertyID aProperty,
   const AnimationPerformanceWarning& aWarning)
 {
-  if (aWarning.mType == AnimationPerformanceWarning::Type::ContentTooLarge &&
-      !mRecordedContentTooLarge) {
-    // ContentTooLarge stores: frameSize (w x h),
-    //                         relativeLimit (w x h), i.e. =~ viewport size *
-    //                                                          ratioLimit
-    //                         absoluteLimit (w x h)
-    MOZ_ASSERT(aWarning.mParams && aWarning.mParams->Length() >= 4,
-               "ContentTooLarge warning should have at least 4 parameters");
-    const nsTArray<int32_t>& params = aWarning.mParams.ref();
-    uint32_t frameSize = uint32_t(params[0]) * params[1];
-    float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
-    float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
-    double viewportWidth = viewportRatioX ? params[2] / viewportRatioX
-                                          : params[2];
-    double viewportHeight = viewportRatioY ? params[3] / viewportRatioY
-                                           : params[3];
-    double viewportSize = viewportWidth * viewportHeight;
-    uint32_t frameToViewport = frameSize / viewportSize * 100.0;
-    Telemetry::Accumulate(
-      Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_FRAME_SIZE, frameSize);
-    Telemetry::Accumulate(
-      Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_PERCENTAGE, frameToViewport);
-    mRecordedContentTooLarge = true;
-  }
-
   for (AnimationProperty& property : mProperties) {
     if (property.mProperty == aProperty &&
         (!property.mPerformanceWarning ||
          *property.mPerformanceWarning != aWarning)) {
       property.mPerformanceWarning = Some(aWarning);
 
       nsAutoString localizedString;
       if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
@@ -1720,24 +1693,16 @@ KeyframeEffectReadOnly::SetPerformanceWa
         nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
       }
       return;
     }
   }
 }
 
-void
-KeyframeEffectReadOnly::RecordFrameSizeTelemetry(uint32_t aPixelArea) {
-  if (!mRecordedFrameSize) {
-    Telemetry::Accumulate(Telemetry::ASYNC_ANIMATION_FRAME_SIZE, aPixelArea);
-    mRecordedFrameSize = true;
-  }
-}
-
 already_AddRefed<nsStyleContext>
 KeyframeEffectReadOnly::CreateStyleContextForAnimationValue(
   nsCSSPropertyID aProperty,
   const AnimationValue& aValue,
   GeckoStyleContext* aBaseStyleContext)
 {
   MOZ_ASSERT(aBaseStyleContext,
              "CreateStyleContextForAnimationValue needs to be called "
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -249,19 +249,16 @@ public:
   // Associates a warning with the animated property on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(
     nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
-  // Record telemetry about the size of the content being animated.
-  void RecordFrameSizeTelemetry(uint32_t aPixelArea);
-
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   template<typename StyleType>
   void CalculateCumulativeChangeHint(StyleType* aStyleContext);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
   // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
@@ -417,25 +414,16 @@ protected:
   nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>
     mBaseStyleValuesForServo;
 
   // True if this effect is in the EffectSet for its target element. This is
   // used as an optimization to avoid unnecessary hashmap lookups on the
   // EffectSet.
   bool mInEffectSet = false;
 
-  // We only want to record telemetry data for "ContentTooLarge" warnings once
-  // per effect:target pair so we use this member to record if we have already
-  // reported a "ContentTooLarge" warning for the current target.
-  bool mRecordedContentTooLarge = false;
-  // Similarly, as a point of comparison we record telemetry whether or not
-  // we get a "ContentTooLarge" warning, but again only once per effect:target
-  // pair.
-  bool mRecordedFrameSize = false;
-
 private:
   nsChangeHint mCumulativeChangeHint;
 
   template<typename StyleType>
   void DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes, StyleType* aStyle);
 
   template<typename StyleType>
   void DoUpdateProperties(StyleType* aStyle);
--- a/dom/animation/test/css-animations/file_animations-dynamic-changes.html
+++ b/dom/animation/test/css-animations/file_animations-dynamic-changes.html
@@ -84,38 +84,39 @@ promise_test(function(t) {
                   'First Animation is in second position after update');
     assert_equals(animations[2], animation2,
                   'Second Animation is in third position after update');
     assert_equals(animations[1].startTime, animations[2].startTime,
                   'Old Animations have the same start time');
     // TODO: Check that animations[0].startTime === null
     return animations[0].ready;
   }).then(function() {
-    assert_true(animations[0].startTime > animations[1].startTime,
-                'New Animation has later start time');
+    assert_greater_than(animations[0].startTime, animations[1].startTime,
+                        'New Animation has later start time');
   });
 }, 'Only the startTimes of existing animations are preserved');
 
 promise_test(function(t) {
   var div = addDiv(t);
   div.style.animation = 'anim1 100s, anim1 100s';
   var secondAnimation = div.getAnimations()[1];
 
   // Wait before continuing so we can compare start times
-  return secondAnimation.ready.then(waitForFrame).then(function() {
+  return secondAnimation.ready.then(waitForNextFrame).then(function() {
     // Trim list of animations
     div.style.animationName = 'anim1';
     var animations = div.getAnimations();
     assert_equals(animations.length, 1, 'List of Animations was trimmed');
     assert_equals(animations[0], secondAnimation,
                   'Remaining Animation is the second one in the list');
     assert_equals(typeof(animations[0].startTime), 'number',
                   'Remaining Animation has resolved startTime');
-    assert_true(animations[0].startTime < animations[0].timeline.currentTime,
-                'Remaining Animation preserves startTime');
+    assert_less_than(animations[0].startTime,
+                     animations[0].timeline.currentTime,
+                     'Remaining Animation preserves startTime');
   });
 }, 'Animations are removed from the start of the list while preserving'
    + ' the state of existing Animations');
 
 promise_test(function(t) {
   var div = addDiv(t);
   div.style.animation = 'anim1 100s';
   var firstAddedAnimation = div.getAnimations()[0],
@@ -137,18 +138,19 @@ promise_test(function(t) {
     assert_equals(animations[0], secondAddedAnimation,
                   'Second Animation remains in same position after'
                   + ' interleaving');
     assert_equals(animations[2], firstAddedAnimation,
                   'First Animation remains in same position after'
                   + ' interleaving');
     return animations[1].ready;
   }).then(function() {
-    assert_true(animations[1].startTime > animations[0].startTime,
-                'Interleaved animation starts later than existing animations');
-    assert_true(animations[0].startTime > animations[2].startTime,
-                'Original animations retain their start time');
+    assert_greater_than(animations[1].startTime, animations[0].startTime,
+                        'Interleaved animation starts later than existing ' +
+                        'animations');
+    assert_greater_than(animations[0].startTime, animations[2].startTime,
+                        'Original animations retain their start time');
   });
 }, 'Animation state is preserved when interleaving animations in list');
 
 done();
 </script>
 </body>
--- a/dom/media/webaudio/blink/PeriodicWave.cpp
+++ b/dom/media/webaudio/blink/PeriodicWave.cpp
@@ -269,28 +269,30 @@ void PeriodicWave::createBandLimitedTabl
     m_bandLimitedTables[rangeIndex] = table;
 
     // Apply an inverse FFT to generate the time-domain table data.
     float* data = m_bandLimitedTables[rangeIndex]->Elements();
     frame.GetInverseWithoutScaling(data);
 
     // For the first range (which has the highest power), calculate
     // its peak value then compute normalization scale.
-    if (!m_disableNormalization && !rangeIndex) {
+    if (m_disableNormalization) {
+      // See Bug 1424906, results need to be scaled by 0.5 even
+      // when normalization is disabled.
+      m_normalizationScale = 0.5;
+    } else if (!rangeIndex) {
         float maxValue;
         maxValue = AudioBufferPeakValue(data, m_periodicWaveSize);
 
         if (maxValue)
             m_normalizationScale = 1.0f / maxValue;
     }
 
     // Apply normalization scale.
-    if (!m_disableNormalization) {
-      AudioBufferInPlaceScale(data, m_normalizationScale, m_periodicWaveSize);
-    }
+    AudioBufferInPlaceScale(data, m_normalizationScale, m_periodicWaveSize);
 }
 
 void PeriodicWave::generateBasicWaveform(OscillatorType shape)
 {
     const float piFloat = float(M_PI);
     unsigned fftSize = periodicWaveSize();
     unsigned halfSize = fftSize / 2;
 
--- a/dom/media/webaudio/test/test_periodicWaveDisableNormalization.html
+++ b/dom/media/webaudio/test/test_periodicWaveDisableNormalization.html
@@ -76,19 +76,17 @@ var gTest = {
       buffer.getChannelData(0)[i] = 1.0 / realPeak *
         (real[1] * Math.cos(2 * Math.PI * realFundamental * i /
                             context.sampleRate) +
          real[realMax] * Math.cos(2 * Math.PI * realMax * realFundamental * i /
                             context.sampleRate));
 
       buffer.getChannelData(1)[i] = buffer.getChannelData(0)[i];
 
-      // TODO: We need to scale by a factor of two to make the results work
-      //       out here. This seems suspicious, see Bug 1266737.
-      buffer.getChannelData(2)[i] = 2.0 *
+      buffer.getChannelData(2)[i] =
         (real[1] * Math.cos(2 * Math.PI * realFundamental * i /
                             context.sampleRate) +
          real[realMax] * Math.cos(2 * Math.PI * realMax * realFundamental * i /
                             context.sampleRate));
     }
     return buffer;
   },
   'numberOfChannels': 3,
--- a/dom/smil/nsSMILParserUtils.cpp
+++ b/dom/smil/nsSMILParserUtils.cpp
@@ -264,65 +264,16 @@ ParseOptionalOffset(RangedPtr<const char
     aResult->SetMillis(0L);
     return true;
   }
 
   return SkipWhitespace(aIter, aEnd) &&
          ParseOffsetValue(aIter, aEnd, aResult);
 }
 
-bool
-ParseAccessKey(const nsAString& aSpec, nsSMILTimeValueSpecParams& aResult)
-{
-  MOZ_ASSERT(StringBeginsWith(aSpec, ACCESSKEY_PREFIX_CC) ||
-             StringBeginsWith(aSpec, ACCESSKEY_PREFIX_LC),
-             "Calling ParseAccessKey on non-accesskey-type spec");
-
-  nsSMILTimeValueSpecParams result;
-  result.mType = nsSMILTimeValueSpecParams::ACCESSKEY;
-
-  MOZ_ASSERT(ACCESSKEY_PREFIX_LC.Length() == ACCESSKEY_PREFIX_CC.Length(),
-             "Case variations for accesskey prefix differ in length");
-
-  RangedPtr<const char16_t> iter(SVGContentUtils::GetStartRangedPtr(aSpec));
-  RangedPtr<const char16_t> end(SVGContentUtils::GetEndRangedPtr(aSpec));
-
-  iter += ACCESSKEY_PREFIX_LC.Length();
-
-  // Expecting at least <accesskey> + ')'
-  if (end - iter < 2)
-    return false;
-
-  uint32_t c = *iter++;
-
-  // Process 32-bit codepoints
-  if (NS_IS_HIGH_SURROGATE(c)) {
-    if (end - iter < 2) // Expecting at least low-surrogate + ')'
-      return false;
-    uint32_t lo = *iter++;
-    if (!NS_IS_LOW_SURROGATE(lo))
-      return false;
-    c = SURROGATE_TO_UCS4(c, lo);
-  // XML 1.1 says that 0xFFFE and 0xFFFF are not valid characters
-  } else if (NS_IS_LOW_SURROGATE(c) || c == 0xFFFE || c == 0xFFFF) {
-    return false;
-  }
-
-  result.mRepeatIterationOrAccessKey = c;
-
-  if (*iter++ != ')')
-    return false;
-
-  if (!ParseOptionalOffset(iter, end, &result.mOffset) || iter != end) {
-    return false;
-  }
-  aResult = result;
-  return true;
-}
-
 void
 MoveToNextToken(RangedPtr<const char16_t>& aIter,
                 const RangedPtr<const char16_t>& aEnd,
                 bool aBreakOnDot,
                 bool& aIsAnyCharEscaped)
 {
   aIsAnyCharEscaped = false;
 
@@ -448,17 +399,17 @@ ParseElementBaseTimeValueSpec(const nsAS
       if (start == tokenEnd || *start == '+' || *start == '-' ||
           !SVGContentUtils::ParseInteger(start, tokenEnd, repeatValue)) {
         return false;
       }
       if (start == tokenEnd || *start != ')') {
         return false;
       }
       result.mType = nsSMILTimeValueSpecParams::REPEAT;
-      result.mRepeatIterationOrAccessKey = repeatValue;
+      result.mRepeatIteration = repeatValue;
     // element-name.event-symbol
     } else {
       atom = ConvertTokenToAtom(token2, requiresUnescaping);
       if (atom == nullptr) {
         return false;
       }
       result.mType = nsSMILTimeValueSpecParams::EVENT;
       result.mEventSymbol = atom;
@@ -682,17 +633,17 @@ nsSMILParserUtils::ParseTimeValueSpecPar
   // wallclock type
   if (StringBeginsWith(spec, WALLCLOCK_PREFIX)) {
     return false; // Wallclock times not implemented
   }
 
   // accesskey type
   if (StringBeginsWith(spec, ACCESSKEY_PREFIX_LC) ||
       StringBeginsWith(spec, ACCESSKEY_PREFIX_CC)) {
-    return ParseAccessKey(spec, aResult);
+    return false; // accesskey is not supported
   }
 
   // event, syncbase, or repeat
   return ParseElementBaseTimeValueSpec(spec, aResult);
 }
 
 bool
 nsSMILParserUtils::ParseClockValue(const nsAString& aSpec,
--- a/dom/smil/nsSMILTimeValueSpec.cpp
+++ b/dom/smil/nsSMILTimeValueSpec.cpp
@@ -73,18 +73,16 @@ nsSMILTimeValueSpec::SetSpec(const nsASt
   if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
       (!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
     mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
   }
 
   // Fill in the event symbol to simplify handling later
   if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
     mParams.mEventSymbol = nsGkAtoms::repeatEvent;
-  } else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
-    mParams.mEventSymbol = nsGkAtoms::keypress;
   }
 
   ResolveReferences(aContextNode);
 
   return NS_OK;
 }
 
 void
@@ -107,32 +105,27 @@ nsSMILTimeValueSpec::ResolveReferences(n
   RefPtr<Element> oldReferencedElement = mReferencedElement.get();
 
   if (mParams.mDependentElemID) {
     mReferencedElement.ResetWithID(aContextNode,
         nsDependentAtomString(mParams.mDependentElemID));
   } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
     Element* target = mOwner->GetTargetElement();
     mReferencedElement.ResetWithElement(target);
-  } else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
-    nsIDocument* doc = aContextNode->GetUncomposedDoc();
-    MOZ_ASSERT(doc, "We are in the document but current doc is null");
-    mReferencedElement.ResetWithElement(doc->GetRootElement());
   } else {
     MOZ_ASSERT(false, "Syncbase or repeat spec without ID");
   }
   UpdateReferencedElement(oldReferencedElement, mReferencedElement.get());
 }
 
 bool
 nsSMILTimeValueSpec::IsEventBased() const
 {
   return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
-         mParams.mType == nsSMILTimeValueSpecParams::REPEAT ||
-         mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY;
+         mParams.mType == nsSMILTimeValueSpecParams::REPEAT;
 }
 
 void
 nsSMILTimeValueSpec::HandleNewInterval(nsSMILInterval& aInterval,
                                        const nsSMILTimeContainer* aSrcContainer)
 {
   const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
     ? *aInterval.Begin() : *aInterval.End();
@@ -234,17 +227,16 @@ nsSMILTimeValueSpec::UpdateReferencedEle
       if (to) {
         to->AddDependent(*this);
       }
     }
     break;
 
   case nsSMILTimeValueSpecParams::EVENT:
   case nsSMILTimeValueSpecParams::REPEAT:
-  case nsSMILTimeValueSpecParams::ACCESSKEY:
     RegisterEventListener(aTo);
     break;
 
   default:
     // not a referencing-type
     break;
   }
 }
@@ -313,179 +305,87 @@ nsSMILTimeValueSpec::RegisterEventListen
       !IsWhitelistedEvent()) {
     return;
   }
 
   if (!mEventListener) {
     mEventListener = new EventListener(this);
   }
 
-  EventListenerManager* elm = GetEventListenerManager(aTarget);
-  if (!elm)
+  EventListenerManager* elm = aTarget->GetOrCreateListenerManager();
+  if (!elm) {
     return;
+  }
 
   elm->AddEventListenerByType(mEventListener,
                               nsDependentAtomString(mParams.mEventSymbol),
                               AllEventsAtSystemGroupBubble());
 }
 
 void
 nsSMILTimeValueSpec::UnregisterEventListener(Element* aTarget)
 {
-  if (!aTarget || !mEventListener)
+  if (!aTarget || !mEventListener) {
     return;
+  }
 
-  EventListenerManager* elm = GetEventListenerManager(aTarget);
-  if (!elm)
+  EventListenerManager* elm = aTarget->GetOrCreateListenerManager();
+  if (!elm) {
     return;
+  }
 
   elm->RemoveEventListenerByType(mEventListener,
                                  nsDependentAtomString(mParams.mEventSymbol),
                                  AllEventsAtSystemGroupBubble());
 }
 
-EventListenerManager*
-nsSMILTimeValueSpec::GetEventListenerManager(Element* aTarget)
-{
-  MOZ_ASSERT(aTarget, "null target; can't get EventListenerManager");
-
-  nsCOMPtr<EventTarget> target;
-
-  if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
-    nsIDocument* doc = aTarget->GetUncomposedDoc();
-    if (!doc)
-      return nullptr;
-    nsPIDOMWindowOuter* win = doc->GetWindow();
-    if (!win)
-      return nullptr;
-    target = do_QueryInterface(win);
-  } else {
-    target = aTarget;
-  }
-  if (!target)
-    return nullptr;
-
-  return target->GetOrCreateListenerManager();
-}
-
 void
 nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent)
 {
   MOZ_ASSERT(mEventListener, "Got event without an event listener");
   MOZ_ASSERT(IsEventBased(),
              "Got event for non-event nsSMILTimeValueSpec");
   MOZ_ASSERT(aEvent, "No event supplied");
 
   // XXX In the long run we should get the time from the event itself which will
   // store the time in global document time which we'll need to convert to our
   // time container
   nsSMILTimeContainer* container = mOwner->GetTimeContainer();
   if (!container)
     return;
 
-  if (!CheckEventDetail(aEvent))
+  if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT &&
+      !CheckRepeatEventDetail(aEvent)) {
     return;
+  }
 
   nsSMILTime currentTime = container->GetCurrentTime();
   nsSMILTimeValue newTime(currentTime);
   if (!ApplyOffset(newTime)) {
     NS_WARNING("New time generated from event overflows nsSMILTime, ignoring");
     return;
   }
 
   RefPtr<nsSMILInstanceTime> newInstance =
     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
 }
 
 bool
-nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent)
-{
-  switch (mParams.mType)
-  {
-  case nsSMILTimeValueSpecParams::REPEAT:
-    return CheckRepeatEventDetail(aEvent);
-
-  case nsSMILTimeValueSpecParams::ACCESSKEY:
-    return CheckAccessKeyEventDetail(aEvent);
-
-  default:
-    // nothing to check
-    return true;
-  }
-}
-
-bool
 nsSMILTimeValueSpec::CheckRepeatEventDetail(nsIDOMEvent *aEvent)
 {
   nsCOMPtr<nsIDOMTimeEvent> timeEvent = do_QueryInterface(aEvent);
   if (!timeEvent) {
     NS_WARNING("Received a repeat event that was not a DOMTimeEvent");
     return false;
   }
 
   int32_t detail;
   timeEvent->GetDetail(&detail);
-  return detail > 0 && (uint32_t)detail == mParams.mRepeatIterationOrAccessKey;
-}
-
-bool
-nsSMILTimeValueSpec::CheckAccessKeyEventDetail(nsIDOMEvent *aEvent)
-{
-  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
-  if (!keyEvent) {
-    NS_WARNING("Received an accesskey event that was not a DOMKeyEvent");
-    return false;
-  }
-
-  // Ignore the key event if any modifier keys are pressed UNLESS we're matching
-  // on the charCode in which case we ignore the state of the shift and alt keys
-  // since they might be needed to generate the character in question.
-  bool isCtrl;
-  bool isMeta;
-  keyEvent->GetCtrlKey(&isCtrl);
-  keyEvent->GetMetaKey(&isMeta);
-  if (isCtrl || isMeta)
-    return false;
-
-  uint32_t code;
-  keyEvent->GetCharCode(&code);
-  if (code)
-    return code == mParams.mRepeatIterationOrAccessKey;
-
-  // Only match on the keyCode if it corresponds to some ASCII character that
-  // does not produce a charCode.
-  // In this case we can safely bail out if either alt or shift is pressed since
-  // they won't already be incorporated into the keyCode unlike the charCode.
-  bool isAlt;
-  bool isShift;
-  keyEvent->GetAltKey(&isAlt);
-  keyEvent->GetShiftKey(&isShift);
-  if (isAlt || isShift)
-    return false;
-
-  keyEvent->GetKeyCode(&code);
-  switch (code)
-  {
-  case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
-    return mParams.mRepeatIterationOrAccessKey == 0x08;
-
-  case nsIDOMKeyEvent::DOM_VK_RETURN:
-    return mParams.mRepeatIterationOrAccessKey == 0x0A ||
-           mParams.mRepeatIterationOrAccessKey == 0x0D;
-
-  case nsIDOMKeyEvent::DOM_VK_ESCAPE:
-    return mParams.mRepeatIterationOrAccessKey == 0x1B;
-
-  case nsIDOMKeyEvent::DOM_VK_DELETE:
-    return mParams.mRepeatIterationOrAccessKey == 0x7F;
-
-  default:
-    return false;
-  }
+  return detail > 0 && (uint32_t)detail == mParams.mRepeatIteration;
 }
 
 nsSMILTimeValue
 nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
     const nsSMILTimeValue& aSrcTime,
     const nsSMILTimeContainer* aSrcContainer)
 {
   // If the source time is either indefinite or unresolved the result is going
--- a/dom/smil/nsSMILTimeValueSpec.h
+++ b/dom/smil/nsSMILTimeValueSpec.h
@@ -23,17 +23,17 @@ namespace mozilla {
 class EventListenerManager;
 } // namespace mozilla
 
 //----------------------------------------------------------------------
 // nsSMILTimeValueSpec class
 //
 // An individual element of a 'begin' or 'end' attribute, e.g. '5s', 'a.end'.
 // This class handles the parsing of such specifications and performs the
-// necessary event handling (for event, repeat, and accesskey specifications)
+// necessary event handling (for event and repeat specifications)
 // and synchronisation (for syncbase specifications).
 //
 // For an overview of how this class is related to other SMIL time classes see
 // the documentation in nsSMILTimeValue.h
 
 class nsSMILTimeValueSpec
 {
 public:
@@ -65,21 +65,18 @@ public:
 
 protected:
   void UpdateReferencedElement(Element* aFrom, Element* aTo);
   void UnregisterFromReferencedElement(Element* aElement);
   nsSMILTimedElement* GetTimedElement(Element* aElement);
   bool IsWhitelistedEvent();
   void RegisterEventListener(Element* aElement);
   void UnregisterEventListener(Element* aElement);
-  mozilla::EventListenerManager* GetEventListenerManager(Element* aElement);
   void HandleEvent(nsIDOMEvent* aEvent);
-  bool CheckEventDetail(nsIDOMEvent* aEvent);
   bool CheckRepeatEventDetail(nsIDOMEvent* aEvent);
-  bool CheckAccessKeyEventDetail(nsIDOMEvent* aEvent);
   nsSMILTimeValue ConvertBetweenTimeContainers(const nsSMILTimeValue& aSrcTime,
                                       const nsSMILTimeContainer* aSrcContainer);
   bool ApplyOffset(nsSMILTimeValue& aTime) const;
 
   nsSMILTimedElement*           mOwner;
   bool                          mIsBegin; // Indicates if *we* are a begin spec,
                                           // not to be confused with
                                           // mParams.mSyncBegin which indicates
--- a/dom/smil/nsSMILTimeValueSpecParams.h
+++ b/dom/smil/nsSMILTimeValueSpecParams.h
@@ -15,39 +15,36 @@
 //
 // A simple data type for storing the result of parsing a single begin or end
 // value (e.g. the '5s' in begin="5s; indefinite; a.begin+2s").
 
 class nsSMILTimeValueSpecParams
 {
 public:
   nsSMILTimeValueSpecParams()
-  :
-    mType(INDEFINITE),
-    mSyncBegin(false),
-    mRepeatIterationOrAccessKey(0)
+    : mType(INDEFINITE)
+    , mSyncBegin(false)
+    , mRepeatIteration(0)
   { }
 
   // The type of value this specification describes
   enum {
     OFFSET,
     SYNCBASE,
     EVENT,
     REPEAT,
-    ACCESSKEY,
     WALLCLOCK,
     INDEFINITE
   } mType;
 
   // A clock value that is added to:
   // - type OFFSET: the document begin
   // - type SYNCBASE: the timebase's begin or end time
   // - type EVENT: the event time
   // - type REPEAT: the repeat time
-  // - type ACCESSKEY: the keypress time
   // It is not used for WALLCLOCK or INDEFINITE times
   nsSMILTimeValue   mOffset;
 
   // The base element that this specification refers to.
   // For SYNCBASE types, this is the timebase
   // For EVENT and REPEAT types, this is the eventbase
   RefPtr<nsAtom> mDependentElemID;
 
@@ -55,14 +52,14 @@ public:
   // Only used for EVENT types.
   RefPtr<nsAtom> mEventSymbol;
 
   // Indicates if this specification refers to the begin or end of the dependent
   // element.
   // Only used for SYNCBASE types.
   bool              mSyncBegin;
 
-  // The repeat iteration (type=REPEAT) or access key (type=ACCESSKEY) to
-  // respond to.
-  uint32_t          mRepeatIterationOrAccessKey;
+  // The repeat iteration to respond to.
+  // Only used for mType=REPEAT.
+  uint32_t mRepeatIteration;
 };
 
 #endif // NS_SMILTIMEVALUESPECPARAMS_H_
--- a/dom/smil/nsSMILTimedElement.cpp
+++ b/dom/smil/nsSMILTimedElement.cpp
@@ -1319,31 +1319,33 @@ nsSMILTimedElement::SetBeginOrEndSpec(co
 
   AutoIntervalUpdateBatcher updateBatcher(*this);
 
   nsCharSeparatedTokenizer tokenizer(aSpec, ';');
   if (!tokenizer.hasMoreTokens()) { // Empty list
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv = NS_OK;
-  while (tokenizer.hasMoreTokens() && NS_SUCCEEDED(rv)) {
+  bool hadFailure = false;
+  while (tokenizer.hasMoreTokens()) {
     nsAutoPtr<nsSMILTimeValueSpec>
       spec(new nsSMILTimeValueSpec(*this, aIsBegin));
-    rv = spec->SetSpec(tokenizer.nextToken(), aContextNode);
+    nsresult rv = spec->SetSpec(tokenizer.nextToken(), aContextNode);
     if (NS_SUCCEEDED(rv)) {
       timeSpecsList.AppendElement(spec.forget());
+    } else {
+      hadFailure = true;
     }
   }
 
-  if (NS_FAILED(rv)) {
-    ClearSpecs(timeSpecsList, instances, aRemove);
-  }
-
-  return rv;
+  // The return value from this function is only used to determine if we should
+  // print a console message or not, so we return failure if we had one or more
+  // failures but we don't need to differentiate between different types of
+  // failures or the number of failures.
+  return hadFailure ? NS_ERROR_FAILURE : NS_OK;
 }
 
 namespace
 {
   // Adaptor functor for RemoveInstanceTimes that allows us to use function
   // pointers instead.
   // Without this we'd have to either templatize ClearSpecs and all its callers
   // or pass bool flags around to specify which removal function to use here.
--- a/dom/smil/test/test_smilAccessKey.xhtml
+++ b/dom/smil/test/test_smilAccessKey.xhtml
@@ -12,351 +12,68 @@
 <div id="content" style="display: none">
 <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
   <circle cx="20" cy="20" r="15" fill="blue" id="circle"/>
 </svg>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 <![CDATA[
-/** Test for SMIL accessKey support **/
+/** Test for lack of SMIL accessKey support **/
 
-const gSvgns = "http://www.w3.org/2000/svg";
-var gSvg = document.getElementById("svg");
+const gSvgns = 'http://www.w3.org/2000/svg';
 SimpleTest.waitForExplicitFinish();
 
 function main()
 {
-  gSvg.pauseAnimations();
-
-  // Basic syntax
-  testOk('accessKey(a)', 'a');
-  testOk(' accessKey(a)  ', 'a');
-  testNotOk('accessKey (a)', 'a');
-  testNotOk('accessKey( a)', 'a');
-  testNotOk('accessKey(a )', 'a');
-  testNotOk('accessKey(a)', 'b');
-  testNotOk('accessKey()', ' ');
-
-  // Test the test framework itself
-  testOk('accessKey(a)', 97);
-
-  // Allow for either accessKey (SVG / SMIL Animation) or accesskey (SMIL2+)
-  testOk('accesskey(a)', 'a');
-
-  // Offset
-  testOk('accessKey(a)+0s', 'a');
-  testOk('accessKey(a) + 0min', 'a');
-  testOk('accessKey(a) -0h', 'a');
-  testOk('accessKey(a)+100ms', 'a', 0, 0.1);
-  testOk('accessKey(a)-0.1s', 'a', 0, -0.1);
-
-  // Id references are not allowed
-  testNotOk('svg.accessKey(a)', 'a');
-  testNotOk('window.accessKey(a)', 'a');
-
-  // Case sensitivity
-  testOk('accessKey(A)', 'A');
-  testNotOk('accessKey(a)', 'A');
-  testNotOk('accessKey(A)', 'a');
+  testBeginValueIsNotSupported('accessKey(a)');
+  testBeginValueIsNotSupported('accesskey(a)');
 
-  // Test unusual characters
-  testOk('accessKey(-)', '-');
-  testOk('accessKey(\\)', '\\');
-  testOk('accessKey( )', ' ');
-  testOk('accessKey(\x0D)', 0, KeyboardEvent.DOM_VK_RETURN);
-  testOk('accessKey(\n)', 0, KeyboardEvent.DOM_VK_RETURN); // New line
-  testOk('accessKey(\r)', 0, KeyboardEvent.DOM_VK_RETURN); // Carriage return
-  testOk('accessKey(\x08)', 0, KeyboardEvent.DOM_VK_BACK_SPACE);
-  testOk('accessKey(\x1B)', 0, KeyboardEvent.DOM_VK_ESCAPE);
-  testOk('accessKey(\x7F)', 0, KeyboardEvent.DOM_VK_DELETE);
-
-  // Check some disallowed keys
-  // -- For now we don't allow tab since the interaction with focus causes
-  //    confusing results
-  testNotOk('accessKey(\x09)', 0, 9);  // Tab
-
-  // Test setting the keyCode field
-  testNotOk('accessKey(a)', 0, 97);
-  testOk('accessKey(a)', 97, 66); // Give priority to charCode field
-  testNotOk('accessKey(a)', 98, 97); // Give priority to charCode field
-
-  // Test unicode
-  testOk("accessKey(\u20AC)", 8364); // euro-symbol
-
-  // Test an astral character just to make sure we don't crash
-  testOk("accessKey(\uD835\uDC00)", 119808); // mathematical bold capital A
-                                             // 0x1D400
-  // Test bad surrogate pairs don't confuse us either
-  testNotOk("accessKey(\uD800\uD800)", 97);
-  testNotOk("accessKey(\uD80020)", 97);
-  testNotOk("accessKey(\uD800)", 97);
-
-  // Test modifiers
-  // -- When matching on charCode ignore shift and alt
-  testNotOk('accessKey(a)', 'a', 0, 0, { ctrl: true });
-  testNotOk('accessKey(a)', 'a', 0, 0, { meta: true });
-  testOk('accessKey(a)', 'a', 0, 0, { alt: true });
-  testOk('accessKey(a)', 'a', 0, 0, { shift: true });
-  testNotOk('accessKey(a)', 'a', 0, 0, { shift: true, ctrl: true });
-  testNotOk('accessKey(a)', 'a', 0, 0, { alt: true, meta: true });
-  // -- When matching on keyCode ignore all
-  testNotOk('accessKey(\x0D)', 0, 13, 0, { ctrl: true });
-  testNotOk('accessKey(\x0D)', 0, 13, 0, { meta: true });
-  testNotOk('accessKey(\x0D)', 0, 13, 0, { alt: true });
-  testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true });
-  testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true, ctrl: true });
-
-  testOpenEnd();
-  testPreventDefault();
-  testDispatchToWindow();
-  testAdoptNode();
-  testFauxEvent();
+  is(getStartTime('accesskey(a); 1s'), 1,
+     'Start time for accesskey(a) followed by a literal time');
+  is(getStartTime('3s; accessKey(a)'), 3,
+     'Start time for accesskey(a) preceded by a literal time');
 
   SimpleTest.finish();
 }
 
-function testOk(spec, charCode, keyCode, offset, modifiers)
-{
-  if (typeof offset == 'undefined') offset = 0;
-  var msg = "No interval created for '" + spec +
-    "' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" +
-    getModifiersDescr(modifiers);
-  ok(test(spec, charCode, keyCode, offset, modifiers), msg);
-}
-
-function testNotOk(spec, charCode, keyCode, offset, modifiers)
-{
-  if (typeof offset == 'undefined') offset = 0;
-  var msg = "Interval unexpectedly created for '" + spec +
-    "' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" +
-    getModifiersDescr(modifiers);
-  ok(!test(spec, charCode, keyCode, offset, modifiers), msg);
-}
-
-function getModifiersDescr(modifiers)
-{
-  if (typeof modifiers != 'object')
-    return '';
-  var str = ' modifiers set:';
-  for (var key in modifiers) {
-    if (modifiers[key]) str += ' ' + key;
-  }
-  return str;
-}
-
-function test(spec, charCode, keyCode, offset, modifiers)
-{
-  gSvg.setCurrentTime(1);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  var anim = createAnim(spec);
-  var evt = createEvent(charCode, keyCode, modifiers);
-
-  document.getElementById('circle').dispatchEvent(evt);
-
-  var gotStartTimeOk = true;
-  try {
-    var start = anim.getStartTime();
-    if (offset) {
-      var expected = gSvg.getCurrentTime() + offset;
-      ok(Math.abs(expected - start) <= 0.00001,
-        "Unexpected start time for animation with begin: " + spec +
-          " got " + start + ", expected " + expected);
-    } else {
-      is(start, gSvg.getCurrentTime() + offset,
-         "Unexpected start time for animation with begin: " + spec);
-    }
-  } catch(e) {
-    is(e.name, "InvalidStateError",
-       "Unexpected exception: " + e.name);
-    is(e.code, DOMException.INVALID_STATE_ERR,
-       "Unexpected exception code: " + e.code);
-    gotStartTimeOk = false;
-  }
-
-  anim.remove();
-
-  return gotStartTimeOk;
-}
-
-function createAnim(beginSpec)
-{
-  var anim = document.createElementNS(gSvgns, 'animate');
+function createAnim(beginSpec) {
+  const anim = document.createElementNS(gSvgns, 'animate');
   anim.setAttribute('attributeName', 'cx');
   anim.setAttribute('values', '0; 100');
   anim.setAttribute('dur', '10s');
   anim.setAttribute('begin', beginSpec);
   return document.getElementById('circle').appendChild(anim);
 }
 
-function createEvent(charCode, keyCode, modifiers)
-{
-  if (typeof charCode == 'string') {
-    is(charCode.length, 1,
-       "If charCode is a string it should be 1 character long");
-    charCode = charCode.charCodeAt(0);
-  } else if (typeof charCode == 'undefined') {
-    charCode = 0;
-  }
-  args = { ctrl: false, alt: false, shift: false, meta: false };
-  if (typeof modifiers == 'object') {
-    for (var key in modifiers)
-      args[key] = modifiers[key];
-  }
-  if (typeof keyCode == 'undefined') keyCode = 0;
-  var evt = document.createEvent("KeyboardEvent");
-  evt.initKeyEvent("keypress", true, true, window,
-                   args['ctrl'],
-                   args['alt'],
-                   args['shift'],
-                   args['meta'],
-                   keyCode,
-                   charCode);
-  return evt;
-}
-
-function testOpenEnd()
-{
-  // Test that an end specification with an accesskey value is treated as open
-  // ended
-  gSvg.setCurrentTime(0);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  var anim = createAnim('0s; 2s');
-  anim.setAttribute('end', '1s; accessKey(a)');
-
-  gSvg.setCurrentTime(2);
+function testBeginValueIsNotSupported(beginSpec) {
+  const anim = createAnim(beginSpec);
 
   try {
-    is(anim.getStartTime(), 2,
-       "Unexpected start time for second interval of open-ended animation");
+    anim.getStartTime();
+    ok(false,
+       `Should have failed to get start time for begin value: ${beginSpec}`);
   } catch(e) {
-    is(e.name, "InvalidStateError",
-       "Unexpected exception:" + e.name);
+    is(e.name, 'InvalidStateError', `Unexpected exception: ${e.name}`);
     is(e.code, DOMException.INVALID_STATE_ERR,
-       "Unexpected exception code:" + e.code);
-    ok(false, "Failed to recognise accessKey as qualifying for creating an " +
-              "open-ended interval");
+       `Unexpected exception code: ${e.code}`);
   }
 
   anim.remove();
 }
 
-function testPreventDefault()
-{
-  // SVG/SMIL don't specify what should happen if preventDefault is called on
-  // the keypress event. For now, for consistency with event timing we ignore
-  // it.
-  gSvg.setCurrentTime(1);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  var anim = createAnim('accessKey(a)');
-  var evt = createEvent('a');
-
-  var circle = document.getElementById('circle');
-  var func = function(evt) { evt.preventDefault(); }
-  circle.addEventListener('keypress', func);
-  circle.dispatchEvent(evt);
-
+function getStartTime(beginSpec) {
+  const anim = createAnim(beginSpec);
+  let startTime;
   try {
-    var start = anim.getStartTime();
-  } catch(e) {
-    ok(false, "preventDefault() cancelled accessKey handling");
-  }
+    startTime = anim.getStartTime();
+  } catch (e) { }
+  anim.remove();
 
-  circle.removeEventListener('keypress', func);
-  anim.remove();
-}
-
-function testDispatchToWindow()
-{
-  gSvg.setCurrentTime(1);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  var anim = createAnim('accessKey(a)');
-  var evt = createEvent('a');
-
-  window.dispatchEvent(evt);
-
-  try {
-    var start = anim.getStartTime();
-  } catch(e) {
-    ok(false, "Key event dispatched to the window failed to trigger " +
-              "accesskey handling");
-  }
-
-  anim.remove();
+  return startTime;
 }
 
-function testAdoptNode()
-{
-  gSvg.setCurrentTime(1);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  // Create a new document with an animation element
-  var newdoc = document.implementation.createDocument(gSvgns, 'svg', null);
-  var anim = newdoc.createElementNS(gSvgns, 'animate');
-  anim.setAttribute('attributeName', 'cx');
-  anim.setAttribute('values', '0; 100');
-  anim.setAttribute('dur', '10s');
-  anim.setAttribute('begin', 'accesskey(a)');
-  newdoc.documentElement.appendChild(anim);
-
-  // Adopt
-  ok(anim.ownerDocument !== document,
-     "Expected newly created animation to belong to a different doc");
-  document.adoptNode(anim);
-  document.getElementById('circle').appendChild(anim);
-  ok(anim.ownerDocument === document,
-     "Expected newly created animation to belong to the same doc");
-
-  var evt = createEvent('a');
-
-  // Now fire an event at the original window and check nothing happens
-  newdoc.dispatchEvent(evt);
-  try {
-    var start = anim.getStartTime();
-    ok(false, "Adopted node still receiving accesskey events from old doc");
-  } catch(e) {
-    // Ok
-  }
-
-  // And then fire at our window
-  document.dispatchEvent(evt);
-  try {
-    var start = anim.getStartTime();
-  } catch(e) {
-    ok(false, "Adopted node failed to catch accesskey event");
-  }
-
-  anim.remove();
-}
-
-function testFauxEvent()
-{
-  // Test a non-KeyEvent labelled as a key event
-  gSvg.setCurrentTime(0);
-  ok(gSvg.animationsPaused(), "Expected animations to be paused");
-
-  var anim = createAnim('accessKey(a)');
-  var evt = document.createEvent("SVGEvents");
-  evt.initEvent("keypress", true, true);
-  document.getElementById('circle').dispatchEvent(evt);
-
-  // We're really just testing that the above didn't crash us, but while we're
-  // at it, just do a sanity check that we didn't also create an interval
-  try {
-    var start = anim.getStartTime();
-    ok(false, "Faux event generated interval");
-  } catch(e) {
-    // All is well
-  }
-
-  anim.remove();
-}
-
-window.addEventListener("load", main);
+window.addEventListener('load', main);
 ]]>
 </script>
 </pre>
 </body>
 </html>
--- a/dom/smil/test/test_smilTiming.xhtml
+++ b/dom/smil/test/test_smilTiming.xhtml
@@ -127,20 +127,20 @@ function main() {
   testCases.push(StartTimeTest('05:40\u30D5', 'none'));
   testCases.push(StartTimeTest('05:40β', 'none'));
 
   // List syntax
   testCases.push(StartTimeTest('3', 3));
   testCases.push(StartTimeTest('3;', 3));
   testCases.push(StartTimeTest('3; ', 3));
   testCases.push(StartTimeTest('3 ; ', 3));
-  testCases.push(StartTimeTest('3;;', 'none'));
-  testCases.push(StartTimeTest('3;; ', 'none'));
-  testCases.push(StartTimeTest(';3', 'none'));
-  testCases.push(StartTimeTest(' ;3', 'none'));
+  testCases.push(StartTimeTest('3;;', 3));
+  testCases.push(StartTimeTest('3;; ', 3));
+  testCases.push(StartTimeTest(';3', 3));
+  testCases.push(StartTimeTest(' ;3', 3));
   testCases.push(StartTimeTest('3;4', 3));
   testCases.push(StartTimeTest(' 3 ; 4 ', 3));
 
   // List syntax on end times
   testCases.push({
     'attr' : { 'begin': '0s',
                'end': '1s; 2s' },
     'times': [ [ 0, 0 ],
--- a/gfx/thebes/PrintTargetEMF.cpp
+++ b/gfx/thebes/PrintTargetEMF.cpp
@@ -17,25 +17,24 @@ using mozilla::ipc::FileDescriptor;
 
 namespace mozilla {
 namespace gfx {
 
 PrintTargetEMF::PrintTargetEMF(HDC aDC, const IntSize& aSize)
   : PrintTarget(/* not using cairo_surface_t */ nullptr, aSize)
   , mPDFiumProcess(nullptr)
   , mPrinterDC(aDC)
-  , mWaitingForEMFConversion(false)
   , mChannelBroken(false)
 {
 }
 
 PrintTargetEMF::~PrintTargetEMF()
 {
   if (mPDFiumProcess) {
-    mPDFiumProcess->Delete(mWaitingForEMFConversion);
+    mPDFiumProcess->Delete();
   }
 }
 
 /* static */ already_AddRefed<PrintTargetEMF>
 PrintTargetEMF::CreateOrNull(HDC aDC, const IntSize& aSizeInPoints)
 {
   return do_AddRef(new PrintTargetEMF(aDC, aSizeInPoints));
 }
@@ -132,17 +131,16 @@ PrintTargetEMF::EndPage()
   if (!mPDFiumProcess->GetActor()->SendConvertToEMF(descriptor,
                                         ::GetDeviceCaps(mPrinterDC, HORZRES),
                                         ::GetDeviceCaps(mPrinterDC, VERTRES)))
   {
     return NS_ERROR_FAILURE;
   }
 
   PR_Close(prfile);
-  mWaitingForEMFConversion = true;
 
   return NS_OK;
 }
 
 already_AddRefed<DrawTarget>
 PrintTargetEMF::MakeDrawTarget(const IntSize& aSize,
                                DrawEventRecorder* aRecorder)
 {
@@ -168,17 +166,16 @@ PrintTargetEMF::GetReferenceDrawTarget(D
 void
 PrintTargetEMF::ConvertToEMFDone(const nsresult& aResult,
                                  mozilla::ipc::Shmem&& aEMF)
 {
   MOZ_ASSERT_IF(NS_FAILED(aResult), aEMF.Size<uint8_t>() == 0);
   MOZ_ASSERT(!mChannelBroken, "It is not possible to get conversion callback "
                               "after the channel was broken.");
 
-  mWaitingForEMFConversion = false;
   if (NS_SUCCEEDED(aResult)) {
     if (::StartPage(mPrinterDC) > 0) {
       mozilla::widget::WindowsEMF emf;
       emf.InitFromFileContents(aEMF.get<BYTE>(), aEMF.Size<BYTE>());
       RECT printRect = {0, 0, ::GetDeviceCaps(mPrinterDC, HORZRES),
                         ::GetDeviceCaps(mPrinterDC, VERTRES)};
       DebugOnly<bool> ret = emf.Playback(mPrinterDC, printRect);
       MOZ_ASSERT(ret);
--- a/gfx/thebes/PrintTargetEMF.h
+++ b/gfx/thebes/PrintTargetEMF.h
@@ -63,16 +63,15 @@ private:
   ~PrintTargetEMF() override;
 
   nsString mTitle;
   RefPtr<PrintTargetSkPDF> mTargetForCurrentPage;
   nsCOMPtr<nsIFile>        mPDFFileForOnePage;
   RefPtr<PrintTargetSkPDF> mRefTarget;
   PDFiumProcessParent*     mPDFiumProcess;
   HDC mPrinterDC;
-  bool mWaitingForEMFConversion;
   bool mChannelBroken;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_PRINTTARGETEMF_H */
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4970,17 +4970,17 @@ PresShell::PaintRangePaintInfo(const nsT
 {
   nsPresContext* pc = GetPresContext();
   if (!pc || aArea.width == 0 || aArea.height == 0)
     return nullptr;
 
   // use the rectangle to create the surface
   nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
 
-  // if the image should not be resized, the scale, relative to the original image, must be 1
+  // if the image should not be resized, scale must be 1
   float scale = 1.0;
   nsIntRect rootScreenRect =
     GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
       pc->AppUnitsPerDevPixel());
 
   nsRect maxSize;
   pc->DeviceContext()->GetClientRect(maxSize);
 
@@ -4992,31 +4992,33 @@ PresShell::PaintRangePaintInfo(const nsT
     if (aFlags & RENDER_IS_IMAGE) {
       // get max screensize
       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
       // resize image relative to the screensize
       // get best height/width relative to screensize
       float bestHeight = float(maxHeight)*RELATIVE_SCALEFACTOR;
       float bestWidth = float(maxWidth)*RELATIVE_SCALEFACTOR;
-      // get scalefactor to reach bestWidth
-      scale = bestWidth / float(pixelArea.width);
+      // calculate scale for bestWidth
+      float adjustedScale = bestWidth / float(pixelArea.width);
       // get the worst height (height when width is perfect)
-      float worstHeight = float(pixelArea.height)*scale;
+      float worstHeight = float(pixelArea.height)*adjustedScale;
       // get the difference of best and worst height
       float difference = bestHeight - worstHeight;
-      // half the difference and add it to worstHeight,
-      // then get scalefactor to reach this
-      scale = (worstHeight + difference / 2) / float(pixelArea.height);
+      // halve the difference and add it to worstHeight to get
+      // the best compromise between bestHeight and bestWidth,
+      // then calculate the corresponding scale factor
+      adjustedScale = (worstHeight + difference / 2) / float(pixelArea.height);
+      // prevent upscaling
+      scale = std::min(scale, adjustedScale);
     } else {
       // get half of max screensize
       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
       if (pixelArea.width > maxWidth || pixelArea.height > maxHeight) {
-        scale = 1.0;
         // divide the maximum size by the image size in both directions. Whichever
         // direction produces the smallest result determines how much should be
         // scaled.
         if (pixelArea.width > maxWidth)
           scale = std::min(scale, float(maxWidth) / pixelArea.width);
         if (pixelArea.height > maxHeight)
           scale = std::min(scale, float(maxHeight) / pixelArea.height);
       }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3465,16 +3465,22 @@ nsIFrame::BuildDisplayListForChild(nsDis
   if (doingShortcut) {
     // This is the shortcut for frames been handled along the common
     // path, the most common one of THE COMMON CASE mentioned later.
     MOZ_ASSERT(child->Type() != LayoutFrameType::Placeholder);
     MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() &&
                !aBuilder->GetIncludeAllOutOfFlows(),
                "It should be held for painting to window");
 
+    if (child->HasPerspective()) {
+      // We need to allocate a perspective index before a potential early
+      // return below.
+      aBuilder->AllocatePerspectiveItemIndex();
+    }
+
     // dirty rect in child-relative coordinates
     nsRect dirty = aBuilder->GetDirtyRect() - child->GetOffsetTo(this);
     nsRect visible = aBuilder->GetVisibleRect() - child->GetOffsetTo(this);
 
     if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
       return;
     }
 
@@ -3568,16 +3574,22 @@ nsIFrame::BuildDisplayListForChild(nsDis
       // to enter to reach other out-of-flow frames that are visible.
       visible.SetEmpty();
       dirty.SetEmpty();
     }
     pseudoStackingContext = true;
     awayFromCommonPath = true;
   }
 
+  if (child->HasPerspective()) {
+    // We need to allocate a perspective index before a potential early
+    // return below.
+    aBuilder->AllocatePerspectiveItemIndex();
+  }
+
   NS_ASSERTION(!child->IsPlaceholderFrame(),
                "Should have dealt with placeholders already");
   if (aBuilder->GetSelectedFramesOnly() &&
       child->IsLeaf() &&
       !aChild->IsSelected()) {
     return;
   }
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8342,31 +8342,16 @@ nsDisplayOpacity::CanUseAsyncAnimations(
 }
 
 bool
 nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
 {
   return mAllowAsyncAnimation;
 }
 
-static void
-RecordAnimationFrameSizeTelemetry(nsIFrame* aFrame, const nsSize& overflow)
-{
-  gfxSize scale = nsLayoutUtils::GetTransformToAncestorScale(aFrame);
-  nsSize frameSize = nsSize(overflow.width * scale.width,
-                            overflow.height * scale.height);
-  uint32_t pixelArea = uint32_t(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width))
-                     * nsPresContext::AppUnitsToIntCSSPixels(frameSize.height);
-  if (EffectSet* effects = EffectSet::GetEffectSet(aFrame)) {
-    for (KeyframeEffectReadOnly* effect : *effects) {
-      effect->RecordFrameSizeTelemetry(pixelArea);
-    }
-  }
-}
-
 /* static */ auto
 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
                                                       nsIFrame* aFrame,
                                                       nsRect* aDirtyRect) -> PrerenderDecision
 {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
@@ -8403,27 +8388,19 @@ nsDisplayTransform::ShouldPrerenderTrans
   for (nsIFrame* container = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
        container; container = nsLayoutUtils::GetCrossDocParentFrame(container)) {
     const nsStyleSVGReset *svgReset = container->StyleSVGReset();
     if (svgReset->HasMask() || svgReset->HasClipPath()) {
       return NoPrerender;
     }
   }
 
-  nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
-
-  // Record telemetry about the size of the animated content.
-  // Check CanRecordExtended() so we don't do any processing if the
-  // telemetry won't be recorded anyways.
-  if (Telemetry::CanRecordExtended()) {
-    RecordAnimationFrameSizeTelemetry(aFrame, overflow.Size());
-  }
-
   // If the incoming dirty rect already contains the entire overflow area,
   // we are already rendering the entire content.
+  nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
   if (aDirtyRect->Contains(overflow)) {
     return FullPrerender;
   }
 
   float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
   float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
   uint32_t absoluteLimitX = gfxPrefs::AnimationPrerenderAbsoluteLimitX();
   uint32_t absoluteLimitY = gfxPrefs::AnimationPrerenderAbsoluteLimitY();
@@ -9126,22 +9103,24 @@ nsDisplayTransform::WriteDebugInfo(std::
 
 nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aTransformFrame,
                                            nsIFrame* aPerspectiveFrame,
                                            nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aPerspectiveFrame)
   , mList(aBuilder, aPerspectiveFrame, aList)
   , mTransformFrame(aTransformFrame)
-  , mIndex(aBuilder->AllocatePerspectiveItemIndex())
+  , mIndex(aBuilder->PerspectiveItemIndex())
 {
   MOZ_ASSERT(mList.GetChildren()->Count() == 1);
   MOZ_ASSERT(mList.GetChildren()->GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM);
 
-  mTransformFrame->AddDisplayItem(this);
+  if (aBuilder->IsRetainingDisplayList()) {
+    mTransformFrame->AddDisplayItem(this);
+  }
 }
 
 already_AddRefed<Layer>
 nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
                                  LayerManager *aManager,
                                  const ContainerLayerParameters& aContainerParameters)
 {
   float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1530,17 +1530,18 @@ public:
   /**
    * mContainsBlendMode is true if we processed a display item that
    * has a blend mode attached. We do this so we can insert a
    * nsDisplayBlendContainer in the parent stacking context.
    */
   void SetContainsBlendMode(bool aContainsBlendMode) { mContainsBlendMode = aContainsBlendMode; }
   bool ContainsBlendMode() const { return mContainsBlendMode; }
 
-  uint32_t AllocatePerspectiveItemIndex() { return mPerspectiveItemIndex++; }
+  void AllocatePerspectiveItemIndex() { ++mPerspectiveItemIndex; }
+  uint32_t PerspectiveItemIndex() const { return mPerspectiveItemIndex; }
 
   DisplayListClipState& ClipState() { return mClipState; }
   const ActiveScrolledRoot* CurrentActiveScrolledRoot() { return mCurrentActiveScrolledRoot; }
   const ActiveScrolledRoot* CurrentAncestorASRStackingContextContents() { return mCurrentContainerASR; }
 
   /**
    * Add the current frame to the will-change budget if possible and
    * remeber the outcome. Subsequent calls to IsInWillChangeBudget
deleted file mode 100644
--- a/layout/reftests/svg/smil/event/accesskey-entity-1.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink"
-     class="reftest-wait"
-     onload="
-        document.documentElement.pauseAnimations();
-        document.documentElement.setCurrentTime(0);
-        keypress(0x20);
-        delayedSnapshot(2)">
-  <script xlink:href="event-util.js" type="text/javascript"/>
-  <circle id="circle" r="10"/>
-  <rect width="100" height="100" fill="red">
-    <set attributeName="fill" attributeType="CSS"
-      to="green" begin="accesskey(&#x20;)" dur="4s"/>
-    <set attributeName="width" attributeType="XML"
-      to="200" begin="accesskey(&#x21;)" dur="4s"/>
-  </rect>
-</svg>
deleted file mode 100644
--- a/layout/reftests/svg/smil/event/accesskey-entity-2.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink"
-     class="reftest-wait"
-     onload="
-        document.documentElement.pauseAnimations();
-        document.documentElement.setCurrentTime(0);
-        keypress(0x0D);
-        delayedSnapshot(2)">
-  <script xlink:href="event-util.js" type="text/javascript"/>
-  <circle id="circle" r="10"/>
-  <rect width="100" height="100" fill="red">
-    <set attributeName="fill" attributeType="CSS"
-      to="green" begin="accesskey(&#x0D;)" dur="4s"/>
-  </rect>
-</svg>
--- a/layout/reftests/svg/smil/event/event-util.js
+++ b/layout/reftests/svg/smil/event/event-util.js
@@ -17,21 +17,8 @@ function finish(seekTimeInSeconds)
 function click(targetId)
 {
   var evt = document.createEvent("MouseEvents");
   evt.initMouseEvent("click", true, true, window,
     0, 0, 0, 0, 0, false, false, false, false, 0, null);
   var target = document.getElementById(targetId);
   target.dispatchEvent(evt);
 }
-
-function keypress(charCode)
-{
-  var evt = document.createEvent("KeyboardEvent");
-  evt.initKeyEvent("keypress", true, true, window,
-                   false, // ctrlKeyArg
-                   false, // altKeyArg
-                   false, // shiftKeyArg
-                   false, // metaKeyArg
-                   0,     // keyCode
-                   charCode);
-  document.documentElement.dispatchEvent(evt);
-}
--- a/layout/reftests/svg/smil/event/reftest.list
+++ b/layout/reftests/svg/smil/event/reftest.list
@@ -23,10 +23,8 @@ random-if(Android) == event-begin-timeev
 == event-target-xlink-change-1.svg green-box-ref.svg
 == event-target-xlink-change-2.svg green-box-ref.svg
 == event-target-xlink-change-3.svg green-box-ref.svg
 == event-target-xlink-change-4.svg green-box-ref.svg
 == event-target-surgery-1.svg green-box-ref.svg
 == event-target-surgery-2.svg green-box-ref.svg
 == event-target-surgery-3.svg green-box-ref.svg
 == event-target-non-svg-1.xhtml green-box-ref.xhtml
-== accesskey-entity-1.svg green-box-ref.svg
-== accesskey-entity-2.svg green-box-ref.svg
--- a/python/mozbuild/mozbuild/backend/__init__.py
+++ b/python/mozbuild/mozbuild/backend/__init__.py
@@ -3,16 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 backends = {
     'ChromeMap': 'mozbuild.codecoverage.chrome_map',
     'CompileDB': 'mozbuild.compilation.database',
     'CppEclipse': 'mozbuild.backend.cpp_eclipse',
     'FasterMake': 'mozbuild.backend.fastermake',
     'FasterMake+RecursiveMake': None,
+    'GnConfigGen': 'mozbuild.gn_processor',
+    'GnMozbuildWriter': 'mozbuild.gn_processor',
     'RecursiveMake': 'mozbuild.backend.recursivemake',
     'TestManifest': 'mozbuild.backend.test_manifest',
     'Tup': 'mozbuild.backend.tup',
     'VisualStudio': 'mozbuild.backend.visualstudio',
 }
 
 
 def get_backend_class(name):
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -26,16 +26,17 @@ from mozbuild.frontend.data import (
     ExampleWebIDLInterface,
     Exports,
     IPDLFile,
     FinalTargetPreprocessedFiles,
     FinalTargetFiles,
     GeneratedEventWebIDLFile,
     GeneratedSources,
     GeneratedWebIDLFile,
+    GnProjectData,
     PreprocessedIPDLFile,
     PreprocessedTestWebIDLFile,
     PreprocessedWebIDLFile,
     SharedLibrary,
     TestWebIDLFile,
     UnifiedSources,
     XPIDLFile,
     WebIDLFile,
@@ -309,16 +310,21 @@ class CommonBackend(BuildBackend):
             return False
 
         elif isinstance(obj, Exports):
             objdir_files = [f.full_path for path, files in obj.files.walk() for f in files if isinstance(f, ObjDirPath)]
             if objdir_files:
                 self._handle_generated_sources(objdir_files)
             return False
 
+        elif isinstance(obj, GnProjectData):
+            # These are only handled by special purpose build backends,
+            # ignore them here.
+            return True
+
         else:
             return False
 
         return True
 
     def consume_finished(self):
         if len(self._idl_manager.idls):
             self._handle_idl_manager(self._idl_manager)
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -2037,16 +2037,34 @@ VARIABLES = {
             GYP_DIRS['foo'].input = 'foo/foo.gyp'
             GYP_DIRS['foo'].variables = {
                 'foo': 'bar',
                 (...)
             }
             (...)
         """),
 
+    'GN_DIRS': (StrictOrderingOnAppendListWithFlagsFactory({
+            'variables': dict,
+            'sandbox_vars': dict,
+            'non_unified_sources': StrictOrderingOnAppendList,
+            'mozilla_flags': list,
+        }), list,
+        """List of dirs containing gn files describing targets to build. Attributes:
+            - variables, a dictionary containing variables and values to pass
+              to `gn gen`.
+            - sandbox_vars, a dictionary containing variables and values to
+              pass to the mozbuild processor on top of those derived from gn.
+            - non_unified_sources, a list containing sources files, relative to
+              the current moz.build, that should be excluded from source file
+              unification.
+            - mozilla_flags, a set of flags that if present in the gn config
+              will be mirrored to the resulting mozbuild configuration.
+        """),
+
     'SPHINX_TREES': (dict, dict,
         """Describes what the Sphinx documentation tree will look like.
 
         Keys are relative directories inside the final Sphinx documentation
         tree to install files into. Values are directories (relative to this
         file) whose content to copy into the Sphinx documentation tree.
         """),
 
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -1158,8 +1158,18 @@ class ChromeManifestEntry(ContextDerived
         ContextDerived.__init__(self, context)
         assert isinstance(entry, ManifestEntry)
         self.path = mozpath.join(self.install_target, manifest_path)
         # Ensure the entry is relative to the directory containing the
         # manifest path.
         entry = entry.rebase(mozpath.dirname(manifest_path))
         # Then add the install_target to the entry base directory.
         self.entry = entry.move(mozpath.dirname(self.path))
+
+
+class GnProjectData(ContextDerived):
+    def __init__(self, context, target_dir, gn_dir_attrs, non_unified_sources):
+        ContextDerived.__init__(self, context)
+        self.target_dir = target_dir
+        self.non_unified_sources = non_unified_sources
+        self.gn_input_variables = gn_dir_attrs.variables
+        self.gn_sandbox_variables = gn_dir_attrs.sandbox_vars
+        self.mozilla_flags = gn_dir_attrs.mozilla_flags
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -38,16 +38,17 @@ from .data import (
     DirectoryTraversal,
     Exports,
     FinalTargetFiles,
     FinalTargetPreprocessedFiles,
     GeneratedEventWebIDLFile,
     GeneratedFile,
     GeneratedSources,
     GeneratedWebIDLFile,
+    GnProjectData,
     ExampleWebIDLInterface,
     ExternalStaticLibrary,
     ExternalSharedLibrary,
     HostDefines,
     HostLibrary,
     HostProgram,
     HostRustProgram,
     HostSimpleProgram,
@@ -552,16 +553,36 @@ class TreeMetadataEmitter(LoggingMixin):
             raise SandboxValidationError(
                 'features for %s should not contain duplicates: %s' % (libname, features),
                 context)
 
         return cls(context, libname, cargo_file, crate_type, dependencies,
                    features, cargo_target_dir, **static_args)
 
 
+    def _handle_gn_dirs(self, context):
+        for target_dir in context.get('GN_DIRS', []):
+            context['DIRS'] += [target_dir]
+            gn_dir = context['GN_DIRS'][target_dir]
+            for v in ('variables',):
+                if not getattr(gn_dir, 'variables'):
+                    raise SandboxValidationError('Missing value for '
+                                                 'GN_DIRS["%s"].%s' % (target_dir, v), context)
+
+            non_unified_sources = set()
+            for s in gn_dir.non_unified_sources:
+                source = SourcePath(context, s)
+                if not os.path.exists(source.full_path):
+                    raise SandboxValidationError('Cannot find %s.' % source,
+                                                 context)
+                non_unified_sources.add(mozpath.join(context.relsrcdir, s))
+
+            yield GnProjectData(context, target_dir, gn_dir, non_unified_sources)
+
+
     def _handle_linkables(self, context, passthru, generated_files):
         linkables = []
         host_linkables = []
         def add_program(prog, var):
             if var.startswith('HOST_'):
                 host_linkables.append(prog)
             else:
                 linkables.append(prog)
@@ -957,16 +978,19 @@ class TreeMetadataEmitter(LoggingMixin):
 
         # We only want to emit an InstallationTarget if one of the consulted
         # variables is defined. Later on, we look up FINAL_TARGET, which has
         # the side-effect of populating it. So, we need to do this lookup
         # early.
         if any(k in context for k in ('FINAL_TARGET', 'XPI_NAME', 'DIST_SUBDIR')):
             yield InstallationTarget(context)
 
+        for obj in self._handle_gn_dirs(context):
+            yield obj
+
         # We always emit a directory traversal descriptor. This is needed by
         # the recursive make backend.
         for o in self._emit_directory_traversal_from_context(context): yield o
 
         for obj in self._process_xpidl(context):
             yield obj
 
         computed_flags = ComputedFlags(context, context['COMPILE_FLAGS'])
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/gn_processor.py
@@ -0,0 +1,576 @@
+# 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/.
+
+from __future__ import print_function
+
+from collections import defaultdict
+from copy import deepcopy
+import glob
+import json
+import os
+import subprocess
+import sys
+import types
+
+from mozbuild.backend.base import BuildBackend
+import mozpack.path as mozpath
+from mozbuild.frontend.sandbox import alphabetical_sorted
+from mozbuild.frontend.data import GnProjectData
+from mozbuild.util import expand_variables, mkdir
+
+
+license_header = """# 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/.
+"""
+
+generated_header = """
+  ### This moz.build was AUTOMATICALLY GENERATED from a GN config,  ###
+  ### DO NOT edit it by hand.                                       ###
+"""
+
+
+class MozbuildWriter(object):
+    def __init__(self, fh):
+        self._fh = fh
+        self.indent = ''
+        self._indent_increment = 4
+
+        # We need to correlate a small amount of state here to figure out
+        # which library template to use ("Library()" or "SharedLibrary()")
+        self._library_name = None
+        self._shared_library = None
+
+    def mb_serialize(self, v):
+        if isinstance(v, (bool, list)):
+            return repr(v)
+        return '"%s"' % v
+
+    def finalize(self):
+        if self._library_name:
+            self.write('\n')
+            if self._shared_library:
+                self.write_ln("SharedLibrary(%s)" % self.mb_serialize(self._library_name))
+            else:
+                self.write_ln("Library(%s)" % self.mb_serialize(self._library_name))
+
+    def write(self, content):
+        self._fh.write(content)
+
+    def write_ln(self, line):
+        self.write(self.indent)
+        self.write(line)
+        self.write('\n')
+
+    def write_attrs(self, context_attrs):
+        for k, v in context_attrs.iteritems():
+            if isinstance(v, (list, set)):
+                self.write_mozbuild_list(k, alphabetical_sorted(v))
+            elif isinstance(v, dict):
+                self.write_mozbuild_dict(k, v)
+            else:
+                self.write_mozbuild_value(k, v)
+
+    def write_mozbuild_list(self, key, value):
+        if value:
+            self.write('\n')
+            self.write(self.indent + key)
+            self.write(' += [\n    ' + self.indent)
+            self.write((',\n    ' + self.indent).join(self.mb_serialize(v) for v in value))
+            self.write('\n')
+            self.write_ln(']')
+
+    def write_mozbuild_value(self, key, value):
+        if value:
+            if key == 'LIBRARY_NAME':
+                self._library_name = value
+            elif key == 'FORCE_SHARED_LIB':
+                self._shared_library = True
+            else:
+                self.write('\n')
+                self.write_ln('%s = %s' % (key, self.mb_serialize(value)))
+                self.write('\n')
+
+    def write_mozbuild_dict(self, key, value):
+        # Templates we need to use instead of certain values.
+        replacements = (
+            (('COMPILE_FLAGS', '"WARNINGS_AS_ERRORS"', '[]'), 'AllowCompilerWarnings()'),
+        )
+        if value:
+            self.write('\n')
+            for k, v in value.iteritems():
+                subst_vals = key, self.mb_serialize(k), self.mb_serialize(v)
+                wrote_ln = False
+                for flags, tmpl in replacements:
+                    if subst_vals == flags:
+                        self.write_ln(tmpl)
+                        wrote_ln = True
+
+                if not wrote_ln:
+                    self.write_ln("%s[%s] = %s" % subst_vals)
+
+
+    def write_condition(self, values):
+        def mk_condition(k, v):
+            if not v:
+                return 'not CONFIG["%s"]' % k
+            return 'CONFIG["%s"] == %s' % (k, self.mb_serialize(v))
+
+        self.write('\n')
+        self.write('if ')
+        self.write(' and '.join(mk_condition(k, v) for k, v in values.items()))
+        self.write(':\n')
+        self.indent += ' ' * self._indent_increment
+
+    def terminate_condition(self):
+        assert len(self.indent) >= self._indent_increment
+        self.indent = self.indent[self._indent_increment:]
+
+
+def find_deps(all_targets, target):
+    all_deps = set([target])
+    for dep in all_targets[target]['deps']:
+        if dep not in all_deps:
+            all_deps |= find_deps(all_targets, dep)
+    return all_deps
+
+
+def filter_gn_config(gn_result, config, sandbox_vars, input_vars):
+    # Translates the raw output of gn into just what we'll need to generate a
+    # mozbuild configuration.
+    gn_out = {
+        'targets': {},
+        'sandbox_vars': sandbox_vars,
+        'gn_gen_args': input_vars,
+    }
+
+    gn_mozbuild_vars = (
+        'MOZ_DEBUG',
+        'OS_TARGET',
+        'HOST_CPU_ARCH',
+        'CPU_ARCH',
+    )
+
+    mozbuild_args = {k: config.substs.get(k) for k in gn_mozbuild_vars}
+    gn_out['mozbuild_args'] = mozbuild_args
+    all_deps = find_deps(gn_result['targets'], "//:default")
+
+    for target_fullname in all_deps:
+        raw_spec = gn_result['targets'][target_fullname]
+
+        # TODO: 'executable' will need to be handled here at some point as well.
+        if raw_spec['type'] not in ('static_library', 'shared_library',
+                                    'source_set'):
+            continue
+
+        spec = {}
+        for spec_attr in ('type', 'sources', 'defines', 'include_dirs',
+                          'cflags', 'deps', 'libs'):
+            spec[spec_attr] = raw_spec.get(spec_attr, [])
+            gn_out['targets'][target_fullname] = spec
+
+    return gn_out
+
+
+def process_gn_config(gn_config, srcdir, config, output, non_unified_sources,
+                      sandbox_vars, mozilla_flags):
+    # Translates a json gn config into attributes that can be used to write out
+    # moz.build files for this configuration.
+
+    # Much of this code is based on similar functionality in `gyp_reader.py`.
+
+    mozbuild_attrs = {'mozbuild_args': gn_config.get('mozbuild_args', None),
+                      'dirs': {}}
+
+    targets = gn_config["targets"]
+
+    project_relsrcdir = mozpath.relpath(srcdir, config.topsrcdir)
+
+    def target_info(fullname):
+        path, name = target_fullname.split(':')
+        # Stripping '//' gives us a path relative to the project root,
+        # adding a suffix avoids name collisions with libraries already
+        # in the tree (like "webrtc").
+        return path.lstrip('//'), name + '_gn'
+
+    # Process all targets from the given gn project and its dependencies.
+    for target_fullname, spec in targets.iteritems():
+
+        target_path, target_name = target_info(target_fullname)
+        context_attrs = {}
+
+        # Remove leading 'lib' from the target_name if any, and use as
+        # library name.
+        name = target_name
+        if spec['type'] in ('static_library', 'shared_library', 'source_set'):
+            if name.startswith('lib'):
+                name = name[3:]
+            context_attrs['LIBRARY_NAME'] = name.decode('utf-8')
+        else:
+            raise Exception('The following GN target type is not currently '
+                            'consumed by moz.build: "%s". It may need to be '
+                            'added, or you may need to re-run the '
+                            '`GnConfigGen` step.' % spec['type'])
+
+        if spec['type'] == 'shared_library':
+            context_attrs['FORCE_SHARED_LIB'] = True
+
+        sources = []
+        unified_sources = []
+        extensions = set()
+        use_defines_in_asflags = False
+
+        for f in spec.get('sources', []):
+            f = f.lstrip("//")
+            ext = mozpath.splitext(f)[-1]
+            extensions.add(ext)
+            src = '%s/%s' % (project_relsrcdir, f)
+            if ext == '.h':
+                continue
+            elif ext == '.def':
+                context_attrs['SYMBOLS_FILE'] = src
+            elif ext != '.S' and src not in non_unified_sources:
+                unified_sources.append('/%s' % src)
+            else:
+                sources.append('/%s' % src)
+            # The Mozilla build system doesn't use DEFINES for building
+            # ASFILES.
+            if ext == '.s':
+                use_defines_in_asflags = True
+
+        context_attrs['SOURCES'] = sources
+        context_attrs['UNIFIED_SOURCES'] = unified_sources
+
+        context_attrs['DEFINES'] = {}
+        for define in spec.get('defines', []):
+            if '=' in define:
+                name, value = define.split('=', 1)
+                context_attrs['DEFINES'][name] = value
+            else:
+                context_attrs['DEFINES'][define] = True
+
+        context_attrs['LOCAL_INCLUDES'] = []
+        for include in spec.get('include_dirs', []):
+            # GN will have resolved all these paths relative to the root of
+            # the project indicated by "//".
+            if include.startswith('//'):
+                include = include[2:]
+            # moz.build expects all LOCAL_INCLUDES to exist, so ensure they do.
+            if include.startswith('/'):
+                resolved = mozpath.abspath(mozpath.join(config.topsrcdir, include[1:]))
+            else:
+                resolved = mozpath.abspath(mozpath.join(srcdir, include))
+            if not os.path.exists(resolved):
+                # GN files may refer to include dirs that are outside of the
+                # tree or we simply didn't vendor. Print a warning in this case.
+                if not resolved.endswith('gn-output/gen'):
+                    print("Included path: '%s' does not exist, dropping include from GN "
+                          "configuration." % resolved, file=sys.stderr)
+                continue
+            if not include.startswith('/'):
+                include = '/%s/%s' % (project_relsrcdir, include)
+            context_attrs['LOCAL_INCLUDES'] += [include]
+
+        context_attrs['ASFLAGS'] = spec.get('asflags_mozilla', [])
+        if use_defines_in_asflags and defines:
+            context_attrs['ASFLAGS'] += ['-D' + d for d in defines]
+        flags = [f for f in spec.get('cflags', []) if f in mozilla_flags]
+        if flags:
+            suffix_map = {
+                '.c': 'CFLAGS',
+                '.cpp': 'CXXFLAGS',
+                '.cc': 'CXXFLAGS',
+                '.m': 'CMFLAGS',
+                '.mm': 'CMMFLAGS',
+            }
+            variables = (suffix_map[e] for e in extensions if e in suffix_map)
+            for var in variables:
+                for f in flags:
+                    # We may be getting make variable references out of the
+                    # gn data, and we don't want those in emitted data, so
+                    # substitute them with their actual value.
+                    f = expand_variables(f, config.substs).split()
+                    if not f:
+                        continue
+                    # the result may be a string or a list.
+                    if isinstance(f, types.StringTypes):
+                        context_attrs.setdefault(var, []).append(f)
+                    else:
+                        context_attrs.setdefault(var, []).extend(f)
+
+        context_attrs['OS_LIBS'] = []
+        for lib in spec.get('libs', []):
+            lib_name = os.path.splitext(lib)[0]
+            if lib.endswith('.framework'):
+                context_attrs['OS_LIBS'] += ['-framework ' + lib_name]
+            else:
+                context_attrs['OS_LIBS'] += [lib_name]
+
+        # Add some features to all contexts. Put here in case LOCAL_INCLUDES
+        # order matters.
+        context_attrs['LOCAL_INCLUDES'] += [
+            '!/ipc/ipdl/_ipdlheaders',
+            '/ipc/chromium/src',
+            '/ipc/glue',
+        ]
+        # These get set via VC project file settings for normal GYP builds.
+        # TODO: Determine if these defines are needed for GN builds.
+        if gn_config['mozbuild_args']['OS_TARGET'] == 'WINNT':
+            context_attrs['DEFINES']['UNICODE'] = True
+            context_attrs['DEFINES']['_UNICODE'] = True
+
+        context_attrs['COMPILE_FLAGS'] = {
+            'STL': [],
+            'OS_INCLUDES': [],
+        }
+
+        for key, value in sandbox_vars.items():
+            if context_attrs.get(key) and isinstance(context_attrs[key], list):
+                # If we have a key from sandbox_vars that's also been
+                # populated here we use the value from sandbox_vars as our
+                # basis rather than overriding outright.
+                context_attrs[key] = value + context_attrs[key]
+            elif context_attrs.get(key) and isinstance(context_attrs[key], dict):
+                context_attrs[key].update(value)
+            else:
+                context_attrs[key] = value
+
+        target_relsrcdir = mozpath.join(project_relsrcdir, target_path, target_name)
+        mozbuild_attrs['dirs'][target_relsrcdir] = context_attrs
+
+    return mozbuild_attrs
+
+
+def find_common_attrs(config_attributes):
+    # Returns the intersection of the given configs and prunes the inputs
+    # to no longer contain these common attributes.
+
+    common_attrs = deepcopy(config_attributes[0])
+
+    def make_intersection(reference, input_attrs):
+        # Modifies `reference` so that after calling this function it only
+        # contains parts it had in common with in `input_attrs`.
+
+        for k, input_value in input_attrs.items():
+            # Anything in `input_attrs` must match what's already in
+            # `reference`.
+            common_value = reference.get(k)
+            if common_value:
+                if isinstance(input_value, list):
+                    input_value = set(input_value)
+                    reference[k] = [i for i in common_value if i in input_value]
+                elif isinstance(input_value, dict):
+                    reference[k] = {key: value for key, value in common_value.items()
+                                    if key in input_value and value == input_value[key]}
+                elif input_value != common_value:
+                    del reference[k]
+            elif k in reference:
+                del reference[k]
+
+        # Additionally, any keys in `reference` that aren't in `input_attrs`
+        # must be deleted.
+        for k in set(reference.keys()) - set(input_attrs.keys()):
+            del reference[k]
+
+    def make_difference(reference, input_attrs):
+        # Modifies `input_attrs` so that after calling this function it contains
+        # no parts it has in common with in `reference`.
+        for k, input_value in input_attrs.items():
+            common_value = reference.get(k)
+            if common_value:
+                if isinstance(input_value, list):
+                    common_value = set(common_value)
+                    input_attrs[k] = [i for i in input_value if i not in common_value]
+                elif isinstance(input_value, dict):
+                    input_attrs[k] = {key: value for key, value in input_value.items()
+                                      if key not in common_value}
+                else:
+                    del input_attrs[k]
+
+    for config_attr_set in config_attributes[1:]:
+        make_intersection(common_attrs, config_attr_set)
+
+    for config_attr_set in config_attributes:
+        make_difference(common_attrs, config_attr_set)
+
+    return common_attrs
+
+
+def write_mozbuild(config, srcdir, output, non_unified_sources, gn_config_files,
+                   mozilla_flags):
+
+    all_mozbuild_results = []
+
+    for path in gn_config_files:
+        with open(path, 'r') as fh:
+            gn_config = json.load(fh)
+            mozbuild_attrs = process_gn_config(gn_config, srcdir, config,
+                                               output, non_unified_sources,
+                                               gn_config['sandbox_vars'],
+                                               mozilla_flags)
+            all_mozbuild_results.append(mozbuild_attrs)
+
+    # Translate {config -> {dirs -> build info}} into
+    #           {dirs -> [(config, build_info)]}
+    configs_by_dir = defaultdict(list)
+    for config_attrs in all_mozbuild_results:
+        mozbuild_args = config_attrs['mozbuild_args']
+        dirs = config_attrs['dirs']
+        for d, build_data in dirs.items():
+            configs_by_dir[d].append((mozbuild_args, build_data))
+
+    for relsrcdir, configs in configs_by_dir.items():
+        target_srcdir = mozpath.join(config.topsrcdir, relsrcdir)
+        mkdir(target_srcdir)
+
+        target_mozbuild = mozpath.join(target_srcdir, 'moz.build')
+        with open(target_mozbuild, 'w') as fh:
+            mb = MozbuildWriter(fh)
+            mb.write(license_header)
+            mb.write('\n')
+            mb.write(generated_header)
+
+            all_attr_sets = [attrs for _, attrs in configs]
+            all_args = [args for args, _ in configs]
+
+            # Start with attributes that will be a part of the mozconfig
+            # for every configuration, then factor by other potentially useful
+            # combinations.
+            for attrs in ((),
+                          ('MOZ_DEBUG',), ('OS_TARGET',), ('MOZ_DEBUG', 'OS_TARGET',),
+                          ('MOZ_DEBUG', 'OS_TARGET', 'CPU_ARCH', 'HOST_CPU_ARCH')):
+                conditions = set()
+                for args in all_args:
+                    cond = tuple(((k, args.get(k)) for k in attrs))
+                    conditions.add(cond)
+                for cond in conditions:
+                    common_attrs = find_common_attrs([attrs for args, attrs in configs if
+                                                      all(args.get(k) == v for k, v in cond)])
+                    if any(common_attrs.values()):
+                        if cond:
+                            mb.write_condition(dict(cond))
+                        mb.write_attrs(common_attrs)
+                        if cond:
+                            mb.terminate_condition()
+
+            mb.finalize()
+
+    dirs_mozbuild = mozpath.join(srcdir, 'moz.build')
+    with open(dirs_mozbuild, 'w') as fh:
+        mb = MozbuildWriter(fh)
+        mb.write(license_header)
+        mb.write('\n')
+        mb.write(generated_header)
+
+        # Not every srcdir is present for every config, which needs to be
+        # reflected in the generated root moz.build.
+        dirs_by_config = {tuple(v['mozbuild_args'].items()): set(v['dirs'].keys())
+                          for v in all_mozbuild_results}
+
+        for attrs in ((), ('OS_TARGET',), ('OS_TARGET', 'CPU_ARCH')):
+
+            conditions = set()
+            for args in dirs_by_config.keys():
+                cond = tuple(((k, dict(args).get(k)) for k in attrs))
+                conditions.add(cond)
+
+            for cond in conditions:
+                common_dirs = None
+                for args, dir_set in dirs_by_config.items():
+                    if all(dict(args).get(k) == v for k, v in cond):
+                        if common_dirs is None:
+                            common_dirs = deepcopy(dir_set)
+                        else:
+                            common_dirs &= dir_set
+
+                for args, dir_set in dirs_by_config.items():
+                    if all(dict(args).get(k) == v for k, v in cond):
+                        dir_set -= common_dirs
+
+                if common_dirs:
+                    if cond:
+                        mb.write_condition(dict(cond))
+                    mb.write_mozbuild_list('DIRS',
+                                           ['/%s' % d for d in common_dirs])
+                    if cond:
+                        mb.terminate_condition()
+
+
+def generate_gn_config(config, srcdir, output, non_unified_sources, gn_binary,
+                       input_variables, sandbox_variables):
+
+    def str_for_arg(v):
+        if v in (True, False):
+            return str(v).lower()
+        return '"%s"' % v
+
+    gn_args = '--args=%s' % ' '.join(['%s=%s' % (k, str_for_arg(v)) for k, v
+                                      in input_variables.iteritems()])
+    gn_arg_string = '_'.join([str(input_variables[k]) for k in sorted(input_variables.keys())])
+    out_dir = mozpath.join(config.topobjdir, 'gn-output')
+    gen_args = [
+        config.substs['GN'], 'gen', out_dir, gn_args, '--ide=json',
+    ]
+    print("Running \"%s\"" % ' '.join(gen_args), file=sys.stderr)
+    subprocess.check_call(gen_args, cwd=srcdir, stderr=subprocess.STDOUT)
+
+
+    gn_config_file = mozpath.join(out_dir, 'project.json')
+
+    with open(gn_config_file, 'r') as fh:
+        gn_out = json.load(fh)
+        gn_out = filter_gn_config(gn_out, config, sandbox_variables,
+                                  input_variables)
+
+    os.remove(gn_config_file)
+
+    gn_out_file = mozpath.join(out_dir, gn_arg_string + '.json')
+    with open(gn_out_file, 'w') as fh:
+        json.dump(gn_out, fh, indent=4, sort_keys=True, separators=(',', ': '))
+    print("Wrote gn config to %s" % gn_out_file)
+
+
+class GnConfigGenBackend(BuildBackend):
+
+    def consume_object(self, obj):
+        if isinstance(obj, GnProjectData):
+            gn_binary = obj.config.substs.get('GN')
+            if not gn_binary:
+                raise Exception("The GN program must be present to generate GN configs.")
+
+            generate_gn_config(obj.config, mozpath.join(obj.srcdir, obj.target_dir),
+                               mozpath.join(obj.objdir, obj.target_dir),
+                               obj.non_unified_sources, gn_binary,
+                               obj.gn_input_variables, obj.gn_sandbox_variables)
+        return True
+
+    def consume_finished(self):
+        pass
+
+
+class GnMozbuildWriterBackend(BuildBackend):
+
+    def consume_object(self, obj):
+        if isinstance(obj, GnProjectData):
+            gn_config_files = glob.glob(mozpath.join(obj.srcdir, 'gn-configs', '*.json'))
+            if not gn_config_files:
+                # Check the objdir for a gn-config in to aide debugging in cases
+                # someone is running both steps on the same machine and want to
+                # sanity check moz.build generation for a particular config.
+                gn_config_files = glob.glob(mozpath.join(obj.topobjdir,
+                                                         'gn-output', '*.json'))
+            if gn_config_files:
+                print("Writing moz.build files based on the following gn configs: %s" %
+                      gn_config_files)
+                write_mozbuild(obj.config, mozpath.join(obj.srcdir, obj.target_dir),
+                               mozpath.join(obj.objdir, obj.target_dir),
+                               obj.non_unified_sources, gn_config_files,
+                               obj.mozilla_flags)
+            else:
+                print("Ignoring gn project '%s', no config files found in '%s'" %
+                      (obj.srcdir, mozpath.join(obj.srcdir, 'gn-configs')))
+        return True
+
+    def consume_finished(self):
+        pass
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -164,17 +164,35 @@ CONFIGS = defaultdict(lambda: {
     'prog-lib-c-only': {
         'defines': {},
         'non_global_defines': [],
         'substs': {
             'COMPILE_ENVIRONMENT': '1',
             'LIB_SUFFIX': '.a',
             'BIN_SUFFIX': '',
         },
-    }
+    },
+    'gn-processor': {
+        'defines': {},
+        'non_global_defines': [],
+        'substs': {
+            'BUILD_BACKENDS': [
+                'GnMozbuildWriter',
+                'RecursiveMake',
+            ],
+            'COMPILE_ENVIRONMENT': '1',
+            'STL_FLAGS': [],
+            'RUST_TARGET': 'x86_64-unknown-linux-gnu',
+            'LIB_PREFIX': 'lib',
+            'RUST_LIB_PREFIX': 'lib',
+            'LIB_SUFFIX': 'a',
+            'RUST_LIB_SUFFIX': 'a',
+            'OS_TARGET': 'Darwin',
+        },
+    },
 })
 
 
 class BackendTester(unittest.TestCase):
     def setUp(self):
         self._old_env = dict(os.environ)
         os.environ.pop('MOZ_OBJDIR', None)
 
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/gn-processor/gn-configs/x64_False_x64_linux.json
@@ -0,0 +1,47 @@
+{
+  "mozbuild_args": {
+    "HOST_CPU_ARCH": "x86_64", 
+    "OS_TARGET": "Linux", 
+    "CPU_ARCH": "x86_64",
+    "MOZ_DEBUG": false
+  }, 
+  "ta