merge autoland to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 30 Oct 2017 23:42:58 +0100
changeset 389084 dd0f265a130098cda83a0c25c7617d2365b28f2d
parent 388991 befd2dd89771edd86d05a92b6f7ce2ccde6835c3 (current diff)
parent 389083 301666d1d339f3c3a22ebce3c0c640e076d779c4 (diff)
child 389169 083a9c84fbd09a6ff9bfecabbf773650842fe1c0
push id32777
push userarchaeopteryx@coole-files.de
push dateMon, 30 Oct 2017 22:44:45 +0000
treeherdermozilla-central@dd0f265a1300 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.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 MozReview-Commit-ID: BnX9U7tZ4zU
third_party/python/json-e/MANIFEST.in
third_party/python/json-e/PKG-INFO
third_party/python/json-e/setup.cfg
third_party/python/json-e/setup.py
third_party/rust/byteorder/src/new.rs
third_party/rust/httparse/.travis_after.sh
third_party/rust/hyper/build.rs
third_party/rust/libc/ci/android-accept-licenses.sh
third_party/rust/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile
third_party/rust/libc/ci/run-docker.sh
third_party/rust/libc/src/redox.rs
third_party/rust/libc/src/unix/notbsd/linux/musl/b32/asmjs.rs
third_party/rust/unicode-bidi/benches/basic.rs
third_party/rust/unicode-bidi/benches/udhr.rs
third_party/rust/unicode-bidi/benches/udhr_data/README.md
third_party/rust/unicode-bidi/tests/conformance_tests.rs
third_party/rust/unicode-bidi/tools/generate.py
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -90,29 +90,30 @@ var BrowserPageActions = {
   /**
    * Adds or removes as necessary DOM nodes for the action in the panel.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
    */
   placeActionInPanel(action) {
     let insertBeforeID = PageActions.nextActionIDInPanel(action);
-    let id = this._panelButtonNodeIDForActionID(action.id);
+    let id = this.panelButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
     if (!node) {
       let panelViewNode;
       [node, panelViewNode] = this._makePanelButtonNodeForAction(action);
       node.id = id;
       let insertBeforeNode = null;
       if (insertBeforeID) {
         let insertBeforeNodeID =
-          this._panelButtonNodeIDForActionID(insertBeforeID);
+          this.panelButtonNodeIDForActionID(insertBeforeID);
         insertBeforeNode = document.getElementById(insertBeforeNodeID);
       }
       this.mainViewBodyNode.insertBefore(node, insertBeforeNode);
+      this.updateAction(action);
       action.onPlacedInPanel(node);
       if (panelViewNode) {
         action.subview.onPlaced(panelViewNode);
       }
     }
   },
 
   _makePanelButtonNodeForAction(action) {
@@ -122,20 +123,16 @@ var BrowserPageActions = {
     }
 
     let buttonNode = document.createElement("toolbarbutton");
     buttonNode.classList.add(
       "subviewbutton",
       "subviewbutton-iconic",
       "pageAction-panel-button"
     );
-    buttonNode.setAttribute("label", action.title);
-    if (action.iconURL) {
-      buttonNode.style.listStyleImage = `url('${action.iconURL}')`;
-    }
     if (action.nodeAttributes) {
       for (let name in action.nodeAttributes) {
         buttonNode.setAttribute(name, action.nodeAttributes[name]);
       }
     }
     let panelViewNode = null;
     if (action.subview) {
       buttonNode.classList.add("subviewbutton-nav");
@@ -172,28 +169,59 @@ var BrowserPageActions = {
       buttonNode.addEventListener("command", event => {
         button.onCommand(event, buttonNode);
       });
       bodyNode.appendChild(buttonNode);
     }
     return panelViewNode;
   },
 
-  _toggleActivatedActionPanelForAction(action) {
-    let panelNode = this.activatedActionPanelNode;
+  /**
+   * Shows or hides a panel for an action.  You can supply your own panel;
+   * otherwise one is created.
+   *
+   * @param  action (PageActions.Action, required)
+   *         The action for which to toggle the panel.  If the action is in the
+   *         urlbar, then the panel will be anchored to it.  Otherwise, a
+   *         suitable anchor will be used.
+   * @param  panelNode (DOM node, optional)
+   *         The panel to use.  This method takes a hands-off approach with
+   *         regard to your panel in terms of attributes, styling, etc.
+   */
+  togglePanelForAction(action, panelNode = null) {
+    let aaPanelNode = this.activatedActionPanelNode;
     if (panelNode) {
-      panelNode.hidePopup();
-      return null;
+      if (panelNode.state != "closed") {
+        panelNode.hidePopup();
+        return;
+      }
+      if (aaPanelNode) {
+        aaPanelNode.hidePopup();
+      }
+    } else if (aaPanelNode) {
+      aaPanelNode.hidePopup();
+      return;
+    } else {
+      panelNode = this._makeActivatedActionPanelForAction(action);
     }
 
-    // Before creating the panel, get the anchor node for it because it'll throw
-    // if there isn't one (which shouldn't happen, but still).
+    // Hide the main panel before showing the action's panel.
+    this.panelNode.hidePopup();
+
     let anchorNode = this.panelAnchorNodeForAction(action);
+    anchorNode.setAttribute("open", "true");
+    panelNode.addEventListener("popuphiding", () => {
+      anchorNode.removeAttribute("open");
+    }, { once: true });
 
-    panelNode = document.createElement("panel");
+    panelNode.openPopup(anchorNode, "bottomcenter topright");
+  },
+
+  _makeActivatedActionPanelForAction(action) {
+    let panelNode = document.createElement("panel");
     panelNode.id = this._activatedActionPanelID;
     panelNode.classList.add("cui-widget-panel");
     panelNode.setAttribute("actionID", action.id);
     panelNode.setAttribute("role", "group");
     panelNode.setAttribute("type", "arrow");
     panelNode.setAttribute("flip", "slide");
     panelNode.setAttribute("noautofocus", "true");
     panelNode.setAttribute("tabspecific", "true");
@@ -221,38 +249,30 @@ var BrowserPageActions = {
     popupSet.appendChild(panelNode);
     panelNode.addEventListener("popuphidden", () => {
       if (iframeNode) {
         action.onIframeHidden(iframeNode, panelNode);
       }
       panelNode.remove();
     }, { once: true });
 
-    panelNode.addEventListener("popuphiding", () => {
-      if (iframeNode) {
+    if (iframeNode) {
+      panelNode.addEventListener("popupshown", () => {
+        action.onIframeShown(iframeNode, panelNode);
+      }, { once: true });
+      panelNode.addEventListener("popuphiding", () => {
         action.onIframeHiding(iframeNode, panelNode);
-      }
-      anchorNode.removeAttribute("open");
-    }, { once: true });
+      }, { once: true });
+    }
 
     if (panelViewNode) {
       action.subview.onPlaced(panelViewNode);
       action.subview.onShowing(panelViewNode);
     }
 
-    // Hide the main page action panel before showing the activated-action
-    // panel.
-    this.panelNode.hidePopup();
-    panelNode.openPopup(anchorNode, "bottomcenter topright");
-    anchorNode.setAttribute("open", "true");
-
-    if (iframeNode) {
-      action.onIframeShown(iframeNode, panelNode);
-    }
-
     return panelNode;
   },
 
   // For tests.
   get _disablePanelAnimations() {
     return this.__disablePanelAnimations || false;
   },
   set _disablePanelAnimations(val) {
@@ -269,24 +289,24 @@ var BrowserPageActions = {
    * be anchored.  If the action is null, a sensible anchor is returned.
    *
    * @param  action (PageActions.Action, optional)
    *         The action you want to anchor.
    * @return (DOM node, nonnull) The node to which the action should be
    *         anchored.
    */
   panelAnchorNodeForAction(action, event) {
-    // Try each of the following nodes in order, using the first that's visible.
     if (event && event.target.closest("panel")) {
       return this.mainButtonNode;
     }
 
+    // Try each of the following nodes in order, using the first that's visible.
     let potentialAnchorNodeIDs = [
       action && action.anchorIDOverride,
-      action && this._urlbarButtonNodeIDForActionID(action.id),
+      action && this.urlbarButtonNodeIDForActionID(action.id),
       this.mainButtonNode.id,
       "identity-icon",
     ];
     let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindowUtils);
     for (let id of potentialAnchorNodeIDs) {
       if (id) {
         let node = document.getElementById(id);
@@ -313,17 +333,17 @@ var BrowserPageActions = {
   /**
    * Adds or removes as necessary a DOM node for the given action in the urlbar.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
    */
   placeActionInUrlbar(action) {
     let insertBeforeID = PageActions.nextActionIDInUrlbar(action);
-    let id = this._urlbarButtonNodeIDForActionID(action.id);
+    let id = this.urlbarButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
 
     if (!action.shownInUrlbar) {
       if (node) {
         if (action.__urlbarNodeInMarkup) {
           node.hidden = true;
         } else {
           node.remove();
@@ -342,46 +362,41 @@ var BrowserPageActions = {
       node.id = id;
     }
 
     if (newlyPlaced) {
       let parentNode = this.mainButtonNode.parentNode;
       let insertBeforeNode = null;
       if (insertBeforeID) {
         let insertBeforeNodeID =
-          this._urlbarButtonNodeIDForActionID(insertBeforeID);
+          this.urlbarButtonNodeIDForActionID(insertBeforeID);
         insertBeforeNode = document.getElementById(insertBeforeNodeID);
       }
       parentNode.insertBefore(node, insertBeforeNode);
+      this.updateAction(action);
       action.onPlacedInUrlbar(node);
 
       // urlbar buttons should always have tooltips, so if the node doesn't have
       // one, then as a last resort use the label of the corresponding panel
       // button.  Why not set tooltiptext to action.title when the node is
       // created?  Because the consumer may set a title dynamically.
       if (!node.hasAttribute("tooltiptext")) {
-        let panelNodeID = this._panelButtonNodeIDForActionID(action.id);
+        let panelNodeID = this.panelButtonNodeIDForActionID(action.id);
         let panelNode = document.getElementById(panelNodeID);
         if (panelNode) {
           node.setAttribute("tooltiptext", panelNode.getAttribute("label"));
         }
       }
     }
   },
 
   _makeUrlbarButtonNode(action) {
     let buttonNode = document.createElement("image");
     buttonNode.classList.add("urlbar-icon", "urlbar-page-action");
     buttonNode.setAttribute("role", "button");
-    if (action.tooltip) {
-      buttonNode.setAttribute("tooltiptext", action.tooltip);
-    }
-    if (action.iconURL) {
-      buttonNode.style.listStyleImage = `url('${action.iconURL}')`;
-    }
     buttonNode.setAttribute("context", "pageActionPanelContextMenu");
     buttonNode.addEventListener("contextmenu", event => {
       BrowserPageActions.onContextMenu(event);
     });
     if (action.nodeAttributes) {
       for (let name in action.nodeAttributes) {
         buttonNode.setAttribute(name, action.nodeAttributes[name]);
       }
@@ -399,85 +414,142 @@ var BrowserPageActions = {
    *         The action to remove.
    */
   removeAction(action) {
     this._removeActionFromPanel(action);
     this._removeActionFromUrlbar(action);
   },
 
   _removeActionFromPanel(action) {
-    let id = this._panelButtonNodeIDForActionID(action.id);
+    let id = this.panelButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
     if (node) {
       node.remove();
     }
     if (action.subview) {
       let panelViewNodeID = this._panelViewNodeIDForActionID(action.id, false);
       let panelViewNode = document.getElementById(panelViewNodeID);
       if (panelViewNode) {
         panelViewNode.remove();
       }
     }
     // If there are now no more non-built-in actions, remove the separator
     // between the built-ins and non-built-ins.
     if (!PageActions.nonBuiltInActions.length) {
       let separator = document.getElementById(
-        this._panelButtonNodeIDForActionID(
+        this.panelButtonNodeIDForActionID(
           PageActions.ACTION_ID_BUILT_IN_SEPARATOR
         )
       );
       if (separator) {
         separator.remove();
       }
     }
   },
 
   _removeActionFromUrlbar(action) {
-    let id = this._urlbarButtonNodeIDForActionID(action.id);
+    let id = this.urlbarButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
     if (node) {
       node.remove();
     }
   },
 
   /**
-   * Updates the DOM nodes of an action to reflect its changed iconURL.
+   * Updates the DOM nodes of an action to reflect either a changed property or
+   * all properties.
    *
    * @param  action (PageActions.Action, required)
    *         The action to update.
+   * @param  nameToUpdate (string, optional)
+   *         The property's name.  If not given, then DOM nodes will be updated
+   *         to reflect the current values of all properties.
    */
-  updateActionIconURL(action) {
-    let url = action.iconURL ? `url('${action.iconURL}')` : null;
+  updateAction(action, nameToUpdate = null) {
+    let names = nameToUpdate ? [nameToUpdate] : [
+      "disabled",
+      "iconURL",
+      "title",
+      "tooltip",
+    ];
+    for (let name of names) {
+      let upper = name[0].toUpperCase() + name.substr(1);
+      this[`_updateAction${upper}`](action);
+    }
+  },
+
+  _updateActionDisabled(action) {
     let nodeIDs = [
-      this._panelButtonNodeIDForActionID(action.id),
-      this._urlbarButtonNodeIDForActionID(action.id),
+      this.panelButtonNodeIDForActionID(action.id),
+      this.urlbarButtonNodeIDForActionID(action.id),
     ];
     for (let nodeID of nodeIDs) {
       let node = document.getElementById(nodeID);
       if (node) {
-        if (url) {
-          node.style.listStyleImage = url;
+        if (action.getDisabled(window)) {
+          node.setAttribute("disabled", "true");
         } else {
-          node.style.removeProperty("list-style-image");
+          node.removeAttribute("disabled");
         }
       }
     }
   },
 
-  /**
-   * Updates the DOM nodes of an action to reflect its changed title.
-   *
-   * @param  action (PageActions.Action, required)
-   *         The action to update.
-   */
-  updateActionTitle(action) {
-    let id = this._panelButtonNodeIDForActionID(action.id);
-    let node = document.getElementById(id);
+  _updateActionIconURL(action) {
+    let nodeIDs = [
+      this.panelButtonNodeIDForActionID(action.id),
+      this.urlbarButtonNodeIDForActionID(action.id),
+    ];
+    for (let nodeID of nodeIDs) {
+      let node = document.getElementById(nodeID);
+      if (node) {
+        for (let size of [16, 32]) {
+          let url = action.iconURLForSize(size, window);
+          let prop = `--pageAction-image-${size}px`;
+          if (url) {
+            node.style.setProperty(prop, `url("${url}")`);
+          } else {
+            node.style.removeProperty(prop);
+          }
+        }
+      }
+    }
+  },
+
+  _updateActionTitle(action) {
+    let title = action.getTitle(window);
+    if (!title) {
+      // `title` is a required action property, but the bookmark action's is an
+      // empty string since its actual title is set via
+      // BookmarkingUI.updateBookmarkPageMenuItem().  The purpose of this early
+      // return is to ignore that empty title.
+      return;
+    }
+    let attrNamesByNodeIDFnName = {
+      panelButtonNodeIDForActionID: "label",
+      urlbarButtonNodeIDForActionID: "aria-label",
+    };
+    for (let [fnName, attrName] of Object.entries(attrNamesByNodeIDFnName)) {
+      let nodeID = this[fnName](action.id);
+      let node = document.getElementById(nodeID);
+      if (node) {
+        node.setAttribute(attrName, title);
+      }
+    }
+    // tooltiptext falls back to the title, so update it, too.
+    this._updateActionTooltip(action);
+  },
+
+  _updateActionTooltip(action) {
+    let node = document.getElementById(
+      this.urlbarButtonNodeIDForActionID(action.id)
+    );
     if (node) {
-      node.setAttribute("label", action.title);
+      let tooltip = action.getTooltip(window) || action.getTitle(window);
+      node.setAttribute("tooltiptext", tooltip);
     }
   },
 
   doCommandForAction(action, event, buttonNode) {
     if (event && event.type == "click" && event.button != 0) {
       return;
     }
     PageActions.logTelemetry("used", action, buttonNode);
@@ -491,17 +563,17 @@ var BrowserPageActions = {
       this.multiViewNode.showSubView(panelViewNode, buttonNode);
       return;
     }
     // Otherwise, hide the main popup in case it was open:
     this.panelNode.hidePopup();
 
     // Toggle the activated action's panel if necessary
     if (action.subview || action.wantsIframe) {
-      this._toggleActivatedActionPanelForAction(action);
+      this.togglePanelForAction(action);
       return;
     }
 
     // Otherwise, run the action.
     action.onCommand(event, buttonNode);
   },
 
   /**
@@ -530,23 +602,35 @@ var BrowserPageActions = {
         }
         actionID = this._actionIDForNodeID(n.id);
         action = PageActions.actionForID(actionID);
       }
     }
     return action;
   },
 
-  // The ID of the given action's top-level button in the panel.
-  _panelButtonNodeIDForActionID(actionID) {
+  /**
+   * The ID of the given action's top-level button in the main panel.
+   *
+   * @param  actionID (string, required)
+   *         The action ID.
+   * @return (string) The ID of the action's button in the main panel.
+   */
+  panelButtonNodeIDForActionID(actionID) {
     return `pageAction-panel-${actionID}`;
   },
 
-  // The ID of the given action's button in the urlbar.
-  _urlbarButtonNodeIDForActionID(actionID) {
+  /**
+   * The ID of the given action's button in the urlbar.
+   *
+   * @param  actionID (string, required)
+   *         The action ID.
+   * @return (string) The ID of the action's urlbar button node.
+   */
+  urlbarButtonNodeIDForActionID(actionID) {
     let action = PageActions.actionForID(actionID);
     if (action && action.urlbarIDOverride) {
       return action.urlbarIDOverride;
     }
     return `pageAction-urlbar-${actionID}`;
   },
 
   // The ID of the given action's panelview.
@@ -613,17 +697,17 @@ var BrowserPageActions = {
    * Show the page action panel
    *
    * @param  event (DOM event, optional)
    *         The event that triggers showing the panel. (such as a mouse click,
    *         if the user clicked something to open the panel)
    */
   showPanel(event = null) {
     for (let action of PageActions.actions) {
-      let buttonNodeID = this._panelButtonNodeIDForActionID(action.id);
+      let buttonNodeID = this.panelButtonNodeIDForActionID(action.id);
       let buttonNode = document.getElementById(buttonNodeID);
       action.onShowingInPanel(buttonNode);
     }
 
     this.panelNode.hidden = false;
     this.panelNode.addEventListener("popuphiding", () => {
       this.mainButtonNode.removeAttribute("open");
     }, {once: true});
@@ -688,30 +772,47 @@ var BrowserPageActions = {
     let telemetryType = this._contextAction.shownInUrlbar ? "removed" : "added";
     PageActions.logTelemetry(telemetryType, this._contextAction);
     this._contextAction.shownInUrlbar = !this._contextAction.shownInUrlbar;
   },
 
   _contextAction: null,
 
   /**
-   * A bunch of strings (labels for actions and the like) are defined in DTD,
-   * but actions are created in JS.  So what we do is add a bunch of attributes
-   * to the page action panel's definition in the markup, whose values hold
-   * these DTD strings.  Then when each built-in action is set up, we get the
-   * related strings from the panel node and set up the action's node with them.
+   * Titles for a few of the built-in actions are defined in DTD, but the
+   * actions are created in JS.  So what we do is for each title, set an
+   * attribute in markup on the main page action panel whose value is the DTD
+   * string.  In gBuiltInActions, where the built-in actions are defined, we set
+   * the action's initial title to the name of this attribute.  Then when the
+   * action is set up, we get the action's current title, and then get the
+   * attribute on the main panel whose name is that title.  If the attribute
+   * exists, then its value is the actual title, and we update the action with
+   * this title.  Otherwise the action's title has already been set up in this
+   * manner.
    *
-   * The convention is to set for example the "title" property in an action's JS
-   * definition to the name of the attribute on the panel node that holds the
-   * actual title string.  Then call this function, passing the action's related
-   * DOM node and the name of the attribute that you are setting on the DOM
-   * node -- "label" or "title" in this example (either will do).
+   * @param  action (PageActions.Action, required)
+   *         The action whose title you're setting.
+   */
+  takeActionTitleFromPanel(action) {
+    let titleOrAttrNameOnPanel = action.getTitle();
+    let attrValueOnPanel = this.panelNode.getAttribute(titleOrAttrNameOnPanel);
+    if (attrValueOnPanel) {
+      this.panelNode.removeAttribute(titleOrAttrNameOnPanel);
+      action.setTitle(attrValueOnPanel);
+    }
+  },
+
+  /**
+   * This is similar to takeActionTitleFromPanel, except it sets an attribute on
+   * a DOM node instead of setting the title on an action.  The point is to map
+   * attributes on the node to strings on the main panel.  Use this for DOM
+   * nodes that don't correspond to actions, like buttons in subviews.
    *
    * @param  node (DOM node, required)
-   *         The node of an action you're setting up.
+   *         The node you're setting up.
    * @param  attrName (string, required)
    *         The name of the attribute *on the node you're setting up*.
    */
   takeNodeAttributeFromPanel(node, attrName) {
     let panelAttrName = node.getAttribute(attrName);
     if (!panelAttrName && attrName == "title") {
       attrName = "label";
       panelAttrName = node.getAttribute(attrName);
@@ -729,16 +830,17 @@ var BrowserPageActions = {
    */
   onLocationChange() {
     for (let action of PageActions.actions) {
       action.onLocationChange(window);
     }
   },
 };
 
+
 var BrowserPageActionFeedback = {
   /**
    * The feedback page action panel DOM node (DOM node)
    */
   get panelNode() {
     delete this.panelNode;
     return this.panelNode = document.getElementById("pageActionFeedback");
   },
@@ -773,16 +875,17 @@ var BrowserPageActionFeedback = {
       }, Services.prefs.getIntPref("browser.pageActions.feedbackTimeoutMS", 1120));
     }, {once: true});
     this.panelNode.addEventListener("popuphidden", () => {
       this.feedbackAnimationBox.removeAttribute("animate");
     }, {once: true});
   },
 };
 
+
 // built-in actions below //////////////////////////////////////////////////////
 
 // bookmark
 BrowserPageActions.bookmark = {
   onShowingInPanel(buttonNode) {
     // Update the button label via the bookmark observer.
     BookmarkingUI.updateBookmarkPageMenuItem();
   },
@@ -791,45 +894,48 @@ BrowserPageActions.bookmark = {
     BrowserPageActions.panelNode.hidePopup();
     BookmarkingUI.onStarCommand(event);
   },
 };
 
 // copy URL
 BrowserPageActions.copyURL = {
   onPlacedInPanel(buttonNode) {
-    BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
+    let action = PageActions.actionForID("copyURL");
+    BrowserPageActions.takeActionTitleFromPanel(action);
   },
 
   onCommand(event, buttonNode) {
     BrowserPageActions.panelNode.hidePopup();
     Cc["@mozilla.org/widget/clipboardhelper;1"]
       .getService(Ci.nsIClipboardHelper)
       .copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
     let action = PageActions.actionForID("copyURL");
     BrowserPageActionFeedback.show(action, event);
   },
 };
 
 // email link
 BrowserPageActions.emailLink = {
   onPlacedInPanel(buttonNode) {
-    BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
+    let action = PageActions.actionForID("emailLink");
+    BrowserPageActions.takeActionTitleFromPanel(action);
   },
 
   onCommand(event, buttonNode) {
     BrowserPageActions.panelNode.hidePopup();
     MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
   },
 };
 
 // send to device
 BrowserPageActions.sendToDevice = {
   onPlacedInPanel(buttonNode) {
-    BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
+    let action = PageActions.actionForID("sendToDevice");
+    BrowserPageActions.takeActionTitleFromPanel(action);
   },
 
   onSubviewPlaced(panelViewNode) {
     let bodyNode = panelViewNode.firstChild;
     for (let node of bodyNode.childNodes) {
       BrowserPageActions.takeNodeAttributeFromPanel(node, "title");
       BrowserPageActions.takeNodeAttributeFromPanel(node, "shortcut");
     }
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -382,20 +382,16 @@ toolbarpaletteitem > toolbaritem[sdkstyl
     list-style-image: var(--webextension-menupanel-image-light, inherit);
   }
 
   .webextension-browser-action[cui-areatype="menu-panel"]:-moz-lwtheme-darktext,
   toolbarpaletteitem[place="palette"] > .webextension-browser-action:-moz-lwtheme-darktext {
     list-style-image: var(--webextension-menupanel-image-dark, inherit);
   }
 
-  .webextension-page-action {
-    list-style-image: var(--webextension-urlbar-image, inherit);
-  }
-
   .webextension-menuitem {
     list-style-image: var(--webextension-menuitem-image, inherit);
   }
 }
 
 @media (min-resolution: 1.1dppx) {
   .webextension-browser-action {
     list-style-image: var(--webextension-toolbar-image-2x, inherit);
@@ -418,20 +414,16 @@ toolbarpaletteitem > toolbaritem[sdkstyl
     list-style-image: var(--webextension-menupanel-image-2x-light, inherit);
   }
 
   .webextension-browser-action[cui-areatype="menu-panel"]:-moz-lwtheme-darktext,
   toolbarpaletteitem[place="palette"] > .webextension-browser-action:-moz-lwtheme-darktext {
     list-style-image: var(--webextension-menupanel-image-2x-dark, inherit);
   }
 
-  .webextension-page-action {
-    list-style-image: var(--webextension-urlbar-image-2x, inherit);
-  }
-
   .webextension-menuitem {
     list-style-image: var(--webextension-menuitem-image-2x, inherit);
   }
 }
 
 toolbarbutton.webextension-menuitem > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
@@ -1430,16 +1422,37 @@ toolbarpaletteitem[place="palette"][hidd
 }
 
 /* Page action panel */
 #pageAction-panel-sendToDevice-subview-body:not([state="notready"]) > #pageAction-panel-sendToDevice-notReady,
 #pageAction-urlbar-sendToDevice-subview-body:not([state="notready"]) > #pageAction-urlbar-sendToDevice-notReady {
   display: none;
 }
 
+/* Page action buttons */
+.pageAction-panel-button > .toolbarbutton-icon {
+  list-style-image: var(--pageAction-image-16px, inherit);
+}
+.urlbar-page-action {
+  list-style-image: var(--pageAction-image-16px, inherit);
+}
+@media (min-resolution: 1.1dppx) {
+  .pageAction-panel-button > .toolbarbutton-icon {
+    list-style-image: var(--pageAction-image-32px, inherit);
+  }
+  .urlbar-page-action {
+    list-style-image: var(--pageAction-image-32px, inherit);
+  }
+}
+
+.urlbar-page-action[disabled] {
+  pointer-events: none;
+  -moz-user-focus: ignore;
+}
+
 /* WebExtension Sidebars */
 #sidebar-box[sidebarcommand$="-sidebar-action"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
   list-style-image: var(--webextension-menuitem-image, inherit);
   -moz-context-properties: fill;
   fill: currentColor;
   width: 16px;
   height: 16px;
 }
--- a/browser/base/content/test/general/browser_bug423833.js
+++ b/browser/base/content/test/general/browser_bug423833.js
@@ -79,24 +79,26 @@ function test2Setup() {
   ok(test2tab, "openFrameInTab() opened a tab");
 
   gBrowser.selectedTab = test2tab;
 
   intervalID = setInterval(testOpenFrameInTab, 3000);
 }
 
 function testOpenFrameInTab() {
+  /* eslint-disable mozilla/no-cpows-in-tests */
   if (gBrowser.contentDocument.location.href == "about:blank")
     // Wait another cycle
     return;
 
   clearInterval(intervalID);
 
   // We should now have the error page in a new, active tab.
   is(gBrowser.contentDocument.location.href, invalidPage, "New tab should have page url, not about:neterror");
+  /* eslint-enable mozilla/no-cpows-in-tests */
 
   // Clear up the new tab, and punt to test 3
   gBrowser.removeCurrentTab();
 
   test3Setup();
 }
 
 function test3Setup() {
--- a/browser/base/content/test/general/browser_bug561636.js
+++ b/browser/base/content/test/general/browser_bug561636.js
@@ -280,16 +280,17 @@ add_task(async function() {
         gObserver.notifyInvalidSubmit = function() {};
         resolve();
       });
     };
 
     Services.obs.addObserver(gObserver, "invalidformsubmit");
 
     executeSoon(function() {
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       browser.contentDocument.getElementById("s").click();
     });
   });
 
   await notifierPromise;
 
   gBrowser.removeTab(gBrowser.getTabForBrowser(browser));
 });
@@ -325,16 +326,17 @@ add_task(async function() {
 
   let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown");
   await clickChildElement(browser);
   await popupShownPromise;
 
   checkPopupShow();
   await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent);
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let inputPromise = promiseWaitForEvent(gBrowser.contentDocument.getElementById("i"), "input");
   EventUtils.synthesizeKey("f", {});
   await inputPromise;
 
   // Now, the element suffers from another error, the message should have
   // been updated.
   await new Promise((resolve, reject) => {
     // XXXndeakin This isn't really going to work when the content is another process
--- a/browser/base/content/test/general/browser_bug575561.js
+++ b/browser/base/content/test/general/browser_bug575561.js
@@ -69,16 +69,17 @@ async function testLink(aLinkIndexOrFunc
     });
   } else {
     promise = BrowserTestUtils.browserLoaded(browser, testSubFrame);
   }
 
   let href;
   if (typeof aLinkIndexOrFunction === "function") {
     ok(!browser.isRemoteBrowser, "don't pass a function for a remote browser");
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let link = aLinkIndexOrFunction(browser.contentDocument);
     info("Clicking " + link.textContent);
     link.click();
     href = link.href;
   } else {
     href = await ContentTask.spawn(browser, [ testSubFrame, aLinkIndexOrFunction ], function([ subFrame, index ]) {
       let doc = subFrame ? content.document.querySelector("iframe").contentDocument : content.document;
       let link = doc.querySelectorAll("a")[index];
--- a/browser/base/content/test/general/browser_bug678392.js
+++ b/browser/base/content/test/general/browser_bug678392.js
@@ -31,16 +31,17 @@ function test() {
      "was successfully initialized when supported.");
 
   cleanupArray();
   load(gBrowser.selectedTab, HTTPROOT + "browser_bug678392-2.html", test0);
 }
 
 function load(aTab, aUrl, aCallback) {
   aTab.linkedBrowser.addEventListener("load", function(aEvent) {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     waitForFocus(aCallback, content);
   }, {capture: true, once: true});
   aTab.linkedBrowser.loadURI(aUrl);
 }
 
 function cleanupArray() {
   let arr = gHistorySwipeAnimation._trackedSnapshots;
   while (arr.length > 0) {
--- a/browser/base/content/test/general/browser_bug767836_perwindowpb.js
+++ b/browser/base/content/test/general/browser_bug767836_perwindowpb.js
@@ -70,16 +70,17 @@ function test() {
   });
 }
 
 function openNewTab(aWindow, aCallback) {
   // Open a new tab
   aWindow.BrowserOpenTab();
 
   let browser = aWindow.gBrowser.selectedBrowser;
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   if (browser.contentDocument.readyState === "complete") {
     executeSoon(aCallback);
     return;
   }
 
   browser.addEventListener("load", function() {
     executeSoon(aCallback);
   }, {capture: true, once: true});
--- a/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
+++ b/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
@@ -11,16 +11,17 @@ const kAboutPagesRegistered = Promise.al
     registerCleanupFunction, "test-about-principal-parent", kParentPage,
     Ci.nsIAboutModule.ALLOW_SCRIPT)
 ]);
 
 add_task(async function test_principal_click() {
   await kAboutPagesRegistered;
   await BrowserTestUtils.withNewTab("about:test-about-principal-parent", async function(browser) {
     let loadPromise = BrowserTestUtils.browserLoaded(browser, false, "about:test-about-principal-child");
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let myLink = browser.contentDocument.getElementById("aboutchildprincipal");
     myLink.click();
     await loadPromise;
 
     await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
       let channel = content.document.docShell.currentDocumentChannel;
       is(channel.originalURI.asciiSpec,
          "about:test-about-principal-child",
--- a/browser/base/content/test/general/browser_gZipOfflineChild.js
+++ b/browser/base/content/test/general/browser_gZipOfflineChild.js
@@ -67,13 +67,14 @@ function test() {
 
   Services.prefs.setBoolPref("offline-apps.allow_by_default", true);
 
   // Open a new tab.
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, URL);
   registerCleanupFunction(() => gBrowser.removeCurrentTab());
 
   BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let window = gBrowser.selectedBrowser.contentWindow;
 
     window.addEventListener("message", handleMessageEvents);
   });
 }
--- a/browser/base/content/test/general/browser_keywordSearch_postData.js
+++ b/browser/base/content/test/general/browser_keywordSearch_postData.js
@@ -62,16 +62,17 @@ function nextTest() {
     finish();
   }
 }
 
 function doTest() {
   info("Running test: " + gCurrTest.name);
 
   waitForLoad(function() {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let loadedText = gBrowser.contentDocument.body.textContent;
     ok(loadedText, "search page loaded");
     let needle = "searchterms=" + gCurrTest.expectText;
     is(loadedText, needle, "The query POST data should be returned in the response");
     nextTest();
   });
 
   // Simulate a user entering search terms
--- a/browser/base/content/test/general/browser_tabfocus.js
+++ b/browser/base/content/test/general/browser_tabfocus.js
@@ -86,16 +86,17 @@ function focusInChild() {
 
   addEventListener("focus", eventListener, true);
   addEventListener("blur", eventListener, true);
 
   addMessageListener("Browser:ChangeFocus", function changeFocus(message) {
     content.document.getElementById(message.data.id)[message.data.type]();
   });
 
+  /* eslint-disable mozilla/no-cpows-in-tests */
   addMessageListener("Browser:GetFocusedElement", function getFocusedElement(message) {
     var focusedWindow = {};
     var node = contentFM.getFocusedElementForWindow(content, false, focusedWindow);
     var details = "Focus is " + (node ? node.id : "<none>");
 
     /* Check focus manager properties. Add an error onto the string if they are
        not what is expected which will cause matching to fail in the parent process. */
     let doc = content.document;
@@ -123,16 +124,17 @@ function focusElementInChild(elementid, 
   let browser = (elementid.indexOf("1") >= 0) ? browser1 : browser2;
   if (gMultiProcessBrowser) {
     browser.messageManager.sendAsyncMessage("Browser:ChangeFocus",
                                             { id: elementid, type });
   } else {
     browser.contentDocument.getElementById(elementid)[type]();
   }
 }
+/* eslint-enable mozilla/no-cpows-in-tests */
 
 add_task(async function() {
   tab1 = BrowserTestUtils.addTab(gBrowser);
   browser1 = gBrowser.getBrowserForTab(tab1);
 
   tab2 = BrowserTestUtils.addTab(gBrowser);
   browser2 = gBrowser.getBrowserForTab(tab2);
 
--- a/browser/base/content/test/newtab/browser_newtab_focus.js
+++ b/browser/base/content/test/newtab/browser_newtab_focus.js
@@ -62,17 +62,17 @@ function countFocus(aExpectedCount) {
 function promiseNoMuteNotificationOnFirstSession() {
   return SpecialPowers.pushPrefEnv({set: [["browser.onboarding.notification.mute-duration-on-first-session-ms", 0]]});
 }
 
 /**
  * Wait for the onboarding tour notification opens
  */
 function promiseTourNotificationOpened(browser) {
-  function isOpened() {
+  return ContentTask.spawn(browser, {}, function() {
     let doc = content && content.document;
     let notification = doc.querySelector("#onboarding-notification-bar");
     if (notification && notification.classList.contains("onboarding-opened")) {
       ok(true, "Should open tour notification");
       return Promise.resolve();
     }
     return new Promise(resolve => {
       let observer = new content.MutationObserver(mutations => {
@@ -83,11 +83,10 @@ function promiseTourNotificationOpened(b
             observer.disconnect();
             ok(true, "Should open tour notification");
             resolve();
           }
         });
       });
       observer.observe(doc.body, { childList: true });
     });
-  }
-  return ContentTask.spawn(browser, {}, isOpened);
+  });
 }
--- a/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js
+++ b/browser/base/content/test/pageinfo/browser_pageinfo_image_info.js
@@ -9,16 +9,17 @@ function getImageInfo(imageElement) {
 }
 
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
 
   gBrowser.selectedBrowser.addEventListener("load", function() {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     var doc = gBrowser.contentDocument;
     var testImg = doc.getElementById("test-image");
     var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
                                    "mediaTab", getImageInfo(testImg));
 
     pageInfo.addEventListener("load", function() {
       pageInfo.onFinished.push(function() {
         var pageInfoImg = pageInfo.document.getElementById("thepreviewimage");
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_keyboard.js
@@ -187,16 +187,17 @@ var tests = [
         await opened;
 
         // Check that the focused element in the chrome window
         // is either the browser in case we're running on e10s
         // or the input field in case of non-e10s.
         if (gMultiProcessBrowser) {
           is(Services.focus.focusedElement, browser);
         } else {
+          // eslint-disable-next-line mozilla/no-cpows-in-tests
           is(Services.focus.focusedElement, browser.contentDocument.getElementById("test-input"));
         }
 
         // Check that the input field is still focused inside the browser.
         await ContentTask.spawn(browser, {}, function() {
           is(content.document.activeElement, content.document.getElementById("test-input"));
         });
 
--- a/browser/base/content/test/sidebar/browser_bug409481.js
+++ b/browser/base/content/test/sidebar/browser_bug409481.js
@@ -32,19 +32,21 @@ function delayedRunTest() {
   setTimeout(runTest, 100);
 }
 
 function runTest(event) {
   var sidebar = document.getElementById("sidebar");
   sidebar.contentDocument.removeEventListener("load", delayedRunTest, true);
 
   var browser = sidebar.contentDocument.getElementById("web-panels-browser");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   var div = browser && browser.contentDocument.getElementById("test_bug409481");
   ok(div && div.textContent == "Content!", "Sidebar content loaded");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   var link = browser && browser.contentDocument.getElementById("link");
   sidebar.contentDocument.addEventListener("popupshown", contextMenuOpened);
 
   EventUtils.synthesizeMouseAtCenter(link, { type: "contextmenu", button: 2 }, browser.contentWindow);
 }
 
 function contextMenuOpened() {
   var sidebar = document.getElementById("sidebar");
@@ -55,16 +57,17 @@ function contextMenuOpened() {
   copyLinkCommand.doCommand();
 }
 
 function copyLinkCommandExecuted(event) {
   event.target.removeEventListener("command", copyLinkCommandExecuted);
 
   var sidebar = document.getElementById("sidebar");
   var browser = sidebar.contentDocument.getElementById("web-panels-browser");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   var textbox = browser && browser.contentDocument.getElementById("textbox");
   textbox.focus();
   document.commandDispatcher.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
   is(textbox.value, "http://www.example.com/ctest", "copy link command");
 
   sidebar.contentDocument.addEventListener("popuphidden", contextMenuClosed);
   event.target.parentNode.hidePopup();
 }
--- a/browser/base/content/test/tabcrashed/browser_autoSubmitRequest.js
+++ b/browser/base/content/test/tabcrashed/browser_autoSubmitRequest.js
@@ -27,16 +27,17 @@ add_task(async function test_show_form()
   }, async function(browser) {
     // Make sure we've flushed the browser messages so that
     // we can restore it.
     await TabStateFlusher.flush(browser);
 
     // Now crash the browser.
     await BrowserTestUtils.crashBrowser(browser);
 
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
 
     // Ensure the request is visible. We can safely reach into
     // the content since about:tabcrashed is an in-process URL.
     let requestAutoSubmit = doc.getElementById("requestAutoSubmit");
     Assert.ok(!requestAutoSubmit.hidden,
               "Request for autosubmission is visible.");
 
@@ -71,16 +72,17 @@ add_task(async function test_show_form()
   return BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE,
   }, async function(browser) {
     await TabStateFlusher.flush(browser);
     // Now crash the browser.
     await BrowserTestUtils.crashBrowser(browser);
 
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
 
     // Ensure the request is NOT visible. We can safely reach into
     // the content since about:tabcrashed is an in-process URL.
     let requestAutoSubmit = doc.getElementById("requestAutoSubmit");
     Assert.ok(requestAutoSubmit.hidden,
               "Request for autosubmission is not visible.");
 
--- a/browser/base/content/test/tabcrashed/browser_clearEmail.js
+++ b/browser/base/content/test/tabcrashed/browser_clearEmail.js
@@ -32,35 +32,36 @@ add_task(async function test_clear_email
     // crash
     prefs.setCharPref("email", EMAIL);
     prefs.setBoolPref("emailMe", true);
 
     let tab = gBrowser.getTabForBrowser(browser);
     await BrowserTestUtils.crashBrowser(browser,
                                         /* shouldShowTabCrashPage */ true,
                                         /* shouldClearMinidumps */ false);
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
 
     // Since about:tabcrashed will run in the parent process, we can safely
     // manipulate its DOM nodes directly
     let emailMe = doc.getElementById("emailMe");
     emailMe.checked = false;
 
     let crashReport = promiseCrashReport({
       Email: "",
     });
 
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let restoreTab = browser.contentDocument.getElementById("restoreTab");
     restoreTab.click();
     await BrowserTestUtils.waitForEvent(tab, "SSTabRestored");
     await crashReport;
 
     is(prefs.getCharPref("email"), "", "No email address should be stored");
 
     // Submitting the crash report may have set some prefs regarding how to
     // send tab crash reports. Let's reset them for the next test.
     prefs.setBoolPref("sendReport", originalSendReport);
     prefs.setBoolPref("emailMe", originalEmailMe);
     prefs.setBoolPref("includeURL", originalIncludeURL);
     prefs.setCharPref("email", originalEmail);
   });
 });
-
--- a/browser/base/content/test/tabcrashed/browser_showForm.js
+++ b/browser/base/content/test/tabcrashed/browser_showForm.js
@@ -21,16 +21,17 @@ add_task(async function test_show_form()
     let pref = TabCrashHandler.prefs.root + "sendReport";
     await SpecialPowers.pushPrefEnv({
       set: [[pref, true]]
     });
 
     // Now crash the browser.
     await BrowserTestUtils.crashBrowser(browser);
 
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
 
     // Ensure the checkbox is checked. We can safely reach into
     // the content since about:tabcrashed is an in-process URL.
     let checkbox = doc.getElementById("sendReport");
     ok(checkbox.checked, "Send report checkbox is checked.");
 
     // Ensure the options form is displayed.
--- a/browser/base/content/test/tabcrashed/browser_shown.js
+++ b/browser/base/content/test/tabcrashed/browser_shown.js
@@ -51,16 +51,17 @@ function crashTabTestHelper(fieldValues,
     let prefs = TabCrashHandler.prefs;
     let originalSendReport = prefs.getBoolPref("sendReport");
     let originalEmailMe = prefs.getBoolPref("emailMe");
     let originalIncludeURL = prefs.getBoolPref("includeURL");
     let originalEmail = prefs.getCharPref("email");
 
     let tab = gBrowser.getTabForBrowser(browser);
     await BrowserTestUtils.crashBrowser(browser);
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
 
     // Since about:tabcrashed will run in the parent process, we can safely
     // manipulate its DOM nodes directly
     let comments = doc.getElementById("comments");
     let email = doc.getElementById("email");
     let emailMe = doc.getElementById("emailMe");
     let includeURL = doc.getElementById("includeURL");
@@ -77,16 +78,17 @@ function crashTabTestHelper(fieldValues,
       emailMe.checked = fieldValues.emailMe;
     }
 
     if (fieldValues.hasOwnProperty("includeURL")) {
       includeURL.checked = fieldValues.includeURL;
     }
 
     let crashReport = promiseCrashReport(expectedExtra);
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let restoreTab = browser.contentDocument.getElementById("restoreTab");
     restoreTab.click();
     await BrowserTestUtils.waitForEvent(tab, "SSTabRestored");
     await crashReport;
 
     // Submitting the crash report may have set some prefs regarding how to
     // send tab crash reports. Let's reset them for the next test.
     prefs.setBoolPref("sendReport", originalSendReport);
@@ -173,9 +175,8 @@ add_task(async function test_send_all() 
     email: EMAIL,
     comments: COMMENTS,
   }, {
     "Comments": COMMENTS,
     "URL": PAGE,
     "Email": EMAIL,
   });
 });
-
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -543,17 +543,17 @@ add_task(async function sendToDevice_inU
     registerCleanupFunction(cleanUp);
 
     // Add Send to Device to the urlbar.
     let action = PageActions.actionForID("sendToDevice");
     action.shownInUrlbar = true;
 
     // Click it to open its panel.
     let urlbarButton = document.getElementById(
-      BrowserPageActions._urlbarButtonNodeIDForActionID(action.id)
+      BrowserPageActions.urlbarButtonNodeIDForActionID(action.id)
     );
     Assert.ok(!urlbarButton.disabled);
     let panelPromise =
       promisePanelShown(BrowserPageActions._activatedActionPanelID);
     EventUtils.synthesizeMouseAtCenter(urlbarButton, {});
     await panelPromise;
     Assert.equal(urlbarButton.getAttribute("open"), "true",
       "Button has open attribute");
--- a/browser/base/content/test/webextensions/browser_extension_sideloading.js
+++ b/browser/base/content/test/webextensions/browser_extension_sideloading.js
@@ -128,16 +128,17 @@ add_task(async function() {
   addons.children[0].click();
 
   // When we get the permissions prompt, we should be at the extensions
   // list in about:addons
   let panel = await popupPromise;
   is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons");
 
   const VIEW = "addons://list/extension";
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.selectedBrowser.contentWindow;
   ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
   is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
 
   // Check the contents of the notification, then choose "Cancel"
   checkNotification(panel, /\/foo-icon\.png$/, [
     ["webextPerms.hostDescription.allUrls"],
     ["webextPerms.description.history"],
@@ -163,16 +164,17 @@ add_task(async function() {
   // Click the second sideloaded extension and wait for the notification
   popupPromise = promisePopupNotificationShown("addon-webext-permissions");
   addons.children[0].click();
   panel = await popupPromise;
 
   // Again we should be at the extentions list in about:addons
   is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   win = gBrowser.selectedBrowser.contentWindow;
   ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
   is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
 
   // Check the notification contents.
   checkNotification(panel, DEFAULT_ICON_URL, []);
 
   // This time accept the install.
--- a/browser/components/contextualidentity/test/browser/browser_usercontext.js
+++ b/browser/components/contextualidentity/test/browser/browser_usercontext.js
@@ -64,16 +64,17 @@ add_task(async function test() {
 
     let tab = openTabInUserContext(BASE_URI, userContextId);
 
     // wait for load
     let browser = gBrowser.getBrowserForTab(tab);
     await BrowserTestUtils.browserLoaded(browser);
 
     // get the title
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let title = browser.contentDocument.title.trim().split("|");
 
     // check each item in the title and validate it meets expectatations
     for (let part of title) {
       let [storageMethodName, value] = part.split("=");
       is(value, expectedContext,
             "the title reflects the expected contextual identity of " +
             expectedContext + " for method " + storageMethodName + ": " + value);
--- a/browser/components/customizableui/test/browser_947914_button_addons.js
+++ b/browser/components/customizableui/test/browser_947914_button_addons.js
@@ -19,16 +19,17 @@ add_task(async function() {
   let addonsButton = document.getElementById("add-ons-button");
   ok(addonsButton, "Add-ons button exists in Panel Menu");
   addonsButton.click();
 
   newTab = gBrowser.selectedTab;
   await waitForCondition(() => gBrowser.currentURI &&
                                gBrowser.currentURI.spec == "about:addons");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let addonsPage = gBrowser.selectedBrowser.contentWindow.document.
                             getElementById("addons-page");
   ok(addonsPage, "Add-ons page was opened");
 });
 
 add_task(async function asyncCleanup() {
   CustomizableUI.reset();
   BrowserTestUtils.addTab(gBrowser, initialLocation);
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -369,42 +369,38 @@ class BasePopup {
 /**
  * A map of active popups for a given browser window.
  *
  * WeakMap[window -> WeakMap[Extension -> BasePopup]]
  */
 BasePopup.instances = new DefaultWeakMap(() => new WeakMap());
 
 class PanelPopup extends BasePopup {
-  constructor(extension, imageNode, popupURL, browserStyle) {
-    let document = imageNode.ownerDocument;
-
+  constructor(extension, document, popupURL, browserStyle) {
     let panel = document.createElement("panel");
     panel.setAttribute("id", makeWidgetId(extension.id) + "-panel");
     panel.setAttribute("class", "browser-extension-panel");
     panel.setAttribute("tabspecific", "true");
     panel.setAttribute("type", "arrow");
     panel.setAttribute("role", "group");
     if (extension.remote) {
       panel.setAttribute("remote", "true");
     }
 
     document.getElementById("mainPopupSet").appendChild(panel);
 
-    super(extension, panel, popupURL, browserStyle);
-
-    this.contentReady.then(() => {
-      panel.openPopup(imageNode, "bottomcenter topright", 0, 0, false, false);
-
+    panel.addEventListener("popupshowing", () => {
       let event = new this.window.CustomEvent("WebExtPopupLoaded", {
         bubbles: true,
         detail: {extension},
       });
       this.browser.dispatchEvent(event);
-    });
+    }, {once: true});
+
+    super(extension, panel, popupURL, browserStyle);
   }
 
   get DESTROY_EVENT() {
     return "popuphidden";
   }
 
   destroy() {
     super.destroy();
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -1,26 +1,24 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browserAction.js */
 /* import-globals-from ext-browser.js */
 
+XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
+                                  "resource:///modules/PageActions.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PanelPopup",
                                   "resource:///modules/ExtensionPopups.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
 
 
-var {
-  DefaultWeakMap,
-} = ExtensionUtils;
-
 Cu.import("resource://gre/modules/ExtensionParent.jsm");
 
 var {
   IconDetails,
   StartupCache,
 } = ExtensionParent;
 
 const popupOpenTimingHistogram = "WEBEXT_PAGEACTION_POPUP_OPEN_MS";
@@ -32,19 +30,18 @@ this.pageAction = class extends Extensio
   static for(extension) {
     return pageActionMap.get(extension);
   }
 
   async onManifestEntry(entryName) {
     let {extension} = this;
     let options = extension.manifest.page_action;
 
-    this.iconData = new DefaultWeakMap(icons => this.getIconData(icons));
-
-    this.id = makeWidgetId(extension.id) + "-page-action";
+    let widgetId = makeWidgetId(extension.id);
+    this.id = widgetId + "-page-action";
 
     this.tabManager = extension.tabManager;
 
     this.defaults = {
       show: false,
       title: options.default_title || extension.name,
       popup: options.default_popup || "",
     };
@@ -55,42 +52,44 @@ this.pageAction = class extends Extensio
                                  "or not in your page_action options.");
     }
 
     this.tabContext = new TabContext(tab => Object.create(this.defaults),
                                      extension);
 
     this.tabContext.on("location-change", this.handleLocationChange.bind(this)); // eslint-disable-line mozilla/balanced-listeners
 
-    // WeakMap[ChromeWindow -> <xul:image>]
-    this.buttons = new WeakMap();
-
     pageActionMap.set(extension, this);
 
     this.defaults.icon = await StartupCache.get(
       extension, ["pageAction", "default_icon"],
       () => IconDetails.normalize({path: options.default_icon}, extension));
 
-    this.iconData.set(
-      this.defaults.icon,
-      await StartupCache.get(
-        extension, ["pageAction", "default_icon_data"],
-        () => this.getIconData(this.defaults.icon)));
+    if (!this.browserPageAction) {
+      this.browserPageAction = PageActions.addAction(new PageActions.Action({
+        id: widgetId,
+        title: this.defaults.title,
+        iconURL: this.defaults.icon,
+        shownInUrlbar: true,
+        disabled: true,
+        onCommand: (event, buttonNode) => {
+          this.handleClick(event.target.ownerGlobal);
+        },
+      }));
+    }
   }
 
   onShutdown(reason) {
     pageActionMap.delete(this.extension);
 
     this.tabContext.shutdown();
 
-    for (let window of windowTracker.browserWindows()) {
-      if (this.buttons.has(window)) {
-        this.buttons.get(window).remove();
-        window.document.removeEventListener("popupshowing", this);
-      }
+    if (this.browserPageAction) {
+      this.browserPageAction.remove();
+      this.browserPageAction = null;
     }
   }
 
   // Returns the value of the property |prop| for the given tab, where
   // |prop| is one of "show", "title", "icon", "popup".
   getProperty(tab, prop) {
     return this.tabContext.get(tab)[prop];
   }
@@ -112,91 +111,34 @@ this.pageAction = class extends Extensio
     }
   }
 
   // Updates the page action button in the given window to reflect the
   // properties of the currently selected tab:
   //
   // Updates "tooltiptext" and "aria-label" to match "title" property.
   // Updates "image" to match the "icon" property.
-  // Shows or hides the icon, based on the "show" property.
+  // Enables or disables the icon, based on the "show" property.
   updateButton(window) {
     let tabData = this.tabContext.get(window.gBrowser.selectedTab);
-
-    if (!(tabData.show || this.buttons.has(window))) {
-      // Don't bother creating a button for a window until it actually
-      // needs to be shown.
-      return;
-    }
-
-    window.requestAnimationFrame(() => {
-      let button = this.getButton(window);
-
-      if (tabData.show) {
-        // Update the title and icon only if the button is visible.
-
-        let title = tabData.title || this.extension.name;
-        button.setAttribute("tooltiptext", title);
-        button.setAttribute("aria-label", title);
-        button.classList.add("webextension-page-action");
-
-        let {style} = this.iconData.get(tabData.icon);
-
-        button.setAttribute("style", style);
-      }
-
-      button.hidden = !tabData.show;
-    });
-  }
-
-  getIconData(icons) {
-    let getIcon = size => {
-      let {icon} = IconDetails.getPreferredIcon(icons, this.extension, size);
-      // TODO: implement theme based icon for pageAction (Bug 1398156)
-      return IconDetails.escapeUrl(icon);
-    };
+    let title = tabData.title || this.extension.name;
+    this.browserPageAction.setTitle(title, window);
+    this.browserPageAction.setTooltip(title, window);
+    this.browserPageAction.setDisabled(!tabData.show, window);
 
-    let style = `
-      --webextension-urlbar-image: url("${getIcon(16)}");
-      --webextension-urlbar-image-2x: url("${getIcon(32)}");
-    `;
-
-    return {style};
-  }
-
-  // Create an |image| node and add it to the |page-action-buttons|
-  // container in the given window.
-  addButton(window) {
-    let document = window.document;
-
-    let button = document.createElement("image");
-    button.id = this.id;
-    button.setAttribute("class", "urlbar-icon");
-
-    button.addEventListener("click", this); // eslint-disable-line mozilla/balanced-listeners
-
-    if (this.extension.hasPermission("menus") ||
-        this.extension.hasPermission("contextMenus")) {
-      document.addEventListener("popupshowing", this);
+    let iconURL;
+    if (typeof(tabData.icon) == "string") {
+      iconURL = IconDetails.escapeUrl(tabData.icon);
+    } else {
+      iconURL = Object.entries(tabData.icon).reduce((memo, [size, url]) => {
+        memo[size] = IconDetails.escapeUrl(url);
+        return memo;
+      }, {});
     }
-
-    document.getElementById("page-action-buttons").appendChild(button);
-
-    return button;
-  }
-
-  // Returns the page action button for the given window, creating it if
-  // it doesn't already exist.
-  getButton(window) {
-    if (!this.buttons.has(window)) {
-      let button = this.addButton(window);
-      this.buttons.set(window, button);
-    }
-
-    return this.buttons.get(window);
+    this.browserPageAction.setIconURL(iconURL, window);
   }
 
   /**
    * Triggers this page action for the given window, with the same effects as
    * if it were clicked by a user.
    *
    * This has no effect if the page action is hidden for the selected tab.
    *
@@ -204,41 +146,16 @@ this.pageAction = class extends Extensio
    */
   triggerAction(window) {
     let pageAction = pageActionMap.get(this.extension);
     if (pageAction.getProperty(window.gBrowser.selectedTab, "show")) {
       pageAction.handleClick(window);
     }
   }
 
-  handleEvent(event) {
-    const window = event.target.ownerGlobal;
-
-    switch (event.type) {
-      case "click":
-        if (event.button === 0) {
-          this.handleClick(window);
-        }
-        break;
-
-      case "popupshowing":
-        const menu = event.target;
-        const trigger = menu.triggerNode;
-
-        if (menu.id === "toolbar-context-menu" && trigger && trigger.id === this.id) {
-          global.actionContextMenu({
-            extension: this.extension,
-            onPageAction: true,
-            menu: menu,
-          });
-        }
-        break;
-    }
-  }
-
   // Handles a click event on the page action button for the given
   // window.
   // If the page action has a |popup| property, a panel is opened to
   // that URL. Otherwise, a "click" event is emitted, and dispatched to
   // the any click listeners in the add-on.
   async handleClick(window) {
     TelemetryStopwatch.start(popupOpenTimingHistogram, this);
     let tab = window.gBrowser.selectedTab;
@@ -246,19 +163,21 @@ this.pageAction = class extends Extensio
 
     this.tabManager.addActiveTabPermission(tab);
 
     // If the widget has a popup URL defined, we open a popup, but do not
     // dispatch a click event to the extension.
     // If it has no popup URL defined, we dispatch a click event, but do not
     // open a popup.
     if (popupURL) {
-      let popup = new PanelPopup(this.extension, this.getButton(window),
-                                 popupURL, this.browserStyle);
+      let popup = new PanelPopup(this.extension, window.document, popupURL,
+                                 this.browserStyle);
       await popup.contentReady;
+      window.BrowserPageActions.togglePanelForAction(this.browserPageAction,
+                                                     popup.panel);
       TelemetryStopwatch.finish(popupOpenTimingHistogram, this);
     } else {
       TelemetryStopwatch.cancel(popupOpenTimingHistogram, this);
       this.emit("click", tab);
     }
   }
 
   handleLocationChange(eventType, tab, fromBrowse) {
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon.js
@@ -255,17 +255,17 @@ add_task(async function testDetailsObjec
       "data/a-x2.png": imageBuffer,
     },
   });
 
   const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
 
   await extension.startup();
 
-  let pageActionId = `${makeWidgetId(extension.id)}-page-action`;
+  let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
   let browserActionWidget = getBrowserActionWidget(extension);
 
   let tests = await extension.awaitMessage("ready");
   for (let test of tests) {
     extension.sendMessage("setIcon", test);
     await extension.awaitMessage("iconSet");
 
     await promiseAnimationFrame();
@@ -355,17 +355,17 @@ add_task(async function testPageActionIc
   });
 
   await extension.startup();
 
   await extension.awaitMessage("ready");
 
   await promiseAnimationFrame();
 
-  let pageActionId = `${makeWidgetId(extension.id)}-page-action`;
+  let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
   let pageActionImage = document.getElementById(pageActionId);
 
   const iconURL = new URL(getListStyleImage(pageActionImage));
 
   is(iconURL.pathname, "/common_cached_icon.png", "Got the expected pageAction icon url");
 
   await extension.unload();
 });
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_pageAction_icon_permissions.js
@@ -97,17 +97,17 @@ add_task(async function testDefaultDetai
         "baz/quux.png": imageBuffer,
         "baz/quux@2x.png": imageBuffer,
       },
     });
 
     await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
 
     let browserActionId = makeWidgetId(extension.id) + "-browser-action";
-    let pageActionId = makeWidgetId(extension.id) + "-page-action";
+    let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
 
     await promiseAnimationFrame();
 
     let browserActionButton = document.getElementById(browserActionId);
     let image = getListStyleImage(browserActionButton);
 
     ok(expectedURL.test(image), `browser action image ${image} matches ${expectedURL}`);
 
--- a/browser/components/extensions/test/browser/browser_ext_menus.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus.js
@@ -63,17 +63,20 @@ add_task(async function test_actionConte
   }
 
   const extension = ExtensionTestUtils.loadExtension({manifest, background});
   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
 
   await extension.startup();
   const tabId = await extension.awaitMessage("ready");
 
-  for (const kind of ["page", "browser"]) {
+  // TODO bug 1412170: Allow WebExtensions to hook into the browser page action
+  // context menu.
+//   for (const kind of ["page", "browser"]) {
+  for (const kind of ["browser"]) {
     const menu = await openActionContextMenu(extension, kind);
     const [submenu, second, , , , last, separator] = menu.children;
 
     is(submenu.tagName, "menu", "Correct submenu type");
     is(submenu.label, "parent", "Correct submenu title");
 
     const popup = await openSubmenu(submenu);
     is(popup, submenu.firstChild, "Correct submenu opened");
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -388,17 +388,20 @@ function closeChromeContextMenu(menuId, 
   }
   return hidden;
 }
 
 async function openActionContextMenu(extension, kind, win = window) {
   // See comment from clickPageAction below.
   SetPageProxyState("valid");
   await promiseAnimationFrame(win);
-  const id = `#${makeWidgetId(extension.id)}-${kind}-action`;
+  const id =
+    kind == "page" ?
+    `#${BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id))}` :
+    `#${makeWidgetId(extension.id)}-${kind}-action`;
   return openChromeContextMenu("toolbar-context-menu", id, win);
 }
 
 function closeActionContextMenu(itemToSelect, win = window) {
   return closeChromeContextMenu("toolbar-context-menu", itemToSelect, win);
 }
 
 function openTabContextMenu(win = window) {
@@ -420,17 +423,18 @@ async function clickPageAction(extension
   // identity info and icons such as page action buttons.
   //
   // Unfortunately, that doesn't happen automatically in browser chrome
   // tests.
   SetPageProxyState("valid");
 
   await promiseAnimationFrame(win);
 
-  let pageActionId = makeWidgetId(extension.id) + "-page-action";
+  let pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
+
   let elem = win.document.getElementById(pageActionId);
 
   EventUtils.synthesizeMouseAtCenter(elem, {}, win);
   return new Promise(SimpleTest.executeSoon);
 }
 
 function closePageAction(extension, win = window) {
   let node = getPageActionPopup(extension, win);
--- a/browser/components/extensions/test/browser/head_pageAction.js
+++ b/browser/components/extensions/test/browser/head_pageAction.js
@@ -100,17 +100,17 @@ async function runTests(options) {
 
   let pageActionId;
   let currentWindow = window;
   let windows = [];
 
   function checkDetails(details) {
     let image = currentWindow.document.getElementById(pageActionId);
     if (details == null) {
-      ok(image == null || image.hidden, "image is hidden");
+      ok(image == null || image.getAttribute("disabled") == "true", "image is disabled");
     } else {
       ok(image, "image exists");
 
       is(getListStyleImage(image), details.icon, "icon URL is correct");
 
       let title = details.title || options.manifest.name;
       is(image.getAttribute("tooltiptext"), title, "image title is correct");
       is(image.getAttribute("aria-label"), title, "image aria-label is correct");
@@ -118,17 +118,17 @@ async function runTests(options) {
     }
   }
 
   let testNewWindows = 1;
 
   let awaitFinish = new Promise(resolve => {
     extension.onMessage("nextTest", async (expecting, testsRemaining) => {
       if (!pageActionId) {
-        pageActionId = `${makeWidgetId(extension.id)}-page-action`;
+        pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
       }
 
       await promiseAnimationFrame(currentWindow);
 
       checkDetails(expecting);
 
       if (testsRemaining) {
         extension.sendMessage("runNextTest");
--- a/browser/components/preferences/in-content/tests/browser_applications_selection.js
+++ b/browser/components/preferences/in-content/tests/browser_applications_selection.js
@@ -3,25 +3,27 @@ var feedItem;
 var container;
 
 SimpleTest.requestCompleteLog();
 
 add_task(async function setup() {
   await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
   info("Preferences page opened on the general pane.");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   await gBrowser.selectedBrowser.contentWindow.promiseLoadHandlersList;
   info("Apps list loaded.");
 
   registerCleanupFunction(() => {
     gBrowser.removeCurrentTab();
   });
 });
 
 add_task(async function getFeedItem() {
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   win = gBrowser.selectedBrowser.contentWindow;
 
   container = win.document.getElementById("handlersView");
   feedItem = container.querySelector("richlistitem[type='application/vnd.mozilla.maybe.feed']");
   Assert.ok(feedItem, "feedItem is present in handlersView.");
 });
 
 add_task(async function selectInternalOptionForFeed() {
@@ -77,16 +79,17 @@ add_task(async function reselectInternal
   Assert.ok(list.selectedItem,
             "Should have a selected item");
   Assert.equal(list.selectedItem.getAttribute("action"),
                Ci.nsIHandlerInfo.handleInternally,
                "Selected item should still be the same as the previously selected item.");
 });
 
 add_task(async function sortingCheck() {
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   win = gBrowser.selectedBrowser.contentWindow;
 
   const handlerView = win.document.getElementById("handlersView");
   const typeColumn = win.document.getElementById("typeColumn");
   Assert.ok(typeColumn, "typeColumn is present in handlersView.");
 
   // Test default sorting
   assertSortByType("ascending");
--- a/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
+++ b/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
@@ -1,17 +1,19 @@
 Services.prefs.setBoolPref("browser.preferences.instantApply", true);
 
 registerCleanupFunction(function() {
   Services.prefs.clearUserPref("browser.preferences.instantApply");
 });
 
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   await gBrowser.contentWindow.gMainPane._selectDefaultLanguageGroupPromise;
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   var langGroup = Services.prefs.getComplexValue("font.language.group", Ci.nsIPrefLocalizedString).data;
   is(doc.getElementById("font.language.group").value, langGroup,
      "Language group should be set correctly.");
 
   let defaultFontType = Services.prefs.getCharPref("font.default." + langGroup);
   let fontFamily = Services.prefs.getCharPref("font.name." + defaultFontType + "." + langGroup);
   let fontFamilyField = doc.getElementById("defaultFont");
--- a/browser/components/preferences/in-content/tests/browser_bug1018066_resetScrollPosition.js
+++ b/browser/components/preferences/in-content/tests/browser_bug1018066_resetScrollPosition.js
@@ -8,16 +8,18 @@ registerCleanupFunction(function() {
     gBrowser.removeTab(gBrowser.tabs[1]);
 });
 
 add_task(async function() {
   originalWindowHeight = window.outerHeight;
   window.resizeTo(window.outerWidth, 300);
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneSearch", {leaveOpen: true});
   is(prefs.selectedPane, "paneSearch", "Search pane was selected");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let mainContent = gBrowser.contentDocument.querySelector(".main-content");
   mainContent.scrollTop = 50;
   is(mainContent.scrollTop, 50, "main-content should be scrolled 50 pixels");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   gBrowser.contentWindow.gotoPref("paneGeneral");
   is(mainContent.scrollTop, 0,
      "Switching to a different category should reset the scroll position");
 });
--- a/browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js
+++ b/browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js
@@ -1,11 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 Services.prefs.setBoolPref("browser.preferences.instantApply", true);
 
 registerCleanupFunction(function() {
   Services.prefs.clearUserPref("browser.preferences.instantApply");
 });
 
 // Test opening to the differerent panes and subcategories in Preferences
 add_task(async function() {
--- a/browser/components/preferences/in-content/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.js
+++ b/browser/components/preferences/in-content/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.js
@@ -4,16 +4,17 @@ const {Utils} = Cu.import("resource://gr
 const triggeringPrincipal_base64 = Utils.SERIALIZED_SYSTEMPRINCIPAL;
 
 add_task(async function() {
   waitForExplicitFinish();
 
   const tabURL = getRootDirectory(gTestPath) + "browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul";
 
   await BrowserTestUtils.withNewTab({ gBrowser, url: tabURL }, async function(browser) {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
     let container = doc.getElementById("container");
 
     // Test button
     let button = doc.getElementById("button");
     button.focus();
     EventUtils.synthesizeKey(" ", {});
     await checkPageScrolling(container, "button");
@@ -36,16 +37,17 @@ add_task(async function() {
     // Test radio
     let radiogroup = doc.getElementById("radiogroup");
     radiogroup.focus();
     EventUtils.synthesizeKey(" ", {});
     await checkPageScrolling(container, "radio");
   });
 
   await BrowserTestUtils.withNewTab({ gBrowser, url: "about:preferences#search" }, async function(browser) {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = browser.contentDocument;
     let container = doc.getElementsByClassName("main-content")[0];
 
     // Test search
     let engineList = doc.getElementById("engineList");
     engineList.focus();
     EventUtils.synthesizeKey(" ", {});
     is(engineList.view.selection.currentIndex, 0, "Search engineList is selected");
--- a/browser/components/preferences/in-content/tests/browser_bug410900.js
+++ b/browser/components/preferences/in-content/tests/browser_bug410900.js
@@ -17,19 +17,21 @@ function test() {
               getService(Ci.nsIExternalProtocolService);
   var info = extps.getProtocolHandlerInfo("apppanetest");
   info.possibleApplicationHandlers.appendElement(handler);
 
   var hserv = Cc["@mozilla.org/uriloader/handler-service;1"].
               getService(Ci.nsIHandlerService);
   hserv.store(info);
 
+  /* eslint-disable mozilla/no-cpows-in-tests */
   openPreferencesViaOpenPreferencesAPI("general", {leaveOpen: true})
   .then(() => gBrowser.selectedBrowser.contentWindow.promiseLoadHandlersList)
   .then(() => runTest(gBrowser.selectedBrowser.contentWindow));
+  /* eslint-enable mozilla/no-cpows-in-tests */
 }
 
 function runTest(win) {
   var rbox = win.document.getElementById("handlersView");
   ok(rbox, "handlersView is present");
 
   var items = rbox && rbox.getElementsByTagName("richlistitem");
   ok(items && items.length > 0, "App handler list populated");
--- a/browser/components/preferences/in-content/tests/browser_change_app_handler.js
+++ b/browser/components/preferences/in-content/tests/browser_change_app_handler.js
@@ -14,16 +14,17 @@ function setupFakeHandler() {
   gHandlerSvc.store(infoToModify);
 }
 
 add_task(async function() {
   setupFakeHandler();
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.selectedBrowser.contentWindow;
 
   let container = win.document.getElementById("handlersView");
   let ourItem = container.querySelector("richlistitem[type='text/x-test-handler']");
   ok(ourItem, "handlersView is present");
   ourItem.scrollIntoView();
   container.selectItem(ourItem);
   ok(ourItem.selected, "Should be able to select our item.");
@@ -93,9 +94,8 @@ add_task(async function() {
   gBrowser.removeCurrentTab();
   await tabRemovedPromise;
 });
 
 registerCleanupFunction(function() {
   let infoToModify = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
   gHandlerSvc.remove(infoToModify);
 });
-
--- a/browser/components/preferences/in-content/tests/browser_checkspelling.js
+++ b/browser/components/preferences/in-content/tests/browser_checkspelling.js
@@ -1,16 +1,17 @@
 add_task(async function() {
   SpecialPowers.pushPrefEnv({set: [
     ["layout.spellcheckDefault", 2]
   ]});
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let checkbox = doc.querySelector("#checkSpelling");
   is(checkbox.checked,
      Services.prefs.getIntPref("layout.spellcheckDefault") == 2,
      "checkbox should represent pref value before clicking on checkbox");
   ok(checkbox.checked, "checkbox should be checked before clicking on checkbox");
 
   checkbox.click();
--- a/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
+++ b/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
@@ -323,16 +323,17 @@ var testRunner = {
         },
       };
 
       registerCleanupFunction(function() {
         Services.prefs.clearUserPref("privacy.history.custom");
       });
 
       openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true}).then(function() {
+        // eslint-disable-next-line mozilla/no-cpows-in-tests
         let doc = gBrowser.contentDocument;
         let historyMode = doc.getElementById("historyMode");
         historyMode.value = "custom";
         historyMode.doCommand();
 
         let promiseSubDialogLoaded =
           promiseLoadSubDialog("chrome://browser/content/preferences/permissions.xul");
         doc.getElementById("cookieExceptions").doCommand();
--- a/browser/components/preferences/in-content/tests/browser_engines.js
+++ b/browser/components/preferences/in-content/tests/browser_engines.js
@@ -1,12 +1,13 @@
 // Test Engine list
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("search", {leaveOpen: true});
   is(prefs.selectedPane, "paneSearch", "Search pane is selected by default");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
 
   let tree = doc.querySelector("#engineList");
   ok(!tree.hidden, "The search engine list should be visible when Search is requested");
 
   // Check for default search engines to be displayed in the engineList
   let defaultEngines = Services.search.getDefaultEngines();
   for (let i = 0; i < defaultEngines.length; i++) {
@@ -18,9 +19,8 @@ add_task(async function() {
   // Avoid duplicated keywords
   tree.view.setCellText(0, tree.columns.getNamedColumn("engineKeyword"), "keyword");
   tree.view.setCellText(1, tree.columns.getNamedColumn("engineKeyword"), "keyword");
   let cellKeyword = tree.view.getCellText(1, tree.columns.getNamedColumn("engineKeyword"));
   isnot(cellKeyword, "keyword", "Do not allow duplicated keywords");
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
-
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -43,30 +43,32 @@ function waitForMutation(target, opts, c
       }
     });
     observer.observe(target, opts);
   });
 }
 
 function waitForMessageChange(messageId, cb) {
   return waitForMutation(
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     gBrowser.contentDocument.getElementById(messageId),
     { attributes: true, attributeFilter: ["hidden"] }, cb);
 }
 
 function waitForMessageHidden(messageId) {
   return waitForMessageChange(messageId, target => target.hidden);
 }
 
 function waitForMessageShown(messageId) {
   return waitForMessageChange(messageId, target => !target.hidden);
 }
 
 add_task(async function testExtensionControlledHomepage() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#general",
      "#general should be in the URI for about:preferences");
   let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage");
   let originalHomepagePref = homepagePref();
   let extensionHomepage = "https://developer.mozilla.org/";
   let controlledContent = doc.getElementById("browserHomePageExtensionContent");
 
@@ -106,16 +108,17 @@ add_task(async function testExtensionCon
   // Do the uninstall now that the enable code has been run.
   addon.uninstall();
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function testPrefLockedHomepage() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#general",
      "#general should be in the URI for about:preferences");
 
   let homePagePref = "browser.startup.homepage";
   let buttonPrefs = [
     "pref.browser.homepage.disable_button.current_page",
     "pref.browser.homepage.disable_button.bookmark_page",
@@ -237,16 +240,17 @@ add_task(async function testPrefLockedHo
   is(controlledContent.hidden, true,
      "The extension controlled message is hidden when unlocked with no extension");
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function testExtensionControlledNewTab() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#general",
      "#general should be in the URI for about:preferences");
 
   let controlledContent = doc.getElementById("browserNewTabExtensionContent");
 
   // The new tab is set to the default and message is hidden.
   ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab is not set");
@@ -276,16 +280,17 @@ add_task(async function testExtensionCon
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   let addon = await AddonManager.getAddonByID("@set_newtab");
   addon.uninstall();
 });
 
 add_task(async function testExtensionControlledHomepageUninstalledAddon() {
   async function checkHomepageEnabled() {
     await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = gBrowser.contentDocument;
     is(gBrowser.currentURI.spec, "about:preferences#general",
       "#general should be in the URI for about:preferences");
     let controlledContent = doc.getElementById("browserHomePageExtensionContent");
 
     // The homepage is enabled.
     let homepageInut = doc.getElementById("browserHomePage");
     is(homepageInut.disabled, false, "The homepage input is enabled");
--- a/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
+++ b/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
@@ -1,12 +1,13 @@
 add_task(async function testSetHomepageUseCurrent() {
   is(gBrowser.currentURI.spec, "about:blank", "Test starts with about:blank open");
   await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#general",
      "#general should be in the URI for about:preferences");
   let oldHomepagePref = Services.prefs.getCharPref("browser.startup.homepage");
 
   let useCurrent = doc.getElementById("useCurrent");
   useCurrent.click();
 
--- a/browser/components/preferences/in-content/tests/browser_layersacceleration.js
+++ b/browser/components/preferences/in-content/tests/browser_layersacceleration.js
@@ -2,16 +2,17 @@ add_task(async function() {
   SpecialPowers.pushPrefEnv({set: [
     ["gfx.direct2d.disabled", false],
     ["layers.acceleration.disabled", false]
   ]});
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let checkbox = doc.querySelector("#allowHWAccel");
   is(!checkbox.checked,
      Services.prefs.getBoolPref("layers.acceleration.disabled"),
      "checkbox should represent inverted pref value before clicking on checkbox");
 
   checkbox.click();
 
--- a/browser/components/preferences/in-content/tests/browser_masterpassword.js
+++ b/browser/components/preferences/in-content/tests/browser_masterpassword.js
@@ -1,12 +1,13 @@
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
   is(prefs.selectedPane, "panePrivacy", "Privacy pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   // Fake the subdialog and LoginHelper
   let win = doc.defaultView;
   let dialogURL = "";
   win.gSubDialog = {
     open(aDialogURL, unused, unused2, aCallback) {
       dialogURL = aDialogURL;
       masterPasswordSet = masterPasswordNextState;
--- a/browser/components/preferences/in-content/tests/browser_notifications_do_not_disturb.js
+++ b/browser/components/preferences/in-content/tests/browser_notifications_do_not_disturb.js
@@ -6,16 +6,17 @@ registerCleanupFunction(function() {
   while (gBrowser.tabs[1])
     gBrowser.removeTab(gBrowser.tabs[1]);
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
   is(prefs.selectedPane, "panePrivacy", "Privacy pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let notificationsDoNotDisturbBox = doc.getElementById("notificationsDoNotDisturbBox");
   if (notificationsDoNotDisturbBox.hidden) {
     todo(false, "Do not disturb is not available on this platform");
     return;
   }
 
   let alertService;
--- a/browser/components/preferences/in-content/tests/browser_performance.js
+++ b/browser/components/preferences/in-content/tests/browser_performance.js
@@ -8,16 +8,17 @@ add_task(async function() {
     ["browser.preferences.defaultPerformanceSettings.enabled", true],
   ]});
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let useRecommendedPerformanceSettings = doc.querySelector("#useRecommendedPerformanceSettings");
 
   is(Services.prefs.getBoolPref("browser.preferences.defaultPerformanceSettings.enabled"), true,
     "pref value should be true before clicking on checkbox");
   ok(useRecommendedPerformanceSettings.checked, "checkbox should be checked before clicking on checkbox");
 
   useRecommendedPerformanceSettings.click();
@@ -73,16 +74,17 @@ add_task(async function() {
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", true);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let useRecommendedPerformanceSettings = doc.querySelector("#useRecommendedPerformanceSettings");
   let allowHWAccel = doc.querySelector("#allowHWAccel");
   let contentProcessCount = doc.querySelector("#contentProcessCount");
   let performanceSettings = doc.querySelector("#performanceSettings");
 
   useRecommendedPerformanceSettings.click();
   allowHWAccel.click();
@@ -98,16 +100,17 @@ add_task(async function() {
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", true);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let performanceSettings = doc.querySelector("#performanceSettings");
 
   is(performanceSettings.hidden, true, "performance settings section should not be shown");
 
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", false);
 
   is(performanceSettings.hidden, false, "performance settings section should be shown");
@@ -117,16 +120,17 @@ add_task(async function() {
 });
 
 add_task(async function() {
   Services.prefs.setIntPref("dom.ipc.processCount", 7);
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
 
   let performanceSettings = doc.querySelector("#performanceSettings");
   is(performanceSettings.hidden, false, "performance settings section should be shown");
 
   let contentProcessCount = doc.querySelector("#contentProcessCount");
   is(Services.prefs.getIntPref("dom.ipc.processCount"), 7, "pref value should be 7");
   is(contentProcessCount.selectedItem.value, 7, "selected item should be 7");
@@ -136,16 +140,17 @@ add_task(async function() {
 });
 
 add_task(async function() {
   Services.prefs.setBoolPref("layers.acceleration.disabled", true);
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
 
   let performanceSettings = doc.querySelector("#performanceSettings");
   is(performanceSettings.hidden, false, "performance settings section should be shown");
 
   let allowHWAccel = doc.querySelector("#allowHWAccel");
   is(Services.prefs.getBoolPref("layers.acceleration.disabled"), true,
     "pref value is false");
--- a/browser/components/preferences/in-content/tests/browser_performance_e10srollout.js
+++ b/browser/components/preferences/in-content/tests/browser_performance_e10srollout.js
@@ -11,16 +11,17 @@ add_task(async function() {
 
 add_task(async function testPrefsAreDefault() {
   Services.prefs.setIntPref("dom.ipc.processCount", DEFAULT_PROCESS_COUNT);
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", true);
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let useRecommendedPerformanceSettings = doc.querySelector("#useRecommendedPerformanceSettings");
 
   is(Services.prefs.getBoolPref("browser.preferences.defaultPerformanceSettings.enabled"), true,
      "pref value should be true before clicking on checkbox");
   ok(useRecommendedPerformanceSettings.checked, "checkbox should be checked before clicking on checkbox");
 
   useRecommendedPerformanceSettings.click();
@@ -45,16 +46,17 @@ add_task(async function testPrefsAreDefa
 
 add_task(async function testPrefsSetByUser() {
   Services.prefs.setIntPref("dom.ipc.processCount", DEFAULT_PROCESS_COUNT + 2);
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", false);
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let performanceSettings = doc.querySelector("#performanceSettings");
   is(performanceSettings.hidden, false, "performance settings section is shown");
 
   let contentProcessCount = doc.querySelector("#contentProcessCount");
   is(contentProcessCount.disabled, false, "process count control should be enabled");
   is(Services.prefs.getIntPref("dom.ipc.processCount"), DEFAULT_PROCESS_COUNT + 2, "process count should be the set value");
   is(contentProcessCount.selectedItem.value, DEFAULT_PROCESS_COUNT + 2, "selected item should be the set one");
--- a/browser/components/preferences/in-content/tests/browser_performance_non_e10s.js
+++ b/browser/components/preferences/in-content/tests/browser_performance_non_e10s.js
@@ -8,16 +8,17 @@ add_task(async function() {
     ["browser.preferences.defaultPerformanceSettings.enabled", true],
   ]});
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let useRecommendedPerformanceSettings = doc.querySelector("#useRecommendedPerformanceSettings");
 
   is(Services.prefs.getBoolPref("browser.preferences.defaultPerformanceSettings.enabled"), true,
     "pref value should be true before clicking on checkbox");
   ok(useRecommendedPerformanceSettings.checked, "checkbox should be checked before clicking on checkbox");
 
   useRecommendedPerformanceSettings.click();
@@ -61,16 +62,17 @@ add_task(async function() {
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", true);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function() {
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   let performanceSettings = doc.querySelector("#performanceSettings");
 
   is(performanceSettings.hidden, true, "performance settings section should not be shown");
 
   Services.prefs.setBoolPref("browser.preferences.defaultPerformanceSettings.enabled", false);
 
   is(performanceSettings.hidden, false, "performance settings section should be shown");
@@ -80,16 +82,17 @@ add_task(async function() {
 });
 
 add_task(async function() {
   Services.prefs.setBoolPref("layers.acceleration.disabled", true);
 
   let prefs = await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
   is(prefs.selectedPane, "paneGeneral", "General pane was selected");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
 
   let performanceSettings = doc.querySelector("#performanceSettings");
   is(performanceSettings.hidden, false, "performance settings section should be shown");
 
   let allowHWAccel = doc.querySelector("#allowHWAccel");
   is(Services.prefs.getBoolPref("layers.acceleration.disabled"), true,
     "pref value is false");
--- a/browser/components/preferences/in-content/tests/browser_permissions_urlFieldHidden.js
+++ b/browser/components/preferences/in-content/tests/browser_permissions_urlFieldHidden.js
@@ -1,14 +1,15 @@
 "use strict";
 
 const PERMISSIONS_URL = "chrome://browser/content/preferences/permissions.xul";
 
 add_task(async function urlFieldVisibleForPopupPermissions(finish) {
   await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.selectedBrowser.contentWindow;
   let doc = win.document;
   let popupPolicyCheckbox = doc.getElementById("popupPolicy");
   ok(!popupPolicyCheckbox.checked, "popupPolicyCheckbox should be unchecked by default");
   popupPolicyCheckbox.click();
   let popupPolicyButton = doc.getElementById("popupPolicyButton");
   ok(popupPolicyButton, "popupPolicyButton found");
   let dialogPromise = promiseLoadSubDialog(PERMISSIONS_URL);
--- a/browser/components/preferences/in-content/tests/browser_sanitizeOnShutdown_prefLocked.js
+++ b/browser/components/preferences/in-content/tests/browser_sanitizeOnShutdown_prefLocked.js
@@ -3,16 +3,17 @@
 function switchToCustomHistoryMode(doc) {
   // Select the last item in the menulist.
   let menulist = doc.getElementById("historyMode");
   menulist.focus();
   EventUtils.sendKey("UP");
 }
 
 function testPrefStateMatchesLockedState() {
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.contentWindow;
   let doc = win.document;
   switchToCustomHistoryMode(doc);
 
   let checkbox = doc.getElementById("alwaysClear");
   let preference = doc.getElementById("privacy.sanitize.sanitizeOnShutdown");
   is(checkbox.disabled, preference.locked, "Always Clear checkbox should be enabled when preference is not locked.");
 
--- a/browser/components/preferences/in-content/tests/browser_search_within_preferences_1.js
+++ b/browser/components/preferences/in-content/tests/browser_search_within_preferences_1.js
@@ -1,13 +1,15 @@
 "use strict";
 /**
  * This file contains tests for the Preferences search bar.
  */
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 requestLongerTimeout(6);
 
 /**
  * Tests to see if search bar is being shown when pref is turned on
  */
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", { leaveOpen: true });
   let searchInput = gBrowser.contentDocument.getElementById("searchInput");
--- a/browser/components/preferences/in-content/tests/browser_search_within_preferences_2.js
+++ b/browser/components/preferences/in-content/tests/browser_search_within_preferences_2.js
@@ -1,13 +1,15 @@
 "use strict";
 /**
  * This file contains tests for the Preferences search bar.
  */
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 /**
  * Enabling searching functionality. Will display search bar from this testcase forward.
  */
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
 });
 
 /**
--- a/browser/components/preferences/in-content/tests/browser_search_within_preferences_command.js
+++ b/browser/components/preferences/in-content/tests/browser_search_within_preferences_command.js
@@ -1,10 +1,12 @@
 "use strict";
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 /**
  * Test for "command" event on search input (when user clicks the x button)
  */
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({"set": [["browser.storageManager.enabled", false]]});
   await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
   let generalPane = gBrowser.contentDocument.getElementById("generalCategory");
 
--- a/browser/components/preferences/in-content/tests/browser_security-1.js
+++ b/browser/components/preferences/in-content/tests/browser_security-1.js
@@ -47,16 +47,17 @@ add_task(async function() {
     }
 
     is(checked, val1 && val2, "safebrowsing preference is initialized correctly");
     // should be disabled when checked is false (= pref is turned off)
     is(blockUncommon.hasAttribute("disabled"), !checked, "block uncommon checkbox is set correctly");
 
     // scroll the checkbox into the viewport and click checkbox
     checkbox.scrollIntoView();
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     EventUtils.synthesizeMouseAtCenter(checkbox, {}, gBrowser.selectedBrowser.contentWindow);
 
     // check that both settings are now turned on or off
     is(Services.prefs.getBoolPref("browser.safebrowsing.phishing.enabled"), !checked,
        "safebrowsing.enabled is set correctly");
     is(Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled"), !checked,
        "safebrowsing.malware.enabled is set correctly");
 
--- a/browser/components/preferences/in-content/tests/browser_security-2.js
+++ b/browser/components/preferences/in-content/tests/browser_security-2.js
@@ -44,16 +44,17 @@ add_task(async function() {
     let blockUncommon = doc.getElementById("blockUncommonUnwanted");
     let checked = checkbox.checked;
     is(checked, val, "downloads preference is initialized correctly");
     // should be disabled when val is false (= pref is turned off)
     is(blockUncommon.hasAttribute("disabled"), !val, "block uncommon checkbox is set correctly");
 
     // scroll the checkbox into view, otherwise the synthesizeMouseAtCenter will be ignored, and click it
     checkbox.scrollIntoView();
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     EventUtils.synthesizeMouseAtCenter(checkbox, {}, gBrowser.selectedBrowser.contentWindow);
 
     // check that setting is now turned on or off
     is(Services.prefs.getBoolPref("browser.safebrowsing.downloads.enabled"), !checked,
        "safebrowsing.downloads preference is set correctly");
 
     // check if the uncommon warning checkbox has updated
     is(blockUncommon.hasAttribute("disabled"), val, "block uncommon checkbox is set correctly");
@@ -83,16 +84,17 @@ add_task(async function() {
 
     let doc = gBrowser.selectedBrowser.contentDocument;
     let checkbox = doc.getElementById("blockUncommonUnwanted");
     let checked = checkbox.checked;
     is(checked, val1 && val2, "unwanted/uncommon preference is initialized correctly");
 
     // scroll the checkbox into view, otherwise the synthesizeMouseAtCenter will be ignored, and click it
     checkbox.scrollIntoView();
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     EventUtils.synthesizeMouseAtCenter(checkbox, {}, gBrowser.selectedBrowser.contentWindow);
 
     // check that both settings are now turned on or off
     is(Services.prefs.getBoolPref("browser.safebrowsing.downloads.remote.block_potentially_unwanted"), !checked,
        "block_potentially_unwanted is set correctly");
     is(Services.prefs.getBoolPref("browser.safebrowsing.downloads.remote.block_uncommon"), !checked,
        "block_uncommon is set correctly");
 
--- a/browser/components/preferences/in-content/tests/browser_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData.js
@@ -97,16 +97,17 @@ add_task(async function() {
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
 
   // Open a test site which would save into appcache
   await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
   // Open a test site which would save into quota manager
   await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL);
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   await waitForEvent(gBrowser.selectedBrowser.contentWindow, "test-indexedDB-done");
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
   let updatedPromise = promiseSiteDataManagerSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   await updatedPromise;
   await openSiteDataSettingsDialog();
   let dialog = content.gSubDialog._topDialog;
@@ -179,16 +180,17 @@ add_task(async function() {
 });
 
 // Test the function of the "Clear All Data" button
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
   addPersistentStoragePerm(TEST_QUOTA_USAGE_ORIGIN);
 
   await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL);
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   await waitForEvent(gBrowser.selectedBrowser.contentWindow, "test-indexedDB-done");
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
 
   // Test the initial states
   let cacheUsage = await cacheUsageGetter.get();
   let quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
--- a/browser/components/preferences/in-content/tests/browser_siteData2.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData2.js
@@ -1,12 +1,14 @@
 "use strict";
 const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
 const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 function promiseSettingsDialogClose() {
   return new Promise(resolve => {
     let win = gBrowser.selectedBrowser.contentWindow;
     let dialogOverlay = win.gSubDialog._topDialog._overlay;
     let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
     dialogWin.addEventListener("unload", function unload() {
       if (dialogWin.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
         isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
--- a/browser/components/preferences/in-content/tests/browser_siteData3.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData3.js
@@ -76,16 +76,17 @@ add_task(async function() {
       persisted: false
     },
   ];
 
   let updatedPromise = promiseSiteDataManagerSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   await updatedPromise;
   await openSiteDataSettingsDialog();
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.selectedBrowser.contentWindow;
   let dialogFrame = win.gSubDialog._topDialog._frame;
   let frameDoc = dialogFrame.contentDocument;
 
   let siteItems = frameDoc.getElementsByTagName("richlistitem");
   is(siteItems.length, 1, "Should group sites across scheme, port and origin attributes");
 
   let expected = "account.xyz.com";
--- a/browser/components/search/test/browser_aboutSearchReset.js
+++ b/browser/components/search/test/browser_aboutSearchReset.js
@@ -56,16 +56,17 @@ var gTests = [
                       getSubmission(kSearchStr, null, kSearchPurpose).
                       uri.spec;
 
     let rawEngine = engine.wrappedJSObject;
     let initialHash = rawEngine.getAttr("loadPathHash");
     rawEngine.setAttr("loadPathHash", "broken");
 
     let loadPromise = promiseStoppedLoad(expectedURL);
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     gBrowser.contentDocument.getElementById("searchResetKeepCurrent").click();
     await loadPromise;
 
     is(engine, Services.search.currentEngine,
        "the custom engine is still default");
     is(rawEngine.getAttr("loadPathHash"), initialHash,
        "the loadPathHash has been fixed");
 
@@ -73,16 +74,17 @@ var gTests = [
   }
 },
 
 {
   desc: "Test the 'Restore Search Defaults' button.",
   async run() {
     let currentEngine = Services.search.currentEngine;
     let originalEngine = Services.search.originalDefaultEngine;
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = gBrowser.contentDocument;
     let defaultEngineSpan = doc.getElementById("defaultEngine");
     is(defaultEngineSpan.textContent, originalEngine.name,
        "the name of the original default engine is displayed");
 
     let expectedURL = originalEngine.
                       getSubmission(kSearchStr, null, kSearchPurpose).
                       uri.spec;
@@ -102,16 +104,17 @@ var gTests = [
 },
 
 {
   desc: "Click the settings link.",
   async run() {
     let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
                                                      false,
                                                      "about:preferences");
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     gBrowser.contentDocument.getElementById("linkSettingsPage").click();
     await loadPromise;
 
     checkTelemetryRecords(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
   }
 },
 
 {
--- a/browser/components/sessionstore/test/browser_480893.js
+++ b/browser/components/sessionstore/test/browser_480893.js
@@ -11,16 +11,17 @@ add_task(async function() {
     ]
   });
 
   let tab = BrowserTestUtils.addTab(gBrowser, "about:sessionrestore");
   gBrowser.selectedTab = tab;
   let browser = tab.linkedBrowser;
   await BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = browser.contentDocument;
 
   // Click on the "Close" button after about:sessionrestore is loaded.
   doc.getElementById("errorCancel").click();
 
   await BrowserTestUtils.browserLoaded(browser, false, "about:blank");
 
   // Test that starting a new session loads the homepage (set to http://mochi.test:8888)
@@ -30,16 +31,17 @@ add_task(async function() {
     "set": [
       ["browser.startup.homepage", homepage],
       ["browser.startup.page", 1],
     ]
   });
 
   browser.loadURI("about:sessionrestore");
   await BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   doc = browser.contentDocument;
 
   // Click on the "Close" button after about:sessionrestore is loaded.
   doc.getElementById("errorCancel").click();
   await BrowserTestUtils.browserLoaded(browser);
 
   is(browser.currentURI.spec, homepage, "loaded page is the homepage");
 
--- a/browser/components/sessionstore/test/browser_590563.js
+++ b/browser/components/sessionstore/test/browser_590563.js
@@ -27,23 +27,25 @@ function test() {
         middleClickTest(win);
       }, win);
     });
   });
 }
 
 async function middleClickTest(win) {
   let browser = win.gBrowser.selectedBrowser;
+  /* eslint-disable mozilla/no-cpows-in-tests */
   let tabsToggle = browser.contentDocument.getElementById("tabsToggle");
   EventUtils.synthesizeMouseAtCenter(tabsToggle, { button: 0 }, browser.contentWindow);
   let treeContainer = browser.contentDocument.querySelector(".tree-container");
   await BrowserTestUtils.waitForCondition(() => win.getComputedStyle(treeContainer).visibility == "visible");
 
   let tree = browser.contentDocument.getElementById("tabList");
   is(tree.view.rowCount, 3, "There should be three items");
+  /* eslint-enable mozilla/no-cpows-in-tests */
 
   // click on the first tab item
   var rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text");
   EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
                              browser.contentWindow);
   // click on the second tab item
   rect = tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text");
   EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
--- a/browser/components/sessionstore/test/browser_705597.js
+++ b/browser/components/sessionstore/test/browser_705597.js
@@ -42,16 +42,17 @@ function test() {
           waitForBrowserState(blankState, finish);
         });
 
         // Force reload the browser to deprecate the subframes.
         browser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
       });
 
       // Create a dynamic subframe.
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       let doc = browser.contentDocument;
       let iframe = doc.createElement("iframe");
       doc.body.appendChild(iframe);
       iframe.setAttribute("src", "about:mozilla");
     });
   });
 }
 
--- a/browser/components/sessionstore/test/browser_707862.js
+++ b/browser/components/sessionstore/test/browser_707862.js
@@ -41,16 +41,17 @@ function test() {
           });
         });
 
         // Force reload the browser to deprecate the subframes.
         browser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
       });
 
       // Create a dynamic subframe.
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       let doc = browser.contentDocument;
       let iframe = doc.createElement("iframe");
       doc.body.appendChild(iframe);
       iframe.setAttribute("src", "about:mozilla");
     });
   });
 
   // This test relies on the test timing out in order to indicate failure so
--- a/browser/components/sessionstore/test/browser_aboutSessionRestore.js
+++ b/browser/components/sessionstore/test/browser_aboutSessionRestore.js
@@ -24,16 +24,17 @@ add_task(async function() {
   await promiseBrowserLoaded(browser);
 
   // Fake a post-crash tab.
   ss.setTabState(tab, JSON.stringify(TAB_STATE));
   await promiseTabRestored(tab);
 
   ok(gBrowser.tabs.length > 1, "we have more than one tab");
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let view = browser.contentDocument.getElementById("tabList").view;
   ok(view.isContainer(0), "first entry is the window");
   is(view.getCellProperties(1, { id: "title" }), "icon",
     "second entry is the tab and has a favicon");
 
   browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
 
   // Wait until the new window was restored.
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -385,16 +385,17 @@ add_task(async function test_hide_restor
   browser.loadURI(PAGE_1);
   await promiseBrowserLoaded(browser);
 
   await TabStateFlusher.flush(browser);
 
   // Crash the tab
   await BrowserTestUtils.crashBrowser(browser);
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = browser.contentDocument;
   let restoreAllButton = doc.getElementById("restoreAll");
   let restoreOneButton = doc.getElementById("restoreTab");
 
   let restoreAllStyles = window.getComputedStyle(restoreAllButton);
   is(restoreAllStyles.display, "none", "Restore All button should be hidden");
   ok(restoreOneButton.classList.contains("primary"), "Restore Tab button should have the primary class");
 
@@ -415,16 +416,17 @@ add_task(async function test_hide_restor
   // sending its AboutTabCrashedReady event before we know for
   // sure whether or not we're showing the right Restore buttons.
   let otherBrowserReady = promiseTabCrashedReady(otherWinBrowser);
 
   // Crash the first tab.
   await BrowserTestUtils.crashBrowser(browser);
   await otherBrowserReady;
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   doc = browser.contentDocument;
   restoreAllButton = doc.getElementById("restoreAll");
   restoreOneButton = doc.getElementById("restoreTab");
 
   restoreAllStyles = window.getComputedStyle(restoreAllButton);
   isnot(restoreAllStyles.display, "none", "Restore All button should not be hidden");
   ok(!(restoreOneButton.classList.contains("primary")), "Restore Tab button should not have the primary class");
 
--- a/browser/components/sessionstore/test/browser_swapDocShells.js
+++ b/browser/components/sessionstore/test/browser_swapDocShells.js
@@ -21,15 +21,16 @@ function promiseDelayedStartupFinished(w
   return new Promise(resolve => {
     whenDelayedStartupFinished(win, resolve);
   });
 }
 
 function promiseBrowserHasURL(browser, url) {
   let promise = Promise.resolve();
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   if (browser.contentDocument.readyState === "complete" &&
       browser.currentURI.spec === url) {
     return promise;
   }
 
   return promise.then(() => promiseBrowserHasURL(browser, url));
 }
--- a/browser/extensions/formautofill/.eslintrc.js
+++ b/browser/extensions/formautofill/.eslintrc.js
@@ -1,16 +1,15 @@
 "use strict";
 
 module.exports = {
   "rules": {
     // Rules from the mozilla plugin
     "mozilla/balanced-listeners": "error",
     "mozilla/no-aArgs": "error",
-    "mozilla/no-cpows-in-tests": "error",
     "mozilla/var-only-at-top-level": "error",
 
     "valid-jsdoc": ["error", {
       "prefer": {
         "return": "returns",
       },
       "preferType": {
         "Boolean": "boolean",
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -18,17 +18,17 @@ const ALTERNATIVE_COUNTRY_NAMES = {
 
 const ADDRESSES_COLLECTION_NAME = "addresses";
 const CREDITCARDS_COLLECTION_NAME = "creditCards";
 const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
 const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";
 const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
 const MANAGE_ADDRESSES_KEYWORDS = ["manageAddressesTitle", "addNewAddressTitle"];
 const EDIT_ADDRESS_KEYWORDS = [
-  "givenName", "additionalName", "familyName", "organization", "streetAddress",
+  "givenName", "additionalName", "familyName", "organization2", "streetAddress",
   "state", "province", "city", "country", "zip", "postalCode", "email", "tel",
 ];
 const MANAGE_CREDITCARDS_KEYWORDS = ["manageCreditCardsTitle", "addNewCreditCardTitle", "showCreditCardsBtnLabel"];
 const EDIT_CREDITCARD_KEYWORDS = ["cardNumber", "nameOnCard", "cardExpires"];
 
 // The maximum length of data to be saved in a single field for preventing DoS
 // attacks that fill the user's hard drive(s).
 const MAX_FIELD_VALUE_LENGTH = 200;
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -21,17 +21,17 @@
       <span data-localization="additionalName"/>
       <input id="additional-name" type="text"/>
     </label>
     <label id="family-name-container">
       <span data-localization="familyName"/>
       <input id="family-name" type="text"/>
     </label>
     <label id="organization-container">
-      <span data-localization="organization"/>
+      <span data-localization="organization2"/>
       <input id="organization" type="text"/>
     </label>
     <label id="street-address-container">
       <span data-localization="streetAddress"/>
       <textarea id="street-address" rows="3"/>
     </label>
     <label id="address-level2-container">
       <span data-localization="city"/>
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -186,32 +186,35 @@
            * 2. An address was selested: Show the additional categories that will also be filled.
            * 3. An address was selected, but the focused category is the same as the only one category: Only show
            * the exact category that we're going to fill in.
            *
            * @private
            * @param {string[]} data.categories
            *        The categories of all the fields contained in the selected address.
            */
-          const namespace = "category.";
           this._updateWarningNote = ({data} = {}) => {
             let categories = (data && data.categories) ? data.categories : this._allFieldCategories;
             // If the length of categories is 1, that means all the fillable fields are in the same
             // category. We will change the way to inform user according to this flag. When the value
             // is true, we show "Also autofills ...", otherwise, show "Autofills ..." only.
             let hasExtraCategories = categories.length > 1;
             // Show the categories in certain order to conform with the spec.
-            let orderedCategoryList = ["address", "name", "organization", "tel", "email"];
+            let orderedCategoryList = [{id: "address", l10nId: "category.address"},
+                                       {id: "name", l10nId: "category.name"},
+                                       {id: "organization", l10nId: "category.organization2"},
+                                       {id: "tel", l10nId: "category.tel"},
+                                       {id: "email", l10nId: "category.email"}];
             let showCategories = hasExtraCategories ?
-              orderedCategoryList.filter(category => categories.includes(category) && category != this._focusedCategory) :
-              [this._focusedCategory];
+              orderedCategoryList.filter(category => categories.includes(category.id) && category.id != this._focusedCategory) :
+              [orderedCategoryList.find(category => category.id == this._focusedCategory)];
 
             let separator = this._stringBundle.GetStringFromName("fieldNameSeparator");
             let warningTextTmplKey = hasExtraCategories ? "phishingWarningMessage" : "phishingWarningMessage2";
-            let categoriesText = showCategories.map(category => this._stringBundle.GetStringFromName(namespace + category)).join(separator);
+            let categoriesText = showCategories.map(category => this._stringBundle.GetStringFromName(category.l10nId)).join(separator);
 
             this._warningTextBox.textContent = this._stringBundle.formatStringFromName(warningTextTmplKey,
               [categoriesText], 1);
             this.parentNode.parentNode.adjustHeight();
           };
 
           this._adjustAcItem();
         ]]>
--- a/browser/extensions/formautofill/locales/en-US/formautofill.properties
+++ b/browser/extensions/formautofill/locales/en-US/formautofill.properties
@@ -42,29 +42,29 @@ openAutofillMessagePanel = Open Form Aut
 # displayed at the bottom of the drop down suggestion, to open Form Autofill browser preferences.
 autocompleteFooterOption = Form Autofill Options
 autocompleteFooterOptionOSX = Form Autofill Preferences
 # LOCALIZATION NOTE (autocompleteFooterOptionShort, autocompleteFooterOptionOSXShort): Used as a label for the button,
 # displayed at the bottom of the drop down suggestion, to open Form Autofill browser preferences. This version is used
 # instead of autocompleteFooterOption* when the menu width is below 185px.
 autocompleteFooterOptionShort = More Options
 autocompleteFooterOptionOSXShort = Preferences
-# LOCALIZATION NOTE (category.address, category.name, category.organization, category.tel, category.email):
+# LOCALIZATION NOTE (category.address, category.name, category.organization2, category.tel, category.email):
 # Used in autofill drop down suggestion to indicate what other categories Form Autofill will attempt to fill.
 category.address = address
 category.name = name
-category.organization = company
+category.organization2 = organization
 category.tel = phone
 category.email = email
 # LOCALIZATION NOTE (fieldNameSeparator): This is used as a separator between categories.
 fieldNameSeparator = ,\u0020
 # LOCALIZATION NOTE (phishingWarningMessage, phishingWarningMessage2): The warning
 # text that is displayed for informing users what categories are about to be filled.
 # "%S" will be replaced with a list generated from the pre-defined categories.
-# The text would be e.g. Also autofills company, phone, email.
+# The text would be e.g. Also autofills organization, phone, email.
 phishingWarningMessage = Also autofills %S
 phishingWarningMessage2 = Autofills %S
 # LOCALIZATION NOTE (insecureFieldWarningDescription): %S is brandShortName. This string is used in drop down
 # suggestion when users try to autofill credit card on an insecure website (without https).
 insecureFieldWarningDescription = %S has detected an insecure site. Form Autofill is temporarily disabled.
 
 # LOCALIZATION NOTE (autofillAddressesCheckbox): Label for the checkbox that enables autofilling addresses.
 autofillAddressesCheckbox = Autofill addresses
@@ -95,17 +95,17 @@ editBtnLabel = Edit…
 
 # LOCALIZATION NOTE (addNewAddressTitle, editAddressTitle): The dialog title for creating or editing addresses
 # in browser preferences.
 addNewAddressTitle = Add New Address
 editAddressTitle = Edit Address
 givenName = First Name
 additionalName = Middle Name
 familyName = Last Name
-organization = Company
+organization2 = Organization
 streetAddress = Street Address
 city = City
 province = Province
 state = State
 postalCode = Postal Code
 zip = Zip Code
 country = Country or Region
 tel = Phone
--- a/browser/extensions/formautofill/test/browser/browser_autocomplete_footer.js
+++ b/browser/extensions/formautofill/test/browser/browser_autocomplete_footer.js
@@ -68,20 +68,20 @@ add_task(async function test_phishing_wa
     await closePopup(browser);
   });
 });
 
 add_task(async function test_phishing_warning_complex_categories() {
   await BrowserTestUtils.withNewTab({gBrowser, url: URL}, async function(browser) {
     await openPopupOn(browser, "#street-address");
 
-    await expectWarningText(browser, "Also autofills company, email");
+    await expectWarningText(browser, "Also autofills organization, email");
     await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
     await expectWarningText(browser, "Autofills address");
     await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
     await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
-    await expectWarningText(browser, "Also autofills company, email");
+    await expectWarningText(browser, "Also autofills organization, email");
     await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
-    await expectWarningText(browser, "Also autofills company, email");
+    await expectWarningText(browser, "Also autofills organization, email");
 
     await closePopup(browser);
   });
 });
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
@@ -8,16 +8,17 @@ requestLongerTimeout(2);
 add_task(async function test_onboarding_default_new_tourset() {
   resetOnboardingDefaultState();
 
   let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, TOUR_IDs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(TOUR_IDs[idx], dom.id, "contain defined onboarding id");
   });
 
   await BrowserTestUtils.removeTab(tab);
@@ -38,16 +39,17 @@ add_task(async function test_onboarding_
     ["browser.onboarding.newtour", "private,addons,customize"],
   ]});
 
   let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, CUSTOM_NEW_TOURs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(CUSTOM_NEW_TOURs[idx], dom.id, "contain defined onboarding id");
   });
 
   await BrowserTestUtils.removeTab(tab);
@@ -67,16 +69,17 @@ add_task(async function test_onboarding_
     ["browser.onboarding.updatetour", "customize,private,addons"],
   ]});
 
   let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, CUSTOM_UPDATE_TOURs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(CUSTOM_UPDATE_TOURs[idx], dom.id, "contain defined onboarding id");
   });
 
   await BrowserTestUtils.removeTab(tab);
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -213,17 +213,17 @@ var PocketPageAction = {
   // Sets or removes the "pocketed" attribute on the Pocket urlbar button as
   // necessary.
   updateUrlbarNodeState(browserWindow) {
     if (!this.pageAction) {
       return;
     }
     let {BrowserPageActions} = browserWindow;
     let urlbarNode = browserWindow.document.getElementById(
-      BrowserPageActions._urlbarButtonNodeIDForActionID(this.pageAction.id)
+      BrowserPageActions.urlbarButtonNodeIDForActionID(this.pageAction.id)
     );
     if (!urlbarNode) {
       return;
     }
     let browser = browserWindow.gBrowser.selectedBrowser;
     let pocketedInnerWindowID = this.innerWindowIDsByBrowser.get(browser);
     if (pocketedInnerWindowID == browser.innerWindowID) {
       // The current window in this browser is pocketed.
--- a/browser/extensions/shield-recipe-client/test/browser/browser_about_preferences.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_about_preferences.js
@@ -1,10 +1,12 @@
 "use strict";
 
+/* eslint-disable mozilla/no-cpows-in-tests */
+
 Cu.import("resource://gre/modules/Services.jsm", this);
 
 const OPT_OUT_PREF = "app.shield.optoutstudies.enabled";
 const FHR_PREF = "datareporting.healthreport.uploadEnabled";
 
 function withPrivacyPrefs(testFunc) {
   return async (...args) => (
     BrowserTestUtils.withNewTab("about:preferences#privacy", async browser => (
--- a/browser/extensions/shield-recipe-client/test/browser/browser_about_studies.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_about_studies.js
@@ -9,16 +9,17 @@ function withAboutStudies(testFunc) {
       testFunc(...args, browser)
     ))
   );
 }
 
 decorate_task(
   withAboutStudies,
   async function testAboutStudiesWorks(browser) {
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
     ok(browser.contentDocument.getElementById("app"), "App element was found");
   }
 );
 
 decorate_task(
   withPrefEnv({
     set: [["extensions.shield-recipe-client.shieldLearnMoreUrl", "http://test/%OS%/"]],
   }),
@@ -45,21 +46,23 @@ decorate_task(
     // We have to use gBrowser instead of browser in most spots since we're
     // dealing with a new tab outside of the about:studies tab.
     const tab = await BrowserTestUtils.switchTab(gBrowser, () => {
       ContentTask.spawn(browser, null, () => {
         content.document.getElementById("shield-studies-update-preferences").click();
       });
     });
 
+    /* eslint-disable mozilla/no-cpows-in-tests */
     if (gBrowser.contentDocument.readyState !== "complete") {
       await BrowserTestUtils.waitForEvent(gBrowser.contentWindow, "load");
     }
 
     const location = gBrowser.contentWindow.location.href;
+    /* eslint-enable mozilla/no-cpows-in-tests */
     is(
       location,
       "about:preferences#privacy",
       "Clicking Update Preferences opens the privacy section of the new about:preferences.",
     );
 
     await BrowserTestUtils.removeTab(tab);
   }
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -61,16 +61,17 @@ lt
 lv
 mai
 mk
 ml
 mr
 ms
 my
 nb-NO
+ne-NP
 nl
 nn-NO
 or
 pa-IN
 pl
 pt-BR
 pt-PT
 rm
--- a/browser/modules/PageActions.jsm
+++ b/browser/modules/PageActions.jsm
@@ -16,16 +16,18 @@ this.EXPORTED_SYMBOLS = [
 
 const { utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
+  "resource://gre/modules/AsyncShutdown.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BinarySearch",
   "resource://gre/modules/BinarySearch.jsm");
 
 
 const ACTION_ID_BOOKMARK = "bookmark";
 const ACTION_ID_BOOKMARK_SEPARATOR = "bookmarkSeparator";
 const ACTION_ID_BUILT_IN_SEPARATOR = "builtInSeparator";
 
@@ -59,16 +61,26 @@ this.PageActions = {
       bpa.placeAllActions();
     }
 
     // These callbacks are deferred until init happens and all built-in actions
     // are added.
     while (callbacks && callbacks.length) {
       callbacks.shift()();
     }
+
+    // Purge removed actions from persisted state on shutdown.  The point is not
+    // to do it on Action.remove().  That way actions that are removed and
+    // re-added while the app is running will have their urlbar placement and
+    // other state remembered and restored.  This happens for upgraded and
+    // downgraded extensions, for example.
+    AsyncShutdown.profileBeforeChange.addBlocker(
+      "PageActions: purging unregistered actions from cache",
+      () => this._purgeUnregisteredPersistedActions(),
+    );
   },
 
   _deferredAddActionCalls: [],
 
   /**
    * The list of Action objects, sorted in the order in which they should be
    * placed in the page action panel.  If there are both built-in and non-built-
    * in actions, then the list will include the separator between the two.  The
@@ -205,17 +217,17 @@ this.PageActions = {
     } else if (gBuiltInActions.find(a => a.id == action.id)) {
       // A built-in action.  These are always added on init before all other
       // actions, one after the other, so just push onto the array.
       this._builtInActions.push(action);
     } else {
       // A non-built-in action, like a non-bundled extension potentially.
       // Keep this list sorted by title.
       let index = BinarySearch.insertionIndexOf((a1, a2) => {
-        return a1.title.localeCompare(a2.title);
+        return a1.getTitle().localeCompare(a2.getTitle());
       }, this._nonBuiltInActions, action);
       this._nonBuiltInActions.splice(index, 0, action);
     }
 
     if (this._persistedActions.ids.includes(action.id)) {
       // The action has been seen before.  Override its shownInUrlbar value
       // with the persisted value.  Set the private version of that property
       // so that onActionToggledShownInUrlbar isn't called, which happens when
@@ -242,16 +254,17 @@ this.PageActions = {
         this._persistedActions.idsInUrlbar.splice(nextIndex, 0, action.id);
       }
     } else if (index >= 0) {
       this._persistedActions.idsInUrlbar.splice(index, 1);
     }
     this._storePersistedActions();
   },
 
+  // These keep track of currently registered actions.
   _builtInActions: [],
   _nonBuiltInActions: [],
   _actionsByID: new Map(),
 
   /**
    * Returns the ID of the action before which the given action should be
    * inserted in the urlbar.
    *
@@ -317,77 +330,35 @@ this.PageActions = {
   /**
    * Call this when an action is removed.
    *
    * @param  action (Action object, required)
    *         The action that was removed.
    */
   onActionRemoved(action) {
     if (!this.actionForID(action.id)) {
-      // The action isn't present.  Not an error.
+      // The action isn't registered (yet).  Not an error.
       return;
     }
 
     this._actionsByID.delete(action.id);
     for (let list of [this._nonBuiltInActions, this._builtInActions]) {
       let index = list.findIndex(a => a.id == action.id);
       if (index >= 0) {
         list.splice(index, 1);
         break;
       }
     }
 
-    // Remove the action from persisted storage.
-    for (let name of ["ids", "idsInUrlbar"]) {
-      let array = this._persistedActions[name];
-      let index = array.indexOf(action.id);
-      if (index >= 0) {
-        array.splice(index, 1);
-      }
-    }
-    this._storePersistedActions();
-
     for (let bpa of allBrowserPageActions()) {
       bpa.removeAction(action);
     }
   },
 
   /**
-   * Call this when an action's iconURL changes.
-   *
-   * @param  action (Action object, required)
-   *         The action whose iconURL property changed.
-   */
-  onActionSetIconURL(action) {
-    if (!this.actionForID(action.id)) {
-      // This may be called before the action has been added.
-      return;
-    }
-    for (let bpa of allBrowserPageActions()) {
-      bpa.updateActionIconURL(action);
-    }
-  },
-
-  /**
-   * Call this when an action's title changes.
-   *
-   * @param  action (Action object, required)
-   *         The action whose title property changed.
-   */
-  onActionSetTitle(action) {
-    if (!this.actionForID(action.id)) {
-      // This may be called before the action has been added.
-      return;
-    }
-    for (let bpa of allBrowserPageActions()) {
-      bpa.updateActionTitle(action);
-    }
-  },
-
-  /**
    * Call this when an action's shownInUrlbar property changes.
    *
    * @param  action (Action object, required)
    *         The action whose shownInUrlbar property changed.
    */
   onActionToggledShownInUrlbar(action) {
     if (!this.actionForID(action.id)) {
       // This may be called before the action has been added.
@@ -427,16 +398,27 @@ this.PageActions = {
 
   _loadPersistedActions() {
     try {
       let json = Services.prefs.getStringPref(PREF_PERSISTED_ACTIONS);
       this._persistedActions = this._migratePersistedActions(JSON.parse(json));
     } catch (ex) {}
   },
 
+  _purgeUnregisteredPersistedActions() {
+    // Remove all action IDs from persisted state that do not correspond to
+    // currently registered actions.
+    for (let name of ["ids", "idsInUrlbar"]) {
+      this._persistedActions[name] = this._persistedActions[name].filter(id => {
+        return this.actionForID(id);
+      });
+    }
+    this._storePersistedActions();
+  },
+
   _migratePersistedActions(actions) {
     // Start with actions.version and migrate one version at a time, all the way
     // up to the current version.
     for (let version = actions.version || 0;
          version < PERSISTED_ACTIONS_CURRENT_VERSION;
          version++) {
       let methodName = `_migratePersistedActionsTo${version + 1}`;
       actions = this[methodName](actions);
@@ -460,115 +442,129 @@ this.PageActions = {
       actions.idsInUrlbar.push(ACTION_ID_BOOKMARK);
     }
     return {
       ids,
       idsInUrlbar: actions.idsInUrlbar,
     };
   },
 
+  // This keeps track of all actions, even those that are not currently
+  // registered because they have been removed, so long as
+  // _purgeUnregisteredPersistedActions has not been called.
   _persistedActions: {
     version: PERSISTED_ACTIONS_CURRENT_VERSION,
     // action IDs that have ever been seen and not removed, order not important
     ids: [],
     // action IDs ordered by position in urlbar
     idsInUrlbar: [],
   },
 };
 
 /**
  * A single page action.
  *
- * @param  options (object, required)
- *         An object with the following properties:
- *         @param id (string, required)
- *                The action's ID.  Treat this like the ID of a DOM node.
- *         @param title (string, required)
- *                The action's title.
- *         @param anchorIDOverride (string, optional)
- *                Pass a string for this property if to override which element
- *                that the temporary panel is anchored to.
- *         @param iconURL (string, optional)
- *                The URL of the action's icon.  Usually you want to specify an
- *                icon in CSS, but this option is useful if that would be a pain
- *                for some reason -- like your code is in an embedded
- *                WebExtension.
- *         @param nodeAttributes (object, optional)
- *                An object of name-value pairs.  Each pair will be added as
- *                an attribute to DOM nodes created for this action.
- *         @param onBeforePlacedInWindow (function, optional)
- *                Called before the action is placed in the window:
- *                onBeforePlacedInWindow(window)
- *                * window: The window that the action will be placed in.
- *         @param onCommand (function, optional)
- *                Called when the action is clicked, but only if it has neither
- *                a subview nor an iframe:
- *                onCommand(event, buttonNode)
- *                * event: The triggering event.
- *                * buttonNode: The button node that was clicked.
- *         @param onIframeHiding (function, optional)
- *                Called when the action's iframe is hiding:
- *                onIframeHiding(iframeNode, parentPanelNode)
- *                * iframeNode: The iframe.
- *                * parentPanelNode: The panel node in which the iframe is
- *                  shown.
- *         @param onIframeHidden (function, optional)
- *                Called when the action's iframe is hidden:
- *                onIframeHidden(iframeNode, parentPanelNode)
- *                * iframeNode: The iframe.
- *                * parentPanelNode: The panel node in which the iframe is
- *                  shown.
- *         @param onIframeShown (function, optional)
- *                Called when the action's iframe is shown to the user:
- *                onIframeShown(iframeNode, parentPanelNode)
- *                * iframeNode: The iframe.
- *                * parentPanelNode: The panel node in which the iframe is
- *                  shown.
- *         @param onLocationChange (function, optional)
- *                Called after tab switch or when the current <browser>'s
- *                location changes:
- *                onLocationChange(browserWindow)
- *                * browserWindow: The browser window containing the tab switch
- *                  or changed <browser>.
- *         @param onPlacedInPanel (function, optional)
- *                Called when the action is added to the page action panel in
- *                a browser window:
- *                onPlacedInPanel(buttonNode)
- *                * buttonNode: The action's node in the page action panel.
- *         @param onPlacedInUrlbar (function, optional)
- *                Called when the action is added to the urlbar in a browser
- *                window:
- *                onPlacedInUrlbar(buttonNode)
- *                * buttonNode: The action's node in the urlbar.
- *         @param onShowingInPanel (function, optional)
- *                Called when a browser window's page action panel is showing:
- *                onShowingInPanel(buttonNode)
- *                * buttonNode: The action's node in the page action panel.
- *         @param shownInUrlbar (bool, optional)
- *                Pass true to show the action in the urlbar, false otherwise.
- *                False by default.
- *         @param subview (object, optional)
- *                An options object suitable for passing to the Subview
- *                constructor, if you'd like the action to have a subview.  See
- *                the subview constructor for info on this object's properties.
- *         @param tooltip (string, optional)
- *                The action's button tooltip text.
- *         @param urlbarIDOverride (string, optional)
- *                Usually the ID of the action's button in the urlbar will be
- *                generated automatically.  Pass a string for this property to
- *                override that with your own ID.
- *         @param wantsIframe (bool, optional)
- *                Pass true to make an action that shows an iframe in a panel
- *                when clicked.
+ * Each action can have both per-browser-window state and global state.
+ * Per-window state takes precedence over global state.  This is reflected in
+ * the title, tooltip, disabled, and icon properties.  Each of these properties
+ * has a getter method and setter method that takes a browser window.  Pass null
+ * to get the action's global state.  Pass a browser window to get the per-
+ * window state.  However, if you pass a window and the action has no state for
+ * that window, then the global state will be returned.
+ *
+ * `options` is a required object with the following properties.  Regarding the
+ * properties discussed in the previous paragraph, the values in `options` set
+ * global state.
+ *
+ * @param id (string, required)
+ *        The action's ID.  Treat this like the ID of a DOM node.
+ * @param title (string, required)
+ *        The action's title.
+ * @param anchorIDOverride (string, optional)
+ *        Pass a string to override the node to which the action's activated-
+ *        action panel is anchored.
+ * @param disabled (bool, optional)
+ *        Pass true to cause the action to be disabled initially in all browser
+ *        windows.  False by default.
+ * @param iconURL (string or object, optional)
+ *        The URL string of the action's icon.  Usually you want to specify an
+ *        icon in CSS, but this option is useful if that would be a pain for
+ *        some reason.  You can also pass an object that maps pixel sizes to
+ *        URLs, like { 16: url16, 32: url32 }.  The best size for the user's
+ *        screen will be used.
+ * @param nodeAttributes (object, optional)
+ *        An object of name-value pairs.  Each pair will be added as an
+ *        attribute to DOM nodes created for this action.
+ * @param onBeforePlacedInWindow (function, optional)
+ *        Called before the action is placed in the window:
+ *        onBeforePlacedInWindow(window)
+ *        * window: The window that the action will be placed in.
+ * @param onCommand (function, optional)
+ *        Called when the action is clicked, but only if it has neither a
+ *        subview nor an iframe:
+ *        onCommand(event, buttonNode)
+ *        * event: The triggering event.
+ *        * buttonNode: The button node that was clicked.
+ * @param onIframeHiding (function, optional)
+ *        Called when the action's iframe is hiding:
+ *        onIframeHiding(iframeNode, parentPanelNode)
+ *        * iframeNode: The iframe.
+ *        * parentPanelNode: The panel node in which the iframe is shown.
+ * @param onIframeHidden (function, optional)
+ *        Called when the action's iframe is hidden:
+ *        onIframeHidden(iframeNode, parentPanelNode)
+ *        * iframeNode: The iframe.
+ *        * parentPanelNode: The panel node in which the iframe is shown.
+ * @param onIframeShown (function, optional)
+ *        Called when the action's iframe is shown to the user:
+ *        onIframeShown(iframeNode, parentPanelNode)
+ *        * iframeNode: The iframe.
+ *        * parentPanelNode: The panel node in which the iframe is shown.
+ * @param onLocationChange (function, optional)
+ *        Called after tab switch or when the current <browser>'s location
+ *        changes:
+ *        onLocationChange(browserWindow)
+ *        * browserWindow: The browser window containing the tab switch or
+ *          changed <browser>.
+ * @param onPlacedInPanel (function, optional)
+ *        Called when the action is added to the page action panel in a browser
+ *        window:
+ *        onPlacedInPanel(buttonNode)
+ *        * buttonNode: The action's node in the page action panel.
+ * @param onPlacedInUrlbar (function, optional)
+ *        Called when the action is added to the urlbar in a browser window:
+ *        onPlacedInUrlbar(buttonNode)
+ *        * buttonNode: The action's node in the urlbar.
+ * @param onShowingInPanel (function, optional)
+ *        Called when a browser window's page action panel is showing:
+ *        onShowingInPanel(buttonNode)
+ *        * buttonNode: The action's node in the page action panel.
+ * @param shownInUrlbar (bool, optional)
+ *        Pass true to show the action in the urlbar, false otherwise.  False by
+ *        default.
+ * @param subview (object, optional)
+ *        An options object suitable for passing to the Subview constructor, if
+ *        you'd like the action to have a subview.  See the subview constructor
+ *        for info on this object's properties.
+ * @param tooltip (string, optional)
+ *        The action's button tooltip text.
+ * @param urlbarIDOverride (string, optional)
+ *        Usually the ID of the action's button in the urlbar will be generated
+ *        automatically.  Pass a string for this property to override that with
+ *        your own ID.
+ * @param wantsIframe (bool, optional)
+ *        Pass true to make an action that shows an iframe in a panel when
+ *        clicked.
  */
 function Action(options) {
   setProperties(this, options, {
     id: true,
     title: !options._isSeparator,
     anchorIDOverride: false,
+    disabled: false,
     iconURL: false,
     labelForHistogram: false,
     nodeAttributes: false,
     onBeforePlacedInWindow: false,
     onCommand: false,
     onIframeHiding: false,
     onIframeHidden: false,
     onIframeShown: false,
@@ -604,28 +600,16 @@ function Action(options) {
   });
   if (this._subview) {
     this._subview = new Subview(options.subview);
   }
 }
 
 Action.prototype = {
   /**
-   * The action's icon URL (string, nullable)
-   */
-  get iconURL() {
-    return this._iconURL;
-  },
-  set iconURL(url) {
-    this._iconURL = url;
-    PageActions.onActionSetIconURL(this);
-    return this._iconURL;
-  },
-
-  /**
    * The action's ID (string, nonnull)
    */
   get id() {
     return this._id;
   },
 
   /**
    * Attribute name => value mapping to set on nodes created for this action
@@ -645,36 +629,123 @@ Action.prototype = {
     if (this.shownInUrlbar != shown) {
       this._shownInUrlbar = shown;
       PageActions.onActionToggledShownInUrlbar(this);
     }
     return this.shownInUrlbar;
   },
 
   /**
+   * The action's disabled state (bool, nonnull)
+   */
+  getDisabled(browserWindow = null) {
+    return !!this._getProperty("disabled", browserWindow);
+  },
+  setDisabled(value, browserWindow = null) {
+    return this._setProperty("disabled", !!value, browserWindow);
+  },
+
+  /**
+   * The action's icon URL string, or an object mapping sizes to URL strings
+   * (string or object, nullable)
+   */
+  getIconURL(browserWindow = null) {
+    return this._getProperty("iconURL", browserWindow);
+  },
+  setIconURL(value, browserWindow = null) {
+    return this._setProperty("iconURL", value, browserWindow);
+  },
+
+  /**
    * The action's title (string, nonnull)
    */
-  get title() {
-    return this._title;
+  getTitle(browserWindow = null) {
+    return this._getProperty("title", browserWindow);
   },
-  set title(title) {
-    this._title = title || "";
-    PageActions.onActionSetTitle(this);
-    return this._title;
+  setTitle(value, browserWindow = null) {
+    return this._setProperty("title", value, browserWindow);
   },
 
   /**
    * The action's tooltip (string, nullable)
    */
-  get tooltip() {
-    return this._tooltip;
+  getTooltip(browserWindow = null) {
+    return this._getProperty("tooltip", browserWindow);
+  },
+  setTooltip(value, browserWindow = null) {
+    return this._setProperty("tooltip", value, browserWindow);
   },
 
   /**
-   * Override for the ID of the action's temporary panel anchor (string, nullable)
+   * Sets a property, optionally for a particular browser window.
+   *
+   * @param  name (string, required)
+   *         The (non-underscored) name of the property.
+   * @param  value
+   *         The value.
+   * @param  browserWindow (DOM window, optional)
+   *         If given, then the property will be set in this window's state, not
+   *         globally.
+   */
+  _setProperty(name, value, browserWindow) {
+    if (!browserWindow) {
+      // Set the global state.
+      this[`_${name}`] = value;
+    } else {
+      // Set the per-window state.
+      let props = this._propertiesByBrowserWindow.get(browserWindow);
+      if (!props) {
+        props = {};
+        this._propertiesByBrowserWindow.set(browserWindow, props);
+      }
+      props[name] = value;
+    }
+    // This may be called before the action has been added.
+    if (PageActions.actionForID(this.id)) {
+      for (let bpa of allBrowserPageActions(browserWindow)) {
+        bpa.updateAction(this, name);
+      }
+    }
+    return value;
+  },
+
+  /**
+   * Gets a property, optionally for a particular browser window.
+   *
+   * @param  name (string, required)
+   *         The (non-underscored) name of the property.
+   * @param  browserWindow (DOM window, optional)
+   *         If given, then the property will be fetched from this window's
+   *         state.  If the property does not exist in the window's state, or if
+   *         no window is given, then the global value is returned.
+   * @return The property value.
+   */
+  _getProperty(name, browserWindow) {
+    if (browserWindow) {
+      // Try the per-window state.
+      let props = this._propertiesByBrowserWindow.get(browserWindow);
+      if (props && name in props) {
+        return props[name];
+      }
+    }
+    // Fall back to the global state.
+    return this[`_${name}`];
+  },
+
+  // maps browser windows => object with properties for that window
+  get _propertiesByBrowserWindow() {
+    if (!this.__propertiesByBrowserWindow) {
+      this.__propertiesByBrowserWindow = new WeakMap();
+    }
+    return this.__propertiesByBrowserWindow;
+  },
+
+  /**
+   * Override for the ID of the action's activated-action panel anchor (string,
+   * nullable)
    */
   get anchorIDOverride() {
     return this._anchorIDOverride;
   },
 
   /**
    * Override for the ID of the action's urlbar node (string, nullable)
    */
@@ -696,16 +767,53 @@ Action.prototype = {
     return this._subview;
   },
 
   get labelForHistogram() {
     return this._labelForHistogram || this._id;
   },
 
   /**
+   * Returns the URL of the best icon to use given a preferred size.  The best
+   * icon is the one with the smallest size that's equal to or bigger than the
+   * preferred size.  Returns null if the action has no icon URL.
+   *
+   * @param  peferredSize (number, required)
+   *         The icon size you prefer.
+   * @return The URL of the best icon, or null.
+   */
+  iconURLForSize(preferredSize, browserWindow) {
+    let iconURL = this.getIconURL(browserWindow);
+    if (!iconURL) {
+      return null;
+    }
+    if (typeof(iconURL) == "string") {
+      return iconURL;
+    }
+    if (typeof(iconURL) == "object") {
+      // This case is copied from ExtensionParent.jsm so that our image logic is
+      // the same, so that WebExtensions page action tests that deal with icons
+      // pass.
+      let bestSize = null;
+      if (iconURL[preferredSize]) {
+        bestSize = preferredSize;
+      } else if (iconURL[2 * preferredSize]) {
+        bestSize = 2 * preferredSize;
+      } else {
+        let sizes = Object.keys(iconURL)
+                          .map(key => parseInt(key, 10))
+                          .sort((a, b) => a - b);
+        bestSize = sizes.find(candidate => candidate > preferredSize) || sizes.pop();
+      }
+      return iconURL[bestSize];
+    }
+    return null;
+  },
+
+  /**
    * Performs the command for an action.  If the action has an onCommand
    * handler, then it's called.  If the action has a subview or iframe, then a
    * panel is opened, displaying the subview or iframe.
    *
    * @param  browserWindow (DOM window, required)
    *         The browser window in which to perform the action.
    */
   doCommand(browserWindow) {
@@ -824,52 +932,49 @@ Action.prototype = {
    */
   onShowingInPanel(buttonNode) {
     if (this._onShowingInPanel) {
       this._onShowingInPanel(buttonNode);
     }
   },
 
   /**
-   * Makes PageActions forget about this action and removes its DOM nodes from
-   * all browser windows.  Call this when the user removes your action, like
-   * when your extension is uninstalled.  You probably don't want to call it
-   * simply when your extension is disabled or the app quits, because then
-   * PageActions won't remember it the next time your extension is enabled or
-   * the app starts.
+   * Removes the action's DOM nodes from all browser windows.
+   *
+   * PageActions will remember the action's urlbar placement, if any, after this
+   * method is called until app shutdown.  If the action is not added again
+   * before shutdown, then PageActions will discard the placement, and the next
+   * time the action is added, its placement will be reset.
    */
   remove() {
     PageActions.onActionRemoved(this);
   }
 };
 
 this.PageActions.Action = Action;
 
 
 /**
  * A Subview represents a PanelUI panelview that your actions can show.
+ * `options` is a required object with the following properties.
  *
- * @param  options (object, required)
- *         An object with the following properties:
- *         @param buttons (array, optional)
- *                An array of buttons to show in the subview.  Each item in the
- *                array must be an options object suitable for passing to the
- *                Button constructor.  See the Button constructor for
- *                information on these objects' properties.
- *         @param onPlaced (function, optional)
- *                Called when the subview is added to its parent panel in a
- *                browser window:
- *                onPlaced(panelViewNode)
- *                * panelViewNode: The panelview node represented by this
- *                  Subview.
- *         @param onShowing (function, optional)
- *                Called when the subview is showing in a browser window:
- *                onShowing(panelViewNode)
- *                * panelViewNode: The panelview node represented by this
- *                  Subview.
+ * @param buttons (array, optional)
+ *        An array of buttons to show in the subview.  Each item in the array
+ *        must be an options object suitable for passing to the Button
+ *        constructor.  See the Button constructor for information on these
+ *        objects' properties.
+ * @param onPlaced (function, optional)
+ *        Called when the subview is added to its parent panel in a browser
+ *        window:
+ *        onPlaced(panelViewNode)
+ *        * panelViewNode: The panelview node represented by this Subview.
+ * @param onShowing (function, optional)
+ *        Called when the subview is showing in a browser window:
+ *        onShowing(panelViewNode)
+ *        * panelViewNode: The panelview node represented by this Subview.
  */
 function Subview(options) {
   setProperties(this, options, {
     buttons: false,
     onPlaced: false,
     onShowing: false,
   });
   this._buttons = (this._buttons || []).map(buttonOptions => {
@@ -909,36 +1014,34 @@ Subview.prototype = {
     }
   }
 };
 
 this.PageActions.Subview = Subview;
 
 
 /**
- * A button that can be shown in a subview.
+ * A button that can be shown in a subview.  `options` is a required object with
+ * the following properties.
  *
- * @param  options (object, required)
- *         An object with the following properties:
- *         @param id (string, required)
- *                The button's ID.  This will not become the ID of a DOM node by
- *                itself, but it will be used to generate DOM node IDs.  But in
- *                terms of spaces and weird characters and such, do treat this
- *                like a DOM node ID.
- *         @param title (string, required)
- *                The button's title.
- *         @param disabled (bool, required)
- *                Pass true to disable the button.
- *         @param onCommand (function, optional)
- *                Called when the button is clicked:
- *                onCommand(event, buttonNode)
- *                * event: The triggering event.
- *                * buttonNode: The node that was clicked.
- *         @param shortcut (string, optional)
- *                The button's shortcut text.
+ * @param id (string, required)
+ *        The button's ID.  This will not become the ID of a DOM node by itself,
+ *        but it will be used to generate DOM node IDs.  But in terms of spaces
+ *        and weird characters and such, do treat this like a DOM node ID.
+ * @param title (string, required)
+ *        The button's title.
+ * @param disabled (bool, required)
+ *        Pass true to disable the button.
+ * @param onCommand (function, optional)
+ *        Called when the button is clicked:
+ *        onCommand(event, buttonNode)
+ *        * event: The triggering event.
+ *        * buttonNode: The node that was clicked.
+ * @param shortcut (string, optional)
+ *        The button's shortcut text.
  */
 function Button(options) {
   setProperties(this, options, {
     id: true,
     title: true,
     disabled: false,
     onCommand: false,
     shortcut: false,
@@ -1009,16 +1112,18 @@ this.PageActions.ACTION_ID_BUILT_IN_SEPA
 // new actions.
 var gBuiltInActions = [
 
   // bookmark
   {
     id: ACTION_ID_BOOKMARK,
     urlbarIDOverride: "star-button-box",
     _urlbarNodeInMarkup: true,
+    // The title is set in browser-pageActions.js by calling
+    // BookmarkingUI.updateBookmarkPageMenuItem().
     title: "",
     shownInUrlbar: true,
     nodeAttributes: {
       observes: "bookmarkThisPageBroadcaster",
     },
     onShowingInPanel(buttonNode) {
       browserPageActions(buttonNode).bookmark.onShowingInPanel(buttonNode);
     },
@@ -1100,26 +1205,43 @@ function browserPageActions(obj) {
   if (obj.BrowserPageActions) {
     return obj.BrowserPageActions;
   }
   return obj.ownerGlobal.BrowserPageActions;
 }
 
 /**
  * A generator function for all open browser windows.
+ *
+ * @param browserWindow (DOM window, optional)
+ *        If given, then only this window will be yielded.  That may sound
+ *        pointless, but it can make callers nicer to write since they don't
+ *        need two separate cases, one where a window is given and another where
+ *        it isn't.
  */
-function* allBrowserWindows() {
+function* allBrowserWindows(browserWindow = null) {
+  if (browserWindow) {
+    yield browserWindow;
+    return;
+  }
   let windows = Services.wm.getEnumerator("navigator:browser");
   while (windows.hasMoreElements()) {
     yield windows.getNext();
   }
 }
 
-function* allBrowserPageActions() {
-  for (let win of allBrowserWindows()) {
+/**
+ * A generator function for BrowserPageActions objects in all open windows.
+ *
+ * @param browserWindow (DOM window, optional)
+ *        If given, then the BrowserPageActions for only this window will be
+ *        yielded.
+ */
+function* allBrowserPageActions(browserWindow = null) {
+  for (let win of allBrowserWindows(browserWindow)) {
     yield browserPageActions(win);
   }
 }
 
 /**
  * A simple function that sets properties on a given object while doing basic
  * required-properties checking.  If a required property isn't specified in the
  * given options object, or if the options object has properties that aren't in
--- a/browser/modules/test/browser/browser_PageActions.js
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -35,18 +35,18 @@ add_task(async function simple() {
   let tooltip = "Test simple tooltip";
 
   let onCommandCallCount = 0;
   let onPlacedInPanelCallCount = 0;
   let onPlacedInUrlbarCallCount = 0;
   let onShowingInPanelCallCount = 0;
   let onCommandExpectedButtonID;
 
-  let panelButtonID = BrowserPageActions._panelButtonNodeIDForActionID(id);
-  let urlbarButtonID = BrowserPageActions._urlbarButtonNodeIDForActionID(id);
+  let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+  let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
 
   let initialActions = PageActions.actions;
 
   let action = PageActions.addAction(new PageActions.Action({
     iconURL,
     id,
     nodeAttributes,
     title,
@@ -69,23 +69,23 @@ add_task(async function simple() {
     },
     onShowingInPanel(buttonNode) {
       onShowingInPanelCallCount++;
       Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
       Assert.equal(buttonNode.id, panelButtonID, "buttonNode.id");
     },
   }));
 
-  Assert.equal(action.iconURL, iconURL, "iconURL");
+  Assert.equal(action.getIconURL(), iconURL, "iconURL");
   Assert.equal(action.id, id, "id");
   Assert.deepEqual(action.nodeAttributes, nodeAttributes, "nodeAttributes");
   Assert.equal(action.shownInUrlbar, false, "shownInUrlbar");
   Assert.equal(action.subview, null, "subview");
-  Assert.equal(action.title, title, "title");
-  Assert.equal(action.tooltip, tooltip, "tooltip");
+  Assert.equal(action.getTitle(), title, "title");
+  Assert.equal(action.getTooltip(), tooltip, "tooltip");
   Assert.equal(action.urlbarIDOverride, null, "urlbarIDOverride");
   Assert.equal(action.wantsIframe, false, "wantsIframe");
 
   Assert.ok(!("__insertBeforeActionID" in action), "__insertBeforeActionID");
   Assert.ok(!("__isSeparator" in action), "__isSeparator");
   Assert.ok(!("__urlbarNodeInMarkup" in action), "__urlbarNodeInMarkup");
 
   Assert.equal(onPlacedInPanelCallCount, 1,
@@ -110,32 +110,33 @@ add_task(async function simple() {
                    "actionForID should be action");
 
   Assert.ok(PageActions._persistedActions.ids.includes(action.id),
             "PageActions should record action in its list of seen actions");
 
   // The action's panel button should have been created.
   let panelButtonNode = document.getElementById(panelButtonID);
   Assert.notEqual(panelButtonNode, null, "panelButtonNode");
-  Assert.equal(panelButtonNode.getAttribute("label"), action.title, "label");
+  Assert.equal(panelButtonNode.getAttribute("label"), action.getTitle(),
+               "label");
   for (let name in action.nodeAttributes) {
     Assert.ok(panelButtonNode.hasAttribute(name), "Has attribute: " + name);
     Assert.equal(panelButtonNode.getAttribute(name),
                  action.nodeAttributes[name],
                  "Equal attribute: " + name);
   }
 
   // The panel button should be the last node in the panel, and its previous
   // sibling should be the separator between the built-in actions and non-built-
   // in actions.
   Assert.equal(panelButtonNode.nextSibling, null, "nextSibling");
   Assert.notEqual(panelButtonNode.previousSibling, null, "previousSibling");
   Assert.equal(
     panelButtonNode.previousSibling.id,
-    BrowserPageActions._panelButtonNodeIDForActionID(
+    BrowserPageActions.panelButtonNodeIDForActionID(
       PageActions.ACTION_ID_BUILT_IN_SEPARATOR
     ),
     "previousSibling.id"
   );
 
   // The action's urlbar button should not have been created.
   let urlbarButtonNode = document.getElementById(urlbarButtonID);
   Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
@@ -173,19 +174,20 @@ add_task(async function simple() {
 
   // Click the urlbar button.
   onCommandExpectedButtonID = urlbarButtonID;
   EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
   Assert.equal(onCommandCallCount, 2, "onCommandCallCount should be inc'ed");
 
   // Set a new title.
   let newTitle = title + " new title";
-  action.title = newTitle;
-  Assert.equal(action.title, newTitle, "New title");
-  Assert.equal(panelButtonNode.getAttribute("label"), action.title, "New label");
+  action.setTitle(newTitle);
+  Assert.equal(action.getTitle(), newTitle, "New title");
+  Assert.equal(panelButtonNode.getAttribute("label"), action.getTitle(),
+               "New label");
 
   // Now that shownInUrlbar has been toggled, make sure that it sticks across
   // app restarts.  Simulate that by "unregistering" the action (not by removing
   // it, which is more permanent) and then registering it again.
 
   // unregister
   PageActions._actionsByID.delete(action.id);
   let index = PageActions._nonBuiltInActions.findIndex(a => a.id == action.id);
@@ -207,51 +209,54 @@ add_task(async function simple() {
 
   // Remove the action.
   action.remove();
   panelButtonNode = document.getElementById(panelButtonID);
   Assert.equal(panelButtonNode, null, "panelButtonNode");
   urlbarButtonNode = document.getElementById(urlbarButtonID);
   Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
 
-  Assert.deepEqual(PageActions.actions, initialActions,
-                   "Actions should go back to initial");
-  Assert.equal(PageActions.actionForID(action.id), null,
-               "actionForID should be null");
-
-  Assert.ok(!PageActions._persistedActions.ids.includes(action.id),
-            "PageActions should remove action from its list of seen actions");
-
   // The separator between the built-in actions and non-built-in actions should
   // be gone now, too.
   let separatorNode = document.getElementById(
-    BrowserPageActions._panelButtonNodeIDForActionID(
+    BrowserPageActions.panelButtonNodeIDForActionID(
       PageActions.ACTION_ID_BUILT_IN_SEPARATOR
     )
   );
   Assert.equal(separatorNode, null, "No separator");
   Assert.ok(!BrowserPageActions.mainViewBodyNode
             .lastChild.localName.includes("separator"),
             "Last child should not be separator");
+
+  Assert.deepEqual(PageActions.actions, initialActions,
+                   "Actions should go back to initial");
+  Assert.equal(PageActions.actionForID(action.id), null,
+               "actionForID should be null");
+
+  Assert.ok(PageActions._persistedActions.ids.includes(action.id),
+            "Action ID should remain in cache until purged");
+  PageActions._purgeUnregisteredPersistedActions();
+  Assert.ok(!PageActions._persistedActions.ids.includes(action.id),
+            "Action ID should be removed from cache after being purged");
 });
 
 
 // Tests a non-built-in action with a subview.
 add_task(async function withSubview() {
   let id = "test-subview";
 
   let onActionCommandCallCount = 0;
   let onActionPlacedInPanelCallCount = 0;
   let onActionPlacedInUrlbarCallCount = 0;
   let onSubviewPlacedCount = 0;
   let onSubviewShowingCount = 0;
   let onButtonCommandCallCount = 0;
 
-  let panelButtonID = BrowserPageActions._panelButtonNodeIDForActionID(id);
-  let urlbarButtonID = BrowserPageActions._urlbarButtonNodeIDForActionID(id);
+  let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+  let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
 
   let panelViewIDPanel =
     BrowserPageActions._panelViewNodeIDForActionID(id, false);
   let panelViewIDUrlbar =
     BrowserPageActions._panelViewNodeIDForActionID(id, true);
 
   let onSubviewPlacedExpectedPanelViewID = panelViewIDPanel;
   let onSubviewShowingExpectedPanelViewID;
@@ -428,18 +433,18 @@ add_task(async function withSubview() {
 add_task(async function withIframe() {
   let id = "test-iframe";
 
   let onCommandCallCount = 0;
   let onPlacedInPanelCallCount = 0;
   let onPlacedInUrlbarCallCount = 0;
   let onIframeShownCount = 0;
 
-  let panelButtonID = BrowserPageActions._panelButtonNodeIDForActionID(id);
-  let urlbarButtonID = BrowserPageActions._urlbarButtonNodeIDForActionID(id);
+  let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+  let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
 
   let action = PageActions.addAction(new PageActions.Action({
     iconURL: "chrome://browser/skin/mail.svg",
     id,
     shownInUrlbar: true,
     title: "Test iframe",
     wantsIframe: true,
     onCommand(event, buttonNode) {
@@ -552,17 +557,17 @@ add_task(async function withIframe() {
   urlbarButtonNode = document.getElementById(urlbarButtonID);
   Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
 });
 
 
 // Tests an action with the _insertBeforeActionID option set.
 add_task(async function insertBeforeActionID() {
   let id = "test-insertBeforeActionID";
-  let panelButtonID = BrowserPageActions._panelButtonNodeIDForActionID(id);
+  let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
 
   let initialActions = PageActions.actions;
   let initialBuiltInActions = PageActions.builtInActions;
   let initialNonBuiltInActions = PageActions.nonBuiltInActions;
   let initialBookmarkSeparatorIndex = PageActions.actions.findIndex(a => {
     return a.id == PageActions.ACTION_ID_BOOKMARK_SEPARATOR;
   });
 
@@ -601,27 +606,27 @@ add_task(async function insertBeforeActi
   let panelButtonNode = document.getElementById(panelButtonID);
   Assert.notEqual(panelButtonNode, null, "panelButtonNode");
 
   // The button's next sibling should be the bookmark separator.
   Assert.notEqual(panelButtonNode.nextSibling, null,
                   "panelButtonNode.nextSibling");
   Assert.equal(
     panelButtonNode.nextSibling.id,
-    BrowserPageActions._panelButtonNodeIDForActionID(
+    BrowserPageActions.panelButtonNodeIDForActionID(
       PageActions.ACTION_ID_BOOKMARK_SEPARATOR
     ),
     "panelButtonNode.nextSibling.id"
   );
 
   // The separator between the built-in and non-built-in actions should not have
   // been created.
   Assert.equal(
     document.getElementById(
-      BrowserPageActions._panelButtonNodeIDForActionID(
+      BrowserPageActions.panelButtonNodeIDForActionID(
         PageActions.ACTION_ID_BUILT_IN_SEPARATOR
       )
     ),
     null,
     "Separator should be gone"
   );
 
   action.remove();
@@ -664,48 +669,48 @@ add_task(async function multipleNonBuilt
     let actualAction = PageActions.nonBuiltInActions[i];
     Assert.equal(actualAction.id, idPrefix + expectedIndex,
                  "actualAction.id for index: " + i);
   }
 
   // Check the button nodes in the panel.
   let expectedIndex = 1;
   let buttonNode = document.getElementById(
-    BrowserPageActions._panelButtonNodeIDForActionID(idPrefix + expectedIndex)
+    BrowserPageActions.panelButtonNodeIDForActionID(idPrefix + expectedIndex)
   );
   Assert.notEqual(buttonNode, null, "buttonNode");
   Assert.notEqual(buttonNode.previousSibling, null,
                   "buttonNode.previousSibling");
   Assert.equal(
     buttonNode.previousSibling.id,
-    BrowserPageActions._panelButtonNodeIDForActionID(
+    BrowserPageActions.panelButtonNodeIDForActionID(
       PageActions.ACTION_ID_BUILT_IN_SEPARATOR
     ),
     "buttonNode.previousSibling.id"
   );
   for (let i = 0; i < actions.length; i++) {
     Assert.notEqual(buttonNode, null, "buttonNode at index: " + i);
     Assert.equal(
       buttonNode.id,
-      BrowserPageActions._panelButtonNodeIDForActionID(idPrefix + expectedIndex),
+      BrowserPageActions.panelButtonNodeIDForActionID(idPrefix + expectedIndex),
       "buttonNode.id at index: " + i
     );
     buttonNode = buttonNode.nextSibling;
     expectedIndex++;
   }
   Assert.equal(buttonNode, null, "Nothing should come after the last button");
 
   for (let action of actions) {
     action.remove();
   }
 
   // The separator between the built-in and non-built-in actions should be gone.
   Assert.equal(
     document.getElementById(
-      BrowserPageActions._panelButtonNodeIDForActionID(
+      BrowserPageActions.panelButtonNodeIDForActionID(
         PageActions.ACTION_ID_BUILT_IN_SEPARATOR
       )
     ),
     null,
     "Separator should be gone"
   );
 });
 
@@ -745,17 +750,17 @@ add_task(async function nonBuiltFirst() 
   Assert.deepEqual(PageActions.builtInActions.map(a => a.id), [],
                    "PageActions.builtInActions should be empty");
   Assert.deepEqual(PageActions.nonBuiltInActions.map(a => a.id), [action.id],
                    "Action should be in PageActions.nonBuiltInActions");
 
   // Check the panel.
   Assert.deepEqual(
     Array.map(BrowserPageActions.mainViewBodyNode.childNodes, n => n.id),
-    [BrowserPageActions._panelButtonNodeIDForActionID(action.id)],
+    [BrowserPageActions.panelButtonNodeIDForActionID(action.id)],
     "Action should be in panel"
   );
 
   // Now add back all the actions.
   for (let a of initialActions) {
     PageActions.addAction(a);
   }
 
@@ -780,17 +785,17 @@ add_task(async function nonBuiltFirst() 
   );
 
   // Check the panel.
   Assert.deepEqual(
     Array.map(BrowserPageActions.mainViewBodyNode.childNodes, n => n.id),
     initialActions.map(a => a.id).concat(
       [PageActions.ACTION_ID_BUILT_IN_SEPARATOR],
       [action.id]
-    ).map(id => BrowserPageActions._panelButtonNodeIDForActionID(id)),
+    ).map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
     "Panel should contain all actions"
   );
 
   // Remove the test action.
   action.remove();
 
   // Check the actions.
   Assert.deepEqual(
@@ -807,17 +812,17 @@ add_task(async function nonBuiltFirst() 
     PageActions.nonBuiltInActions.map(a => a.id),
     [],
     "Action should no longer be in PageActions.nonBuiltInActions"
   );
 
   // Check the panel.
   Assert.deepEqual(
     Array.map(BrowserPageActions.mainViewBodyNode.childNodes, n => n.id),
-    initialActions.map(a => BrowserPageActions._panelButtonNodeIDForActionID(a.id)),
+    initialActions.map(a => BrowserPageActions.panelButtonNodeIDForActionID(a.id)),
     "Action should no longer be in panel"
   );
 });
 
 
 // Makes sure that urlbar nodes appear in the correct order in a new window.
 add_task(async function urlbarOrderNewWindow() {
   // Make some new actions.
@@ -865,31 +870,37 @@ add_task(async function urlbarOrderNewWi
 
   // Make sure that worked.
   Assert.deepEqual(
     ids.slice(0, actions.length),
     actions.map(a => a.id),
     "PageActions._persistedActions.idsInUrlbar now has new actions at front"
   );
 
+  // _persistedActions will contain the IDs of test actions added and removed
+  // above (unless PageActions._purgeUnregisteredPersistedActions() was called
+  // for all of them, which it wasn't).  Filter them out because they should
+  // not appear in the new window (or any window at this point).
+  ids = ids.filter(id => PageActions.actionForID(id));
+
   // Open the new window.
   let win = await BrowserTestUtils.openNewBrowserWindow();
 
   // Collect its urlbar nodes.
   let actualUrlbarNodeIDs = [];
   for (let node = win.BrowserPageActions.mainButtonNode.nextSibling;
        node;
        node = node.nextSibling) {
     actualUrlbarNodeIDs.push(node.id);
   }
 
   // Now check that they're in the right order.
   Assert.deepEqual(
     actualUrlbarNodeIDs,
-    ids.map(id => win.BrowserPageActions._urlbarButtonNodeIDForActionID(id)),
+    ids.map(id => win.BrowserPageActions.urlbarButtonNodeIDForActionID(id)),
     "Expected actions in new window's urlbar"
   );
 
   // Done, clean up.
   await BrowserTestUtils.closeWindow(win);
   for (let action of actions) {
     action.remove();
   }
@@ -959,26 +970,195 @@ add_task(async function migrate1() {
        node;
        node = node.nextSibling) {
     actualUrlbarNodeIDs.push(node.id);
   }
 
   // Now check that they're in the right order.
   Assert.deepEqual(
     actualUrlbarNodeIDs,
-    orderedIDs.map(id => win.BrowserPageActions._urlbarButtonNodeIDForActionID(id)),
+    orderedIDs.map(id => win.BrowserPageActions.urlbarButtonNodeIDForActionID(id)),
     "Expected actions in new window's urlbar"
   );
 
   // Done, clean up.
   await BrowserTestUtils.closeWindow(win);
   Services.prefs.clearUserPref(PageActions.PREF_PERSISTED_ACTIONS);
-  PageActions.actionForID("copyURL")._shownInUrlbar = false;
+  PageActions.actionForID("copyURL").shownInUrlbar = false;
+});
+
+
+// Opens a new browser window and makes sure per-window state works right.
+add_task(async function perWindowState() {
+  // Add a test action.
+  let title = "Test perWindowState";
+  let action = PageActions.addAction(new PageActions.Action({
+    iconURL: "chrome://browser/skin/mail.svg",
+    id: "test-perWindowState",
+    shownInUrlbar: true,
+    title,
+  }));
+
+  // Open a new browser window and load an actionable page so that the action
+  // shows up in it.
+  let newWindow = await BrowserTestUtils.openNewBrowserWindow();
+  await BrowserTestUtils.openNewForegroundTab({
+    gBrowser: newWindow.gBrowser,
+    url: "http://example.com/",
+  });
+
+  // Set a new title globally.
+  let newGlobalTitle = title + " new title";
+  action.setTitle(newGlobalTitle);
+  Assert.equal(action.getTitle(), newGlobalTitle,
+               "Title: global");
+  Assert.equal(action.getTitle(window), newGlobalTitle,
+               "Title: old window");
+  Assert.equal(action.getTitle(newWindow), newGlobalTitle,
+               "Title: new window");
+
+  // The action's panel button nodes should be updated in both windows.
+  let panelButtonID =
+    BrowserPageActions.panelButtonNodeIDForActionID(action.id);
+  for (let win of [window, newWindow]) {
+    let panelButtonNode = win.document.getElementById(panelButtonID);
+    Assert.equal(panelButtonNode.getAttribute("label"), newGlobalTitle,
+                 "Panel button label should be global title");
+  }
+
+  // Set a new title in the new window.
+  let newPerWinTitle = title + " new title in new window";
+  action.setTitle(newPerWinTitle, newWindow);
+  Assert.equal(action.getTitle(), newGlobalTitle,
+               "Title: global should remain same");
+  Assert.equal(action.getTitle(window), newGlobalTitle,
+               "Title: old window should remain same");
+  Assert.equal(action.getTitle(newWindow), newPerWinTitle,
+               "Title: new window should be new");
+
+  // The action's panel button node should be updated in the new window but the
+  // same in the old window.
+  let panelButtonNode1 = document.getElementById(panelButtonID);
+  Assert.equal(panelButtonNode1.getAttribute("label"), newGlobalTitle,
+               "Panel button label in old window");
+  let panelButtonNode2 = newWindow.document.getElementById(panelButtonID);
+  Assert.equal(panelButtonNode2.getAttribute("label"), newPerWinTitle,
+               "Panel button label in new window");
+
+  // Done, clean up.
+  await BrowserTestUtils.closeWindow(newWindow);
+  action.remove();
 });
 
+
+// Adds an action, changes its placement in the urlbar to something non-default,
+// removes the action, and then adds it back.  Since the action was removed and
+// re-added without restarting the app (or more accurately without calling
+// PageActions._purgeUnregisteredPersistedActions), the action should remain in
+// persisted state and retain its last placement in the urlbar.
+add_task(async function removeRetainState() {
+  // Get the list of actions initially in the urlbar.
+  let initialActionsInUrlbar = PageActions.actionsInUrlbar;
+  Assert.ok(initialActionsInUrlbar.length > 0,
+            "This test expects there to be at least one action in the urlbar initially (like the bookmark star)");
+
+  // Add a test action.
+  let id = "test-removeRetainState";
+  let testAction = PageActions.addAction(new PageActions.Action({
+    id,
+    title: "Test removeRetainState",
+  }));
+
+  // Show its button in the urlbar.
+  testAction.shownInUrlbar = true;
+
+  // "Move" the test action to the front of the urlbar by toggling shownInUrlbar
+  // for all the other actions in the urlbar.
+  for (let action of initialActionsInUrlbar) {
+    action.shownInUrlbar = false;
+    action.shownInUrlbar = true;
+  }
+
+  // Check the actions in PageActions.actionsInUrlbar.
+  Assert.deepEqual(
+    PageActions.actionsInUrlbar.map(a => a.id),
+    [testAction].concat(initialActionsInUrlbar).map(a => a.id),
+    "PageActions.actionsInUrlbar should be in expected order: testAction followed by all initial actions"
+  );
+
+  // Check the nodes in the urlbar.
+  let actualUrlbarNodeIDs = [];
+  for (let node = BrowserPageActions.mainButtonNode.nextSibling;
+       node;
+       node = node.nextSibling) {
+    actualUrlbarNodeIDs.push(node.id);
+  }
+  Assert.deepEqual(
+    actualUrlbarNodeIDs,
+    [testAction].concat(initialActionsInUrlbar).map(a => BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)),
+    "urlbar nodes should be in expected order: testAction followed by all initial actions"
+  );
+
+  // Remove the test action.
+  testAction.remove();
+
+  // Check the actions in PageActions.actionsInUrlbar.
+  Assert.deepEqual(
+    PageActions.actionsInUrlbar.map(a => a.id),
+    initialActionsInUrlbar.map(a => a.id),
+    "PageActions.actionsInUrlbar should be in expected order after removing test action: all initial actions"
+  );
+
+  // Check the nodes in the urlbar.
+  actualUrlbarNodeIDs = [];
+  for (let node = BrowserPageActions.mainButtonNode.nextSibling;
+       node;
+       node = node.nextSibling) {
+    actualUrlbarNodeIDs.push(node.id);
+  }
+  Assert.deepEqual(
+    actualUrlbarNodeIDs,
+    initialActionsInUrlbar.map(a => BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)),
+    "urlbar nodes should be in expected order after removing test action: all initial actions"
+  );
+
+  // Add the test action again.
+  testAction = PageActions.addAction(new PageActions.Action({
+    id,
+    title: "Test removeRetainState",
+  }));
+
+  // Show its button in the urlbar again.
+  testAction.shownInUrlbar = true;
+
+  // Check the actions in PageActions.actionsInUrlbar.
+  Assert.deepEqual(
+    PageActions.actionsInUrlbar.map(a => a.id),
+    [testAction].concat(initialActionsInUrlbar).map(a => a.id),
+    "PageActions.actionsInUrlbar should be in expected order after re-adding test action: testAction followed by all initial actions"
+  );
+
+  // Check the nodes in the urlbar.
+  actualUrlbarNodeIDs = [];
+  for (let node = BrowserPageActions.mainButtonNode.nextSibling;
+       node;
+       node = node.nextSibling) {
+    actualUrlbarNodeIDs.push(node.id);
+  }
+  Assert.deepEqual(
+    actualUrlbarNodeIDs,
+    [testAction].concat(initialActionsInUrlbar).map(a => BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)),
+    "urlbar nodes should be in expected order after re-adding test action: testAction followed by all initial actions"
+  );
+
+  // Done, clean up.
+  testAction.remove();
+});
+
+
 function promisePageActionPanelOpen() {
   let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIDOMWindowUtils);
   return BrowserTestUtils.waitForCondition(() => {
     // Wait for the main page action button to become visible.  It's hidden for
     // some URIs, so depending on when this is called, it may not yet be quite
     // visible.  It's up to the caller to make sure it will be visible.
     info("Waiting for main page action button to have non-0 size");
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -191,16 +191,20 @@
   height: 28px;
   padding: var(--urlbar-icon-padding);
   -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
   fill-opacity: 0.6;
   color: inherit;
 }
 
+.urlbar-page-action[disabled] {
+  fill-opacity: 0.3;
+}
+
 :root[uidensity=compact] .urlbar-icon {
   width: 24px;
   height: 24px;
 }
 
 :root[uidensity=touch] .urlbar-icon {
   width: 30px;
   height: 30px;
--- a/build.gradle
+++ b/build.gradle
@@ -1,10 +1,8 @@
-import java.util.regex.Pattern
-
 def tryInt = { string ->
     if (string == null) {
         return string
     }
     if (string.isInteger()) {
         return string as Integer
     }
     return string
@@ -50,59 +48,51 @@ buildscript {
         // For in tree plugins.
         maven {
             url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
         }
     }
 
     dependencies {
         classpath 'com.android.tools.build:gradle:2.3.3'
-        classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.4') {
-            // Without these, we get errors linting.
-            exclude module: 'guava'
-        }
         // Provided in tree.
         classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.3'
     }
 }
 
-task generateCodeAndResources(type:Exec) {
-    workingDir "${topobjdir}"
-
-    commandLine mozconfig.substs.GMAKE
-    args '-C'
-    args "${topobjdir}/mobile/android/base"
-    args 'gradle-targets'
+if ('multi' == System.env.AB_CD) {
+    // Multi-l10n builds set `AB_CD=multi`, which isn't a valid locale.  This
+    // causes the
+    //
+    // |mach build| > |mach gradle| > |make gradle-targets| > AndroidManifest.xml > strings.xml > multi/brand.dtd
+    //
+    // dependency chain to fail, since multi isn't a real locale.  To avoid
+    // this, if Gradle is invoked with AB_CD=multi, we don't invoke Make at all.
+    task generateCodeAndResources()
+} else {
+    task generateCodeAndResources(type:Exec) {
+        workingDir "${topobjdir}"
 
-    // Only show the output if something went wrong.
-    ignoreExitValue = true
-    standardOutput = new ByteArrayOutputStream()
-    errorOutput = standardOutput
-    doLast {
-        if (execResult.exitValue != 0) {
-            throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
+        commandLine mozconfig.substs.GMAKE
+        args '-C'
+        args "${topobjdir}/mobile/android/base"
+        args 'gradle-targets'
+
+        // Only show the output if something went wrong.
+        ignoreExitValue = true
+        standardOutput = new ByteArrayOutputStream()
+        errorOutput = standardOutput
+        doLast {
+            if (execResult.exitValue != 0) {
+                throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
+            }
         }
     }
 }
 
-// Skip unit test for all build variants, unless if it was specifically requested by user.
-// The enabled property for the unit test tasks is reset based on the command line task names just before the task execution.
-// I bet there is a easier/cleaner way to do this, but this gets the job done for now.
-Pattern pattern = Pattern.compile('.*test(.+UnitTest)?.*')
-boolean startTasksIncludeTest = gradle.startParameter.taskNames.any {
-    taskName ->
-        taskName.matches(pattern)
-}
-gradle.taskGraph.beforeTask {
-    Task task ->
-        if (task.name.matches(pattern)) {
-            task.enabled = startTasksIncludeTest
-        }
-}
-
 afterEvaluate {
     subprojects {
         if (!hasProperty('android')) {
             return
         }
         android.applicationVariants.all {
             preBuild.dependsOn rootProject.generateCodeAndResources
         }
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -83,17 +83,16 @@ add_old_configure_assignment(
     'DIST', check_build_environment.dist)
 
 option(env='MOZ_AUTOMATION', help='Enable options for automated builds')
 set_config('MOZ_AUTOMATION', depends_if('MOZ_AUTOMATION')(lambda x: True))
 
 
 option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
 
-option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project')
 option(env='MOZCONFIG', nargs=1, help='Mozconfig location')
 
 option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
        help='External directory containing additional build files')
 
 
 @depends('--with-external-source-dir')
 def external_source_dir(value):
@@ -106,21 +105,21 @@ add_old_configure_assignment('EXTERNAL_S
 
 # Read user mozconfig
 # ==============================================================
 # Note: the dependency on --help is only there to always read the mozconfig,
 # even when --help is passed. Without this dependency, the function wouldn't
 # be called when --help is passed, and the mozconfig wouldn't be read.
 
 
-@depends('MOZ_CURRENT_PROJECT', 'MOZCONFIG', 'OLD_CONFIGURE',
+@depends('MOZCONFIG', 'OLD_CONFIGURE',
          check_build_environment, '--with-external-source-dir',
          '--help')
 @imports(_from='mozbuild.mozconfig', _import='MozconfigLoader')
-def mozconfig(current_project, mozconfig, old_configure, build_env,
+def mozconfig(mozconfig, old_configure, build_env,
               external_source_dir, help):
     if not old_configure:
         die('The OLD_CONFIGURE environment variable must be set')
 
     # Don't read the mozconfig for the js configure (yay backwards
     # compatibility)
     # While the long term goal is that js and top-level use the same configure
     # and the same overall setup, including the possibility to use mozconfigs,
@@ -138,20 +137,19 @@ def mozconfig(current_project, mozconfig
     # old-configure dies.
     if os.path.dirname(os.path.abspath(old_configure[0])).endswith('/js/src'):
         return {'path': None}
 
     topsrcdir = build_env.topsrcdir
     if external_source_dir:
         topsrcdir = external_source_dir[0]
     loader = MozconfigLoader(topsrcdir)
-    current_project = current_project[0] if current_project else None
     mozconfig = mozconfig[0] if mozconfig else None
     mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig})
-    mozconfig = loader.read_mozconfig(mozconfig, moz_build_app=current_project)
+    mozconfig = loader.read_mozconfig(mozconfig)
 
     return mozconfig
 
 
 set_config('MOZCONFIG', depends(mozconfig)(lambda m: m['path']))
 
 
 option(env='PYTHON', nargs=1, help='Python interpreter')
--- a/build/sccache.mk
+++ b/build/sccache.mk
@@ -1,19 +1,12 @@
 # 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/.
 
-ifdef OBJDIR
-BASE_DIR = $(OBJDIR)
-else
-# OSX Universal builds only do upload in the first MOZ_BUILD_PROJECTS
-BASE_DIR = $(MOZ_OBJDIR)/$(firstword $(MOZ_BUILD_PROJECTS))
-endif
-
 preflight_all:
 	# Terminate any sccache server that might still be around
 	-$(TOPSRCDIR)/sccache2/sccache --stop-server > /dev/null 2>&1
 	# Start a new server, ensuring it gets the jobserver file descriptors
 	# from make (but don't use the + prefix when make -n is used, so that
 	# the command doesn't run in that case)
 	$(if $(findstring n,$(filter-out --%, $(MAKEFLAGS))),,+)env RUST_LOG=sccache::compiler=debug SCCACHE_ERROR_LOG=$(OBJDIR)/dist/sccache.log $(TOPSRCDIR)/sccache2/sccache --start-server
 
--- a/client.mk
+++ b/client.mk
@@ -17,26 +17,20 @@
 #    build
 #    clean (realclean is now the same as clean)
 #    distclean
 #
 # See http://developer.mozilla.org/en/docs/Build_Documentation for 
 # more information.
 #
 # Options:
-#   MOZ_BUILD_PROJECTS   - Build multiple projects in subdirectories
-#                          of MOZ_OBJDIR
 #   MOZ_OBJDIR           - Destination object directory
 #   MOZ_MAKE_FLAGS       - Flags to pass to $(MAKE)
-#   MOZ_PREFLIGHT_ALL  } - Makefiles to run before any project in
-#   MOZ_PREFLIGHT      }   MOZ_BUILD_PROJECTS, before each project, after
-#   MOZ_POSTFLIGHT     }   each project, and after all projects; these
-#   MOZ_POSTFLIGHT_ALL }   variables contain space-separated lists
-#   MOZ_UNIFY_BDATE      - Set to use the same bdate for each project in
-#                          MOZ_BUILD_PROJECTS
+#   MOZ_PREFLIGHT_ALL    - Makefiles to run before building.
+#   MOZ_POSTFLIGHT_ALL   - Makefiles to run after building.
 #
 #######################################################################
 # Defines
 
 comma := ,
 
 ifdef MACH
 ifndef NO_BUILDSTATUS_MESSAGES
@@ -104,18 +98,17 @@ define CR
 endef
 
 # As $(shell) doesn't preserve newlines, use sed to replace them with an
 # unlikely sequence (||), which is then replaced back to newlines by make
 # before evaluation. $(shell) replacing newlines with spaces, || is always
 # followed by a space (since sed doesn't remove newlines), except on the
 # last line, so replace both '|| ' and '||'.
 # Also, make MOZ_PGO available to mozconfig when passed on make command line.
-# Likewise for MOZ_CURRENT_PROJECT.
-MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell $(addprefix MOZ_CURRENT_PROJECT=,$(MOZ_CURRENT_PROJECT)) MOZ_PGO=$(MOZ_PGO) $(TOPSRCDIR)/mach environment --format=client.mk | sed 's/$$/||/')))
+MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell MOZ_PGO=$(MOZ_PGO) $(TOPSRCDIR)/mach environment --format=client.mk | sed 's/$$/||/')))
 $(eval $(MOZCONFIG_CONTENT))
 
 export FOUND_MOZCONFIG
 
 # As '||' was used as a newline separator, it means it's not occurring in
 # lines themselves. It can thus safely be used to replaces normal spaces,
 # to then replace newlines with normal spaces. This allows to get a list
 # of mozconfig output lines.
@@ -143,26 +136,16 @@ ifeq (,$(findstring -j,$(MOZ_MAKE_FLAGS)
 endif
 
 ifdef MOZ_AUTOMATION
 ifeq (4.0,$(firstword $(sort 4.0 $(MAKE_VERSION))))
 MOZ_MAKE_FLAGS += --output-sync=line
 endif
 endif
 
-ifdef MOZ_BUILD_PROJECTS
-
-ifdef MOZ_CURRENT_PROJECT
-  BUILD_PROJECT_ARG = MOZ_BUILD_APP=$(MOZ_CURRENT_PROJECT)
-  export MOZ_CURRENT_PROJECT
-else
-  MOZ_MAKE = $(error Cannot build in the OBJDIR when MOZ_CURRENT_PROJECT is not set.)
-endif
-endif # MOZ_BUILD_PROJECTS
-
 MOZ_MAKE = $(MAKE) $(MOZ_MAKE_FLAGS) -C $(OBJDIR)
 
 # 'configure' scripts generated by autoconf.
 CONFIGURES := $(TOPSRCDIR)/configure
 CONFIGURES += $(TOPSRCDIR)/js/src/configure
 
 # Make targets that are going to be passed to the real build system
 OBJDIR_TARGETS = install export libs clean realclean distclean maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check automation/build
@@ -176,43 +159,26 @@ build::
 
 # Include baseconfig.mk for its $(MAKE) validation.
 include $(TOPSRCDIR)/config/baseconfig.mk
 
 # Define mkdir
 include $(TOPSRCDIR)/config/makefiles/makeutils.mk
 include $(TOPSRCDIR)/config/makefiles/autotargets.mk
 
-# Create a makefile containing the mk_add_options values from mozconfig,
-# but only do so when OBJDIR is defined (see further above).
-ifdef MOZ_BUILD_PROJECTS
-ifdef MOZ_CURRENT_PROJECT
-WANT_MOZCONFIG_MK = 1
-else
-WANT_MOZCONFIG_MK =
-endif
-else
-WANT_MOZCONFIG_MK = 1
-endif
-
-ifdef WANT_MOZCONFIG_MK
 # For now, only output "export" lines and lines containing UPLOAD_EXTRA_FILES
 # from mach environment --format=client.mk output.
 MOZCONFIG_MK_LINES := $(filter export||% UPLOAD_EXTRA_FILES% %UPLOAD_EXTRA_FILES%,$(MOZCONFIG_OUT_LINES))
 $(OBJDIR)/.mozconfig.mk: $(TOPSRCDIR)/client.mk $(FOUND_MOZCONFIG) $(call mkdir_deps,$(OBJDIR)) $(OBJDIR)/CLOBBER
 	$(if $(MOZCONFIG_MK_LINES),( $(foreach line,$(MOZCONFIG_MK_LINES), echo '$(subst ||, ,$(line))';) )) > $@
-ifdef MOZ_CURRENT_PROJECT
-	echo export MOZ_CURRENT_PROJECT=$(MOZ_CURRENT_PROJECT) >> $@
-endif
 
 # Include that makefile so that it is created. This should not actually change
 # the environment since MOZCONFIG_CONTENT, which MOZCONFIG_OUT_LINES derives
 # from, has already been eval'ed.
 include $(OBJDIR)/.mozconfig.mk
-endif
 
 # Print out any options loaded from mozconfig.
 all realbuild clean distclean export libs install realclean::
 ifneq (,$(strip $(MOZCONFIG_OUT_FILTERED)))
 	$(info Adding client.mk options from $(FOUND_MOZCONFIG):)
 	$(foreach line,$(MOZCONFIG_OUT_FILTERED),$(info $(NULL) $(NULL) $(NULL) $(NULL) $(subst ||, ,$(line))))
 endif
 
@@ -223,19 +189,18 @@ clobber clobber_all: clean
 # helper target for mobile
 build_and_deploy: build package install
 
 # Do everything from scratch
 everything: clean build
 
 ####################################
 # Profile-Guided Optimization
-#  This is up here, outside of the MOZ_CURRENT_PROJECT logic so that this
-#  is usable in multi-pass builds, where you might not have a runnable
-#  application until all the build passes and postflight scripts have run.
+#  This is up here so that this is usable in multi-pass builds, where you
+# might not have a runnable application until all the build passes have run.
 profiledbuild::
 	$(call BUILDSTATUS,TIERS pgo_profile_generate pgo_package pgo_profile pgo_clobber pgo_profile_use)
 	$(call BUILDSTATUS,TIER_START pgo_profile_generate)
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1 MOZ_PGO_INSTRUMENTED=1 CREATE_MOZCONFIG_JSON=
 	$(call BUILDSTATUS,TIER_FINISH pgo_profile_generate)
 	$(call BUILDSTATUS,TIER_START pgo_package)
 	$(MAKE) -C $(OBJDIR) package MOZ_PGO_INSTRUMENTED=1 MOZ_INTERNAL_SIGNING_FORMAT= MOZ_EXTERNAL_SIGNING_FORMAT=
 	rm -f $(OBJDIR)/jarlog/en-US.log
@@ -246,64 +211,25 @@ profiledbuild::
 	$(call BUILDSTATUS,TIER_START pgo_clobber)
 	$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild CREATE_MOZCONFIG_JSON=
 	$(call BUILDSTATUS,TIER_FINISH pgo_clobber)
 	$(call BUILDSTATUS,TIER_START pgo_profile_use)
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1 CREATE_MOZCONFIG_JSON=
 	$(call BUILDSTATUS,TIER_FINISH pgo_profile_use)
 
 #####################################################
-# Build date unification
-
-ifdef MOZ_UNIFY_BDATE
-ifndef MOZ_BUILD_DATE
-ifdef MOZ_BUILD_PROJECTS
-MOZ_BUILD_DATE = $(shell $(PYTHON) $(TOPSRCDIR)/build/variables.py buildid_header | awk '{print $$3}')
-export MOZ_BUILD_DATE
-endif
-endif
-endif
-
-#####################################################
 # Preflight, before building any project
 
+ifdef MOZ_PREFLIGHT_ALL
 realbuild preflight_all::
-ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_PREFLIGHT_ALL),,1))
-# Don't run preflight_all for individual projects in multi-project builds
-# (when MOZ_CURRENT_PROJECT is set.)
-ifndef MOZ_BUILD_PROJECTS
-# Building a single project, OBJDIR is usable.
 	set -e; \
 	for mkfile in $(MOZ_PREFLIGHT_ALL); do \
 	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight_all TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
 	done
-else
-# OBJDIR refers to the project-specific OBJDIR, which is not available at
-# this point when building multiple projects.  Only MOZ_OBJDIR is available.
-	set -e; \
-	for mkfile in $(MOZ_PREFLIGHT_ALL); do \
-	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight_all TOPSRCDIR=$(TOPSRCDIR) MOZ_OBJDIR=$(MOZ_OBJDIR) MOZ_BUILD_PROJECTS='$(MOZ_BUILD_PROJECTS)'; \
-	done
 endif
-endif
-
-# If we're building multiple projects, but haven't specified which project,
-# loop through them.
-
-ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_BUILD_PROJECTS),,1))
-configure realbuild preflight postflight $(OBJDIR_TARGETS)::
-	set -e; \
-	for app in $(MOZ_BUILD_PROJECTS); do \
-	  $(MAKE) -f $(TOPSRCDIR)/client.mk $@ MOZ_CURRENT_PROJECT=$$app; \
-	done
-
-else
-
-# MOZ_CURRENT_PROJECT: either doing a single-project build, or building an
-# individual project in a multi-project build.
 
 ####################################
 # Configure
 
 MAKEFILE      = $(wildcard $(OBJDIR)/Makefile)
 CONFIG_STATUS = $(wildcard $(OBJDIR)/config.status)
 CONFIG_CACHE  = $(wildcard $(OBJDIR)/config.cache)
 
@@ -356,17 +282,16 @@ endif
 	    $(TOPSRCDIR)/python/mozbuild/mozbuild/controller/clobber.py $(TOPSRCDIR) $(OBJDIR)
 
 configure-files: $(CONFIGURES)
 
 configure-preqs = \
   $(OBJDIR)/CLOBBER \
   configure-files \
   $(call mkdir_deps,$(OBJDIR)) \
-  $(if $(MOZ_BUILD_PROJECTS),$(call mkdir_deps,$(MOZ_OBJDIR))) \
   save-mozconfig \
   $(OBJDIR)/.mozconfig.json \
   $(NULL)
 
 CREATE_MOZCONFIG_JSON = $(shell $(TOPSRCDIR)/mach environment --format=json -o $(OBJDIR)/.mozconfig.json)
 # Force CREATE_MOZCONFIG_JSON above to be resolved, without side effects in
 # case the result is non empty, and allowing an override on the make command
 # line not running the command (using := $(shell) still runs the shell command).
@@ -400,84 +325,43 @@ else
 endif
 	@$(MAKE) -f $(TOPSRCDIR)/client.mk configure CREATE_MOZCONFIG_JSON=
 
 ifneq (,$(CONFIG_STATUS))
 $(OBJDIR)/config/autoconf.mk: $(TOPSRCDIR)/config/autoconf.mk.in
 	$(PYTHON) $(OBJDIR)/config.status -n --file=$(OBJDIR)/config/autoconf.mk
 endif
 
-
-####################################
-# Preflight
-
-realbuild preflight::
-ifdef MOZ_PREFLIGHT
-	set -e; \
-	for mkfile in $(MOZ_PREFLIGHT); do \
-	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
-	done
-endif
-
 ####################################
 # Build it
 
 realbuild::  $(OBJDIR)/Makefile $(OBJDIR)/config.status
 	+$(MOZ_MAKE)
 
 ####################################
 # Other targets
 
 # Pass these target onto the real build system
 $(OBJDIR_TARGETS):: $(OBJDIR)/Makefile $(OBJDIR)/config.status
 	+$(MOZ_MAKE) $@
 
 ####################################
-# Postflight
-
-realbuild postflight::
-ifdef MOZ_POSTFLIGHT
-	set -e; \
-	for mkfile in $(MOZ_POSTFLIGHT); do \
-	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
-	done
-endif
-
-endif # MOZ_CURRENT_PROJECT
-
-####################################
 # Postflight, after building all projects
 
 ifdef MOZ_AUTOMATION
-ifndef MOZ_CURRENT_PROJECT
 $(if $(MOZ_PGO),profiledbuild,realbuild)::
-# Only run the automation/build target for the first project.
-# (i.e. first platform of universal builds)
-	$(MAKE) -f $(TOPSRCDIR)/client.mk automation/build $(addprefix MOZ_CURRENT_PROJECT=,$(firstword $(MOZ_BUILD_PROJECTS)))
-endif
+	$(MAKE) -f $(TOPSRCDIR)/client.mk automation/build
 endif
 
+ifdef MOZ_POSTFLIGHT_ALL
 realbuild postflight_all::
-ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_POSTFLIGHT_ALL),,1))
-# Don't run postflight_all for individual projects in multi-project builds
-# (when MOZ_CURRENT_PROJECT is set.)
-ifndef MOZ_BUILD_PROJECTS
-# Building a single project, OBJDIR is usable.
 	set -e; \
 	for mkfile in $(MOZ_POSTFLIGHT_ALL); do \
 	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight_all TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
 	done
-else
-# OBJDIR refers to the project-specific OBJDIR, which is not available at
-# this point when building multiple projects.  Only MOZ_OBJDIR is available.
-	set -e; \
-	for mkfile in $(MOZ_POSTFLIGHT_ALL); do \
-	  $(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight_all TOPSRCDIR=$(TOPSRCDIR) MOZ_OBJDIR=$(MOZ_OBJDIR) MOZ_BUILD_PROJECTS='$(MOZ_BUILD_PROJECTS)'; \
-	done
-endif
 endif
 
 echo-variable-%:
 	@echo $($*)
 
 # This makefile doesn't support parallel execution. It does pass
 # MOZ_MAKE_FLAGS to sub-make processes, so they will correctly execute
 # in parallel.
@@ -491,12 +375,10 @@ echo-variable-%:
     pull_all \
     build_all \
     clobber \
     clobber_all \
     pull_and_build_all \
     everything \
     configure \
     preflight_all \
-    preflight \
-    postflight \
     postflight_all \
     $(OBJDIR_TARGETS)
--- a/config/config.mk
+++ b/config/config.mk
@@ -262,18 +262,18 @@ HOST_CFLAGS	+= $(HOST_OPTIMIZE_FLAGS)
 HOST_CXXFLAGS	+= $(HOST_OPTIMIZE_FLAGS)
 else
 ifdef MOZ_OPTIMIZE
 HOST_CFLAGS	+= $(MOZ_OPTIMIZE_FLAGS)
 HOST_CXXFLAGS	+= $(MOZ_OPTIMIZE_FLAGS)
 endif # MOZ_OPTIMIZE
 endif # CROSS_COMPILE
 
-COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(PGO_CFLAGS) $(MOZBUILD_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
-COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(PGO_CFLAGS) $(MOZBUILD_CXXFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
+COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
+COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
 COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
 COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
 ASFLAGS += $(MOZBUILD_ASFLAGS)
 
 ifndef CROSS_COMPILE
 HOST_CFLAGS += $(RTL_FLAGS)
 endif
 
--- a/devtools/client/webconsole/new-console-output/store.js
+++ b/devtools/client/webconsole/new-console-output/store.js
@@ -25,16 +25,19 @@ const {
 } = require("devtools/client/webconsole/new-console-output/constants");
 const { reducers } = require("./reducers/index");
 const Services = require("Services");
 const {
   getMessage,
   getAllMessagesUiById,
 } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 const DataProvider = require("devtools/client/netmonitor/src/connector/firefox-data-provider");
+const {
+  getAllNetworkMessagesUpdateById,
+} = require("devtools/client/webconsole/new-console-output/selectors/messages");
 
 /**
  * Create and configure store for the Console panel. This is the place
  * where various enhancers and middleware can be registered.
  */
 function configureStore(hud, options = {}) {
   const logLimit = options.logLimit
     || Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1);
@@ -182,16 +185,33 @@ function enableNetProvider(hud) {
       // If network message has been opened, fetch all HTTP details
       // from the backend. It can happen (especially in test) that
       // the message is opened before all network event updates are
       // received. The rest of updates will be handled below, see:
       // NETWORK_MESSAGE_UPDATE action handler.
       if (type == MESSAGE_OPEN) {
         let message = getMessage(state, action.id);
         if (!message.openedOnce && message.source == "network") {
+          let updates = getAllNetworkMessagesUpdateById(newState);
+
+          // If there is no network request update received for this
+          // request-log, it's likely that it comes from cache.
+          // I.e. it's been executed before the console panel started
+          // listening from network events. Let fix that by updating
+          // the reducer now.
+          // Executing the reducer means that the `networkMessagesUpdateById`
+          // is updated (a actor key created). The key is needed for proper
+          // handling NETWORK_UPDATE_REQUEST event (in the same reducer).
+          if (!updates[action.id]) {
+            newState = reducer(newState, {
+              type: NETWORK_MESSAGE_UPDATE,
+              message: message,
+            });
+          }
+
           dataProvider.onNetworkEvent(null, message);
           message.updates.forEach(updateType => {
             dataProvider.onNetworkEventUpdate(null, {
               packet: { updateType: updateType },
               networkInfo: message,
             });
           });
         }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -376,16 +376,17 @@ skip-if = true #	Bug 1404384
 tags = mcb
 skip-if = true #	Bug 1404886
 [browser_webconsole_multiline_input.js]
 skip-if = true # Bug 1408941
 [browser_webconsole_multiple_windows_and_tabs.js]
 skip-if = true # Bug 1408942
 [browser_webconsole_netlogging_reset_filter.js]
 skip-if = true #	Bug 1405636
+[browser_webconsole_network_attach.js]
 [browser_webconsole_network_exceptions.js]
 skip-if = true # Bug 1408943
 [browser_webconsole_network_messages_expand.js]
 [browser_webconsole_network_messages_openinnet.js]
 [browser_webconsole_network_requests_from_chrome.js]
 skip-if = true # Bug 1408944
 [browser_webconsole_nodes_highlight.js]
 [browser_webconsole_nodes_select.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_attach.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_FILE = "test-network-request.html";
+const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/mochitest/";
+const TEST_URI = TEST_PATH + TEST_FILE;
+
+add_task(async function task() {
+  await pushPref("devtools.webconsole.filter.net", false);
+  await pushPref("devtools.webconsole.filter.netxhr", true);
+  await openNewTabAndToolbox(TEST_URI, "netmonitor");
+
+  const currentTab = gBrowser.selectedTab;
+  let target = TargetFactory.forTab(currentTab);
+  let toolbox = gDevTools.getToolbox(target);
+
+  let monitor = toolbox.getCurrentPanel();
+  let netReady = monitor.panelWin.once("NetMonitor:PayloadReady");
+
+  // Fire an XHR POST request.
+  await ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
+    content.wrappedJSObject.testXhrGet();
+  });
+
+  info("XHR executed");
+
+  await netReady;
+
+  info("NetMonitor:PayloadReady received");
+
+  let webconsolePanel = await toolbox.selectTool("webconsole");
+  let { hud } = webconsolePanel;
+
+  let xhrUrl = TEST_PATH + "test-data.json";
+  let messageNode = await waitFor(() => findMessage(hud, xhrUrl));
+  let urlNode = messageNode.querySelector(".url");
+  info("Network message found.");
+
+  let ui = hud.ui;
+  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);
+});
+
+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");
+  ok(headersContent, "Headers content is available");
+}
--- a/devtools/server/event-parsers.js
+++ b/devtools/server/event-parsers.js
@@ -264,17 +264,17 @@ var parsers = [
 
       return handlerDO;
     }
   },
 ];
 
 function reactGetListeners(node, boolOnEventFound) {
   function getProps() {
-    for (let key in node) {
+    for (let key of Object.keys(node)) {
       if (key.startsWith("__reactInternalInstance$")) {
         return node[key]._currentElement.props;
       }
     }
     return null;
   }
 
   node = node.wrappedJSObject || node;
--- a/dom/media/flac/FlacDemuxer.cpp
+++ b/dom/media/flac/FlacDemuxer.cpp
@@ -39,21 +39,19 @@ public:
 
   // Return the index (in samples) from the beginning of the track.
   int64_t Index() const { return mIndex; }
 
   // Parse the current packet and check that it made a valid flac frame header.
   // From https://xiph.org/flac/format.html#frame_header
   // A valid header is one that can be decoded without error and that has a
   // valid CRC.
-  // aPacket must points to a buffer that is at least FLAC_MAX_FRAME_HEADER_SIZE
-  // bytes.
-  bool Parse(const uint8_t* aPacket)
+  bool Parse(const uint8_t* aPacket, size_t aBytes)
   {
-    mp4_demuxer::BitReader br(aPacket, FLAC_MAX_FRAME_HEADER_SIZE * 8);
+    mp4_demuxer::BitReader br(aPacket, aBytes * 8);
 
     // Frame sync code.
     if ((br.ReadBits(15) & 0x7fff) != 0x7ffc) {
       return false;
     }
 
     // Variable block size stream code.
     mVariableBlockSize = br.ReadBit();
@@ -225,37 +223,42 @@ const uint8_t FrameHeader::CRC8Table[256
 class Frame
 {
 public:
 
   // The FLAC signature is made of 14 bits set to 1; however the 15th bit is
   // mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
   // signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
   // so we check for the whole signature.
-  // aData must be pointing to a buffer at least
-  // aLength + FLAC_MAX_FRAME_HEADER_SIZE bytes.
   int64_t FindNext(const uint8_t* aData, const uint32_t aLength)
   {
+    // The non-variable size of a FLAC header is 32 bits followed by variable
+    // size data and a 8 bits CRC.
+    // There's no need to read the last 4 bytes, it can never make a complete
+    // header.
+    if (aLength < 4) {
+      return -1;
+    }
     uint32_t modOffset = aLength % 4;
     uint32_t i, j;
 
     for (i = 0; i < modOffset; i++) {
       if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
-        if (mHeader.Parse(aData + i)) {
+        if (mHeader.Parse(aData + i, aLength - i)) {
           return i;
         }
       }
     }
 
-    for (; i < aLength; i += 4) {
+    for (; i < aLength - 4; i += 4) {
       uint32_t x = BigEndian::readUint32(aData + i);
       if (((x & ~(x + 0x01010101)) & 0x80808080)) {
         for (j = 0; j < 4; j++) {
           if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
-            if (mHeader.Parse(aData + i + j)) {
+            if (mHeader.Parse(aData + i + j, aLength - i - j)) {
               return i + j;
             }
           }
         }
       }
     }
     return -1;
   }
@@ -277,36 +280,38 @@ public:
       uint32_t read = 0;
       buffer.SetLength(BUFFER_SIZE + innerOffset);
       nsresult rv =
         aResource.Read(buffer.Elements() + innerOffset, BUFFER_SIZE, &read);
       if (NS_FAILED(rv)) {
         return false;
       }
 
-      if (read < FLAC_MAX_FRAME_HEADER_SIZE) {
-        // Assume that we can't have a valid frame in such small content, we
-        // must have reached EOS.
-        // So we're done.
-        mEOS = true;
-        return false;
-      }
-
-      const size_t bufSize = read + innerOffset - FLAC_MAX_FRAME_HEADER_SIZE;
+      const size_t bufSize = read + innerOffset;
       int64_t foundOffset =
         FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
 
       if (foundOffset >= 0) {
         SetOffset(aResource, foundOffset + offset);
         return true;
       }
 
+      if (read < BUFFER_SIZE) {
+        // Nothing more to try on as we had reached EOS during the previous
+        // read.
+        mEOS = true;
+        return false;
+      }
+
       // Scan the next block;
-      offset += bufSize;
-      buffer.RemoveElementsAt(0, bufSize);
+      // We rewind a bit to re-try what could have been an incomplete packet.
+      // The maximum size of a FLAC header being FLAC_MAX_FRAME_HEADER_SIZE so
+      // we need to retry just after that amount.
+      offset += bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1);
+      buffer.RemoveElementsAt(0, bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1));
       innerOffset = buffer.Length();
     } while (offset - originalOffset < FLAC_MAX_FRAME_SIZE);
 
     return false;
   }
 
   int64_t Offset() const { return mOffset; }
 
@@ -1041,17 +1046,17 @@ FlacTrackDemuxer::TimeAtEnd()
   mTotalFrameLen = streamLen - mParser->FirstFrame().Offset();
 
   return mParsedFramesDuration;
 }
 
 /* static */ bool
 FlacDemuxer::FlacSniffer(const uint8_t* aData, const uint32_t aLength)
 {
-  if (aLength < FLAC_MAX_FRAME_HEADER_SIZE) {
+  if (aLength < FLAC_MIN_FRAME_SIZE) {
     return false;
   }
 
   flac::Frame frame;
-  return frame.FindNext(aData, aLength - FLAC_MAX_FRAME_HEADER_SIZE) >= 0;
+  return frame.FindNext(aData, aLength) >= 0;
 }
 
 } // namespace mozilla
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -128,68 +128,48 @@ public:
   }
 
   static const unsigned NS_PER_USEC = 1000;
   static const unsigned USEC_PER_SEC = 1000000;
 
   MediaResult IsInitSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsInitSegmentPresent(aData);
-    // XXX: This is overly primitive, needs to collect data as it's appended
-    // to the SB and handle, rather than assuming everything is present in a
-    // single aData segment.
-    // 0x1a45dfa3 // EBML
-    // ...
-    // DocType == "webm"
-    // ...
-    // 0x18538067 // Segment (must be "unknown" size or contain a value large
-                  // enough to include the Segment Information and Tracks
-                  // elements that follow)
-    // 0x1549a966 // -> Segment Info
-    // 0x1654ae6b // -> One or more Tracks
-
-    // 0x1a45dfa3 // EBML
     if (aData->Length() < 4) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-    if ((*aData)[0] == 0x1a && (*aData)[1] == 0x45 && (*aData)[2] == 0xdf &&
-        (*aData)[3] == 0xa3) {
-      return NS_OK;
+
+    WebMBufferedParser parser(0);
+    nsTArray<WebMTimeDataOffset> mapping;
+    ReentrantMonitor dummy("dummy");
+    bool result = parser.Append(aData->Elements(), aData->Length(), mapping,
+                                dummy);
+    if (!result) {
+      return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
     }
-    return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
+    return parser.mInitEndOffset > 0 ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
   MediaResult IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsMediaSegmentPresent(aData);
-    // XXX: This is overly primitive, needs to collect data as it's appended
-    // to the SB and handle, rather than assuming everything is present in a
-    // single aData segment.
-    // 0x1a45dfa3 // EBML
-    // ...
-    // DocType == "webm"
-    // ...
-    // 0x18538067 // Segment (must be "unknown" size)
-    // 0x1549a966 // -> Segment Info
-    // 0x1654ae6b // -> One or more Tracks
-
-    // 0x1f43b675 // Cluster
     if (aData->Length() < 4) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-    if ((*aData)[0] == 0x1f && (*aData)[1] == 0x43 && (*aData)[2] == 0xb6 &&
-        (*aData)[3] == 0x75) {
-      return NS_OK;
+
+    WebMBufferedParser parser(0);
+    nsTArray<WebMTimeDataOffset> mapping;
+    ReentrantMonitor dummy("dummy");
+    parser.AppendMediaSegmentOnly();
+    bool result = parser.Append(aData->Elements(), aData->Length(), mapping,
+                                dummy);
+    if (!result) {
+      return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
     }
-    // 0x1c53bb6b // Cues
-    if ((*aData)[0] == 0x1c && (*aData)[1] == 0x53 && (*aData)[2] == 0xbb &&
-        (*aData)[3] == 0x6b) {
-      return NS_OK;
-    }
-    return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
+    return parser.GetClusterOffset() >= 0 ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
   MediaResult ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                          int64_t& aStart,
                                          int64_t& aEnd) override
   {
     bool initSegment = NS_SUCCEEDED(IsInitSegmentPresent(aData));
 
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -40,17 +40,20 @@ support-files =
   aac51-48000-128000-1.m4s aac51-48000-128000-1.m4s^headers^
   aac51-48000-128000-2.m4s aac51-48000-128000-2.m4s^headers^
   bipbop/bipbop_480_624kbps-videoinit.mp4 bipbop/bipbop_480_624kbps-videoinit.mp4^headers^
   bipbop/bipbop_480_624kbps-video1.m4s bipbop/bipbop_480_624kbps-video1.m4s^headers^
   bipbop/bipbop_480_624kbps-video2.m4s bipbop/bipbop_480_624kbps-video2.m4s^headers^
   flac/IS.mp4 flac/IS.mp4^headers^ flac/00001.m4s flac/00001.m4s^headers^
   flac/00002.m4s flac/00002.m4s^headers^ flac/00003.m4s flac/00003.m4s^headers^
   avc3/init.mp4 avc3/init.mp4^headers^ avc3/segment1.m4s avc3/segment1.m4s^headers^
+  tags_before_cluster.webm
+  tags_before_cluster.webm^header^
 
+[test_AppendPartialInitSegment.html]
 [test_AVC3_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_AudioChange_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_AutoRevocation.html]
 tags = firstpartyisolation
 [test_BufferedSeek.html]
 skip-if = android_version == '22' # bug 1329532 bug 1066090
@@ -150,9 +153,9 @@ skip-if = toolkit == 'android' # Not sup
 [test_WaitingOnMissingData.html]
 skip-if = (toolkit == 'android') #timeout android only bug 1101187
 [test_WaitingOnMissingData_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_WaitingOnMissingDataEnded_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
 [test_WaitingToEndedTransition_mp4.html]
 skip-if = toolkit == 'android' # Not supported on android
-
+[test_WebMTagsBeforeCluster.html]
new file mode 100644
index 0000000000000000000000000000000000000000..cf7d596b0ec7020766c8d21cdc5627d3f146dffc
GIT binary patch
literal 111714
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%0D+_HEO{fI8EcjMdwt&nut|9ees>rB%o~@s}3P
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
F{|AiQ%ntwn
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/tags_before_cluster.webm^header^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/test_AppendPartialInitSegment.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>MSE: split init segment and append them separately </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="mediasource.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+runWithMSE(function (ms, v) {
+  ms.addEventListener("sourceopen", function () {
+    var sb = ms.addSourceBuffer("video/webm");
+
+    fetchWithXHR("seek.webm", async function (arrayBuffer) {
+      // init segment is total 236 bytes.
+      info("- append partial init segment -");
+      sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 100));
+
+      info("- wait for updateend -");
+      await once(sb, "updateend");
+
+      info("- append remaining init segment -");
+      sb.appendBuffer(new Uint8Array(arrayBuffer, 100, 136));
+
+      info("- wait for metadata -");
+      await once(v, "loadedmetadata");
+      is(v.videoWidth, 320, "videoWidth has correct initial value");
+      is(v.videoHeight, 240, "videoHeight has correct initial value");
+
+      info("- wait for updateend -");
+      await once(sb, "updateend");
+      SimpleTest.finish();
+    });
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/test_WebMTagsBeforeCluster.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>MSE: WebM tags element before cluster element</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="mediasource.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+addMSEPrefs(["media.mediasource.webm.enabled", true]);
+
+runWithMSE(function (ms, v) {
+  ms.addEventListener("sourceopen", function () {
+    var sb = ms.addSourceBuffer("video/webm");
+
+    fetchWithXHR("tags_before_cluster.webm", async function (arrayBuffer) {
+      info("- append buffer -");
+      sb.appendBuffer(new Uint8Array(arrayBuffer));
+
+      info("- wait for metadata -");
+      await once(v, "loadedmetadata");
+
+      info("- wait for updateend -");
+      await once(sb, "updateend");
+
+      info("- call end of stream -");
+      ms.endOfStream();
+      await once(ms, "sourceended");
+
+      info("- check buffered range -");
+      is(sb.buffered.length, 1, "buffered range is not empty.");
+
+      info("- video is playing -");
+      v.play();
+      await once(v, "timeupdate");
+      SimpleTest.finish();
+    });
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
@@ -114,118 +114,110 @@ CopyAndPackAudio(AVFrame* aFrame, uint32
         *tmp++ = AudioSampleToFloat(data[channel][frame]);
       }
     }
   }
 
   return audio;
 }
 
-RefPtr<MediaDataDecoder::DecodePromise>
-FFmpegAudioDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
+MediaResult
+FFmpegAudioDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
+                                        uint8_t* aData,
+                                        int aSize,
+                                        bool* aGotFrame,
+                                        DecodedData& aResults)
 {
   AVPacket packet;
   mLib->av_init_packet(&packet);
 
-  packet.data = const_cast<uint8_t*>(aSample->Data());
-  packet.size = aSample->Size();
+  packet.data = const_cast<uint8_t*>(aData);
+  packet.size = aSize;
+
+  if (aGotFrame) {
+    *aGotFrame = false;
+  }
 
   if (!PrepareFrame()) {
-    return DecodePromise::CreateAndReject(
-      MediaResult(
-        NS_ERROR_OUT_OF_MEMORY,
-        RESULT_DETAIL("FFmpeg audio decoder failed to allocate frame")),
-      __func__);
+    return MediaResult(
+      NS_ERROR_OUT_OF_MEMORY,
+      RESULT_DETAIL("FFmpeg audio decoder failed to allocate frame"));
   }
 
   int64_t samplePosition = aSample->mOffset;
   media::TimeUnit pts = aSample->mTime;
 
-  DecodedData results;
   while (packet.size > 0) {
     int decoded;
     int bytesConsumed =
       mLib->avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet);
 
     if (bytesConsumed < 0) {
       NS_WARNING("FFmpeg audio decoder error.");
-      return DecodePromise::CreateAndReject(
-        MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
-                    RESULT_DETAIL("FFmpeg audio error:%d", bytesConsumed)),
-        __func__);
+      return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
+                         RESULT_DETAIL("FFmpeg audio error:%d", bytesConsumed));
     }
 
     if (decoded) {
       if (mFrame->format != AV_SAMPLE_FMT_FLT &&
           mFrame->format != AV_SAMPLE_FMT_FLTP &&
           mFrame->format != AV_SAMPLE_FMT_S16 &&
           mFrame->format != AV_SAMPLE_FMT_S16P &&
           mFrame->format != AV_SAMPLE_FMT_S32 &&
           mFrame->format != AV_SAMPLE_FMT_S32P) {
-        return DecodePromise::CreateAndReject(
-          MediaResult(
-            NS_ERROR_DOM_MEDIA_DECODE_ERR,
-            RESULT_DETAIL(
-              "FFmpeg audio decoder outputs unsupported audio format")),
-          __func__);
+        return MediaResult(
+          NS_ERROR_DOM_MEDIA_DECODE_ERR,
+          RESULT_DETAIL(
+            "FFmpeg audio decoder outputs unsupported audio format"));
       }
       uint32_t numChannels = mCodecContext->channels;
       AudioConfig::ChannelLayout layout(numChannels);
       if (!layout.IsValid()) {
-        return DecodePromise::CreateAndReject(
-          MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                      RESULT_DETAIL("Unsupported channel layout:%u", numChannels)),
-          __func__);
+        return MediaResult(
+          NS_ERROR_DOM_MEDIA_FATAL_ERR,
+          RESULT_DETAIL("Unsupported channel layout:%u", numChannels));
       }
 
       uint32_t samplingRate = mCodecContext->sample_rate;
 
       AlignedAudioBuffer audio =
         CopyAndPackAudio(mFrame, numChannels, mFrame->nb_samples);
       if (!audio) {
-        return DecodePromise::CreateAndReject(
-          MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
+        return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__);
       }
 
       media::TimeUnit duration =
         FramesToTimeUnit(mFrame->nb_samples, samplingRate);
       if (!duration.IsValid()) {
-        return DecodePromise::CreateAndReject(
-          MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
-                      RESULT_DETAIL("Invalid sample duration")),
-          __func__);
+        return MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
+                           RESULT_DETAIL("Invalid sample duration"));
       }
 
       media::TimeUnit newpts = pts + duration;
       if (!newpts.IsValid()) {
-        return DecodePromise::CreateAndReject(
-          MediaResult(
-            NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
-            RESULT_DETAIL("Invalid count of accumulated audio samples")),
-          __func__);
+        return MediaResult(
+          NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
+          RESULT_DETAIL("Invalid count of accumulated audio samples"));
       }
 
-      results.AppendElement(new AudioData(
+      aResults.AppendElement(new AudioData(
         samplePosition, pts, duration,
         mFrame->nb_samples, Move(audio), numChannels, samplingRate));
 
       pts = newpts;
+
+      if (aGotFrame) {
+        *aGotFrame = true;
+      }
     }
     packet.data += bytesConsumed;
     packet.size -= bytesConsumed;
     samplePosition += bytesConsumed;
   }
-  return DecodePromise::CreateAndResolve(Move(results), __func__);
-}
-
-RefPtr<MediaDataDecoder::DecodePromise>
-FFmpegAudioDecoder<LIBAV_VER>::ProcessDrain()
-{
-  ProcessFlush();
-  return DecodePromise::CreateAndResolve(DecodedData(), __func__);
+  return NS_OK;
 }
 
 AVCodecID
 FFmpegAudioDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
 {
   if (aMimeType.EqualsLiteral("audio/mpeg")) {
     return AV_CODEC_ID_MP3;
   } else if (aMimeType.EqualsLiteral("audio/flac")) {
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
@@ -28,15 +28,18 @@ public:
   void InitCodecContext() override;
   static AVCodecID GetCodecId(const nsACString& aMimeType);
   nsCString GetDescriptionName() const override
   {
     return NS_LITERAL_CSTRING("ffmpeg audio decoder");
   }
 
 private:
-  RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample) override;
-  RefPtr<DecodePromise> ProcessDrain() override;
+  MediaResult DoDecode(MediaRawData* aSample,
+                       uint8_t* aData,
+                       int aSize,
+                       bool* aGotFrame,
+                       DecodedData& aResults) override;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegAACDecoder_h__
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -19,28 +19,34 @@ namespace mozilla {
 
 StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
 
 FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FFmpegLibWrapper* aLib,
                                                 TaskQueue* aTaskQueue,
                                                 AVCodecID aCodecID)
   : mLib(aLib)
   , mCodecContext(nullptr)
+  , mCodecParser(nullptr)
   , mFrame(NULL)
   , mExtraData(nullptr)
   , mCodecID(aCodecID)
   , mTaskQueue(aTaskQueue)
+  , mLastInputDts(media::TimeUnit::FromMicroseconds(INT64_MIN))
 {
   MOZ_ASSERT(aLib);
   MOZ_COUNT_CTOR(FFmpegDataDecoder);
 }
 
 FFmpegDataDecoder<LIBAV_VER>::~FFmpegDataDecoder()
 {
   MOZ_COUNT_DTOR(FFmpegDataDecoder);
+  if (mCodecParser) {
+    mLib->av_parser_close(mCodecParser);
+    mCodecParser = nullptr;
+  }
 }
 
 MediaResult
 FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
 {
   FFMPEG_LOG("Initialising FFmpeg decoder.");
 
   AVCodec* codec = FindAVCodec(mLib, mCodecID);
@@ -51,16 +57,23 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecode
 
   StaticMutexAutoLock mon(sMonitor);
 
   if (!(mCodecContext = mLib->avcodec_alloc_context3(codec))) {
     return MediaResult(NS_ERROR_OUT_OF_MEMORY,
                        RESULT_DETAIL("Couldn't init ffmpeg context"));
   }
 
+  if (NeedParser()) {
+    MOZ_ASSERT(mCodecParser == nullptr);
+    mCodecParser = mLib->av_parser_init(mCodecID);
+    if (mCodecParser) {
+      mCodecParser->flags |= ParserFlags();
+    }
+  }
   mCodecContext->opaque = this;
 
   InitCodecContext();
 
   if (mExtraData) {
     mCodecContext->extradata_size = mExtraData->Length();
     // FFmpeg may use SIMD instructions to access the data which reads the
     // data in 32 bytes block. Must ensure we have enough data to read.
@@ -101,37 +114,107 @@ FFmpegDataDecoder<LIBAV_VER>::Shutdown()
 
 RefPtr<MediaDataDecoder::DecodePromise>
 FFmpegDataDecoder<LIBAV_VER>::Decode(MediaRawData* aSample)
 {
   return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
                                     &FFmpegDataDecoder::ProcessDecode, aSample);
 }
 
+RefPtr<MediaDataDecoder::DecodePromise>
+FFmpegDataDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
+{
+  bool gotFrame = false;
+  DecodedData results;
+  MediaResult rv = DoDecode(aSample, &gotFrame, results);
+  if (NS_FAILED(rv)) {
+    return DecodePromise::CreateAndReject(rv, __func__);
+  }
+  return DecodePromise::CreateAndResolve(Move(results), __func__);
+}
+
+MediaResult
+FFmpegDataDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, bool* aGotFrame,
+                                       MediaDataDecoder::DecodedData& aResults)
+{
+  uint8_t* inputData = const_cast<uint8_t*>(aSample->Data());
+  size_t inputSize = aSample->Size();
+
+  mLastInputDts = aSample->mTimecode;
+
+  if (mCodecParser) {
+    if (aGotFrame) {
+      *aGotFrame = false;
+    }
+    do {
+      uint8_t* data = inputData;
+      int size = inputSize;
+      int len = mLib->av_parser_parse2(
+        mCodecParser, mCodecContext, &data, &size, inputData, inputSize,
+        aSample->mTime.ToMicroseconds(), aSample->mTimecode.ToMicroseconds(),
+        aSample->mOffset);
+      if (size_t(len) > inputSize) {
+        return NS_ERROR_DOM_MEDIA_DECODE_ERR;
+      }
+      if (size || !inputSize) {
+        bool gotFrame = false;
+        MediaResult rv = DoDecode(aSample, data, size, &gotFrame, aResults);
+        if (NS_FAILED(rv)) {
+          return rv;
+        }
+        if (gotFrame && aGotFrame) {
+          *aGotFrame = true;
+        }
+      }
+      inputData += len;
+      inputSize -= len;
+    } while (inputSize > 0);
+    return NS_OK;
+  }
+  return DoDecode(aSample, inputData, inputSize, aGotFrame, aResults);
+}
+
 RefPtr<MediaDataDecoder::FlushPromise>
 FFmpegDataDecoder<LIBAV_VER>::Flush()
 {
   return InvokeAsync(mTaskQueue, this, __func__,
                      &FFmpegDataDecoder<LIBAV_VER>::ProcessFlush);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 FFmpegDataDecoder<LIBAV_VER>::Drain()
 {
   return InvokeAsync(mTaskQueue, this, __func__,
                      &FFmpegDataDecoder<LIBAV_VER>::ProcessDrain);
 }
 
+RefPtr<MediaDataDecoder::DecodePromise>
+FFmpegDataDecoder<LIBAV_VER>::ProcessDrain()
+{
+  RefPtr<MediaRawData> empty(new MediaRawData());
+  empty->mTimecode = mLastInputDts;
+  bool gotFrame = false;
+  DecodedData results;
+  while (NS_SUCCEEDED(DoDecode(empty, &gotFrame, results)) &&
+         gotFrame) {
+  }
+  return DecodePromise::CreateAndResolve(Move(results), __func__);
+}
+
 RefPtr<MediaDataDecoder::FlushPromise>
 FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mCodecContext) {
     mLib->avcodec_flush_buffers(mCodecContext);
   }
+  if (mCodecParser) {
+    mLib->av_parser_close(mCodecParser);
+    mCodecParser = mLib->av_parser_init(mCodecID);
+  }
   return FlushPromise::CreateAndResolve(true, __func__);
 }
 
 void
 FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
 {
   StaticMutexAutoLock mon(sMonitor);
 
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
@@ -37,30 +37,42 @@ public:
 
   static AVCodec* FindAVCodec(FFmpegLibWrapper* aLib, AVCodecID aCodec);
 
 protected:
   // Flush and Drain operation, always run
   virtual RefPtr<FlushPromise> ProcessFlush();
   virtual void ProcessShutdown();
   virtual void InitCodecContext() { }
-  AVFrame*        PrepareFrame();
-  MediaResult     InitDecoder();
+  AVFrame* PrepareFrame();
+  MediaResult InitDecoder();
+  MediaResult DoDecode(MediaRawData* aSample,
+                       bool* aGotFrame,
+                       DecodedData& aOutResults);
 
   FFmpegLibWrapper* mLib;
 
   AVCodecContext* mCodecContext;
-  AVFrame*        mFrame;
+  AVCodecParserContext* mCodecParser;
+  AVFrame* mFrame;
   RefPtr<MediaByteBuffer> mExtraData;
   AVCodecID mCodecID;
 
 private:
-  virtual RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample) = 0;
-  virtual RefPtr<DecodePromise> ProcessDrain() = 0;
+  RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
+  RefPtr<DecodePromise> ProcessDrain();
+  virtual MediaResult DoDecode(MediaRawData* aSample,
+                               uint8_t* aData,
+                               int aSize,
+                               bool* aGotFrame,
+                               MediaDataDecoder::DecodedData& aOutResults) = 0;
+  virtual bool NeedParser() const { return false; }
+  virtual int ParserFlags() const { return PARSER_FLAG_COMPLETE_FRAMES; }
 
   static StaticMutex sMonitor;
   const RefPtr<TaskQueue> mTaskQueue;
   MozPromiseHolder<DecodePromise> mPromise;
+  media::TimeUnit mLastInputDts;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegDataDecoder_h__
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -6,16 +6,17 @@
 #include "FFmpegLog.h"
 #include "MediaPrefs.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Types.h"
 #include "PlatformDecoderModule.h"
 #include "prlink.h"
 
 #define AV_LOG_DEBUG    48
+#define AV_LOG_INFO     32
 
 namespace mozilla
 {
 
 FFmpegLibWrapper::LinkResult
 FFmpegLibWrapper::Link()
 {
   if (!mAVCodecLib || !mAVUtilLib) {
@@ -136,20 +137,23 @@ FFmpegLibWrapper::Link()
   AV_FUNC(av_frame_alloc, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
   AV_FUNC(av_frame_free, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
   AV_FUNC(av_frame_unref, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
   AV_FUNC_OPTION(av_frame_get_colorspace, AV_FUNC_AVUTIL_ALL)
 #undef AV_FUNC
 #undef AV_FUNC_OPTION
 
   avcodec_register_all();
-#ifdef DEBUG
-  av_log_set_level(AV_LOG_DEBUG);
-#endif
-
+  if (MOZ_LOG_TEST(sPDMLog, LogLevel::Debug)) {
+    av_log_set_level(AV_LOG_DEBUG);
+  } else if (MOZ_LOG_TEST(sPDMLog, LogLevel::Info)) {
+    av_log_set_level(AV_LOG_INFO);
+  } else {
+    av_log_set_level(0);
+  }
   return LinkResult::Success;
 }
 
 void
 FFmpegLibWrapper::Unlink()
 {
   if (av_lockmgr_register) {
     // Registering a null lockmgr cause the destruction of libav* global mutexes
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -123,21 +123,18 @@ FFmpegVideoDecoder<LIBAV_VER>::PtsCorrec
 FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(
   FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue, const VideoInfo& aConfig,
   KnowsCompositor* aAllocator, ImageContainer* aImageContainer,
   bool aLowLatency)
   : FFmpegDataDecoder(aLib, aTaskQueue, GetCodecId(aConfig.mMimeType))
   , mImageAllocator(aAllocator)
   , mImageContainer(aImageContainer)
   , mInfo(aConfig)
-  , mCodecParser(nullptr)
-  , mLastInputDts(INT64_MIN)
   , mLowLatency(aLowLatency)
 {
-  MOZ_COUNT_CTOR(FFmpegVideoDecoder);
   // Use a new MediaByteBuffer as the object will be modified during
   // initialization.
   mExtraData = new MediaByteBuffer;
   mExtraData->AppendElements(*aConfig.mExtraData);
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 FFmpegVideoDecoder<LIBAV_VER>::Init()
@@ -179,89 +176,30 @@ FFmpegVideoDecoder<LIBAV_VER>::InitCodec
     mCodecContext->thread_count = decode_threads;
     if (decode_threads > 1) {
       mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
     }
   }
 
   // FFmpeg will call back to this to negotiate a video pixel format.
   mCodecContext->get_format = ChoosePixelFormat;
-
-  mCodecParser = mLib->av_parser_init(mCodecID);
-  if (mCodecParser) {
-    mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
-  }
-}
-
-RefPtr<MediaDataDecoder::DecodePromise>
-FFmpegVideoDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
-{
-  bool gotFrame = false;
-  DecodedData results;
-  MediaResult rv = DoDecode(aSample, &gotFrame, results);
-  if (NS_FAILED(rv)) {
-    return DecodePromise::CreateAndReject(rv, __func__);
-  }
-  return DecodePromise::CreateAndResolve(Move(results), __func__);
-}
-
-MediaResult
-FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, bool* aGotFrame,
-                                        MediaDataDecoder::DecodedData& aResults)
-{
-  uint8_t* inputData = const_cast<uint8_t*>(aSample->Data());
-  size_t inputSize = aSample->Size();
-
-#if LIBAVCODEC_VERSION_MAJOR >= 54
-  if (inputSize && mCodecParser && (mCodecID == AV_CODEC_ID_VP8
-#if LIBAVCODEC_VERSION_MAJOR >= 55
-      || mCodecID == AV_CODEC_ID_VP9
-#endif
-      )) {
-    while (inputSize) {
-      uint8_t* data = inputData;
-      int size = inputSize;
-      int len = mLib->av_parser_parse2(
-        mCodecParser, mCodecContext, &data, &size, inputData, inputSize,
-        aSample->mTime.ToMicroseconds(), aSample->mTimecode.ToMicroseconds(),
-        aSample->mOffset);
-      if (size_t(len) > inputSize) {
-        return NS_ERROR_DOM_MEDIA_DECODE_ERR;
-      }
-      inputData += len;
-      inputSize -= len;
-      if (size) {
-        bool gotFrame = false;
-        MediaResult rv = DoDecode(aSample, data, size, &gotFrame, aResults);
-        if (NS_FAILED(rv)) {
-          return rv;
-        }
-        if (gotFrame && aGotFrame) {
-          *aGotFrame = true;
-        }
-      }
-    }
-    return NS_OK;
-  }
-#endif
-  return DoDecode(aSample, inputData, inputSize, aGotFrame, aResults);
 }
 
 MediaResult
 FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
                                         uint8_t* aData, int aSize,
                                         bool* aGotFrame,
                                         MediaDataDecoder::DecodedData& aResults)
 {
   AVPacket packet;
   mLib->av_init_packet(&packet);
 
   packet.data = aData;
   packet.size = aSize;
-  packet.dts = mLastInputDts = aSample->mTimecode.ToMicroseconds();
+  packet.dts = aSample->mTimecode.ToMicroseconds();
   packet.pts = aSample->mTime.ToMicroseconds();
   packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
   packet.pos = aSample->mOffset;
 
   // LibAV provides no API to retrieve the decoded sample's duration.
   // (FFmpeg >= 1.0 provides av_frame_get_pkt_duration)
   // As such we instead use a map using the dts as key that we will retrieve
   // later.
@@ -414,45 +352,24 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
   }
   aResults.AppendElement(Move(v));
   if (aGotFrame) {
     *aGotFrame = true;
   }
   return NS_OK;
 }
 
-RefPtr<MediaDataDecoder::DecodePromise>
-FFmpegVideoDecoder<LIBAV_VER>::ProcessDrain()
-{
-  RefPtr<MediaRawData> empty(new MediaRawData());
-  empty->mTimecode = TimeUnit::FromMicroseconds(mLastInputDts);
-  bool gotFrame = false;
-  DecodedData results;
-  while (NS_SUCCEEDED(DoDecode(empty, &gotFrame, results)) && gotFrame) {
-  }
-  return DecodePromise::CreateAndResolve(Move(results), __func__);
-}
-
 RefPtr<MediaDataDecoder::FlushPromise>
 FFmpegVideoDecoder<LIBAV_VER>::ProcessFlush()
 {
   mPtsContext.Reset();
   mDurationMap.Clear();
   return FFmpegDataDecoder::ProcessFlush();
 }
 
-FFmpegVideoDecoder<LIBAV_VER>::~FFmpegVideoDecoder()
-{
-  MOZ_COUNT_DTOR(FFmpegVideoDecoder);
-  if (mCodecParser) {
-    mLib->av_parser_close(mCodecParser);
-    mCodecParser = nullptr;
-  }
-}
-
 AVCodecID
 FFmpegVideoDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
 {
   if (MP4Decoder::IsH264(aMimeType)) {
     return AV_CODEC_ID_H264;
   }
 
   if (aMimeType.EqualsLiteral("video/x-vnd.on2.vp6")) {
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
@@ -28,17 +28,16 @@ class FFmpegVideoDecoder<LIBAV_VER> : pu
   typedef SimpleMap<int64_t> DurationMap;
 
 public:
   FFmpegVideoDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
                      const VideoInfo& aConfig,
                      KnowsCompositor* aAllocator,
                      ImageContainer* aImageContainer,
                      bool aLowLatency);
-  virtual ~FFmpegVideoDecoder();
 
   RefPtr<InitPromise> Init() override;
   void InitCodecContext() override;
   nsCString GetDescriptionName() const override
   {
 #ifdef USING_MOZFFVPX
     return NS_LITERAL_CSTRING("ffvpx video decoder");
 #else
@@ -48,58 +47,61 @@ public:
   ConversionRequired NeedsConversion() const override
   {
     return ConversionRequired::kNeedAVCC;
   }
 
   static AVCodecID GetCodecId(const nsACString& aMimeType);
 
 private:
-  RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample) override;
-  RefPtr<DecodePromise> ProcessDrain() override;
   RefPtr<FlushPromise> ProcessFlush() override;
-  MediaResult DoDecode(MediaRawData* aSample, bool* aGotFrame,
-                       DecodedData& aResults);
-  MediaResult DoDecode(MediaRawData* aSample, uint8_t* aData, int aSize,
-                       bool* aGotFrame, DecodedData& aResults);
+  MediaResult DoDecode(MediaRawData* aSample,
+                       uint8_t* aData,
+                       int aSize,
+                       bool* aGotFrame,
+                       DecodedData& aResults) override;
   void OutputDelayedFrames();
+  bool NeedParser() const override
+  {
+    return
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+      mCodecID == AV_CODEC_ID_VP9 ||
+#endif
+      mCodecID == AV_CODEC_ID_VP8;
+  }
 
   /**
    * This method allocates a buffer for FFmpeg's decoder, wrapped in an Image.
    * Currently it only supports Planar YUV420, which appears to be the only
    * non-hardware accelerated image format that FFmpeg's H264 decoder is
    * capable of outputting.
    */
   int AllocateYUV420PVideoBuffer(AVCodecContext* aCodecContext,
                                  AVFrame* aFrame);
 
   RefPtr<KnowsCompositor> mImageAllocator;
   RefPtr<ImageContainer> mImageContainer;
   VideoInfo mInfo;
 
-  // Parser used for VP8 and VP9 decoding.
-  AVCodecParserContext* mCodecParser;
-
   class PtsCorrectionContext
   {
   public:
     PtsCorrectionContext();
     int64_t GuessCorrectPts(int64_t aPts, int64_t aDts);
     void Reset();
     int64_t LastDts() const { return mLastDts; }
 
   private:
     int64_t mNumFaultyPts; /// Number of incorrect PTS values so far
     int64_t mNumFaultyDts; /// Number of incorrect DTS values so far
     int64_t mLastPts;      /// PTS of the last frame
     int64_t mLastDts;      /// DTS of the last frame
   };
 
   PtsCorrectionContext mPtsContext;
-  int64_t mLastInputDts;
 
   DurationMap mDurationMap;
   const bool mLowLatency;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegVideoDecoder_h__
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -116,17 +116,17 @@ H264Converter::Decode(MediaRawData* aSam
     return DecodePromise::CreateAndReject(rv, __func__);
   }
 
   if (mNeedKeyframe && !aSample->mKeyframe) {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   }
 
   if (!*mNeedAVCC &&
-      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+      mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe).isErr()) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("ConvertSampleToAnnexB")),
       __func__);
   }
 
   mNeedKeyframe = false;
 
@@ -370,17 +370,17 @@ H264Converter::DecodeFirstSample(MediaRa
 {
   if (mNeedKeyframe && !aSample->mKeyframe) {
     mDecodePromise.Resolve(mPendingFrames, __func__);
     mPendingFrames.Clear();
     return;
   }
 
   if (!*mNeedAVCC &&
-      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+      mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe).isErr()) {
     mDecodePromise.Reject(MediaResult(NS_ERROR_OUT_OF_MEMORY,
                                       RESULT_DETAIL("ConvertSampleToAnnexB")),
                           __func__);
     return;
   }
 
   mNeedKeyframe = false;
 
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -108,24 +108,30 @@ bool WebMBufferedParser::Append(const un
         mClusterOffset = mCurrentOffset + (p - aBuffer) -
                         (mElement.mID.mLength + mElement.mSize.mLength);
         // Handle "unknown" length;
         if (mElement.mSize.mValue + 1 != uint64_t(1) << (mElement.mSize.mLength * 7)) {
           mClusterEndOffset = mClusterOffset + mElement.mID.mLength + mElement.mSize.mLength + mElement.mSize.mValue;
         } else {
           mClusterEndOffset = -1;
         }
+        mGotClusterTimecode = false;
         mState = READ_ELEMENT_ID;
         break;
       case BLOCKGROUP_ID:
         mState = READ_ELEMENT_ID;
         break;
       case SIMPLEBLOCK_ID:
         /* FALLTHROUGH */
       case BLOCK_ID:
+        if (!mGotClusterTimecode) {
+          WEBM_DEBUG("The Timecode element must appear before any Block or "
+                     "SimpleBlock elements in a Cluster");
+          return false;
+        }
         mBlockSize = mElement.mSize.mValue;
         mBlockTimecode = 0;
         mBlockTimecodeLength = BLOCK_TIMECODE_LENGTH;
         mBlockOffset = mCurrentOffset + (p - aBuffer) -
                        (mElement.mID.mLength + mElement.mSize.mLength);
         mState = READ_VINT;
         mNextState = READ_BLOCK_TIMECODE;
         break;
@@ -159,23 +165,25 @@ bool WebMBufferedParser::Append(const un
         mVInt.mValue |= *p++;
         mVIntLeft -= 1;
       } else {
         mState = mNextState;
       }
       break;
     case READ_TIMECODESCALE:
       if (!mGotTimecodeScale) {
+        WEBM_DEBUG("Should get the SegmentInfo first");
         return false;
       }
       mTimecodeScale = mVInt.mValue;
       mState = READ_ELEMENT_ID;
       break;
     case READ_CLUSTER_TIMECODE:
       mClusterTimecode = mVInt.mValue;
+      mGotClusterTimecode = true;
       mState = READ_ELEMENT_ID;
       break;
     case READ_BLOCK_TIMECODE:
       if (mBlockTimecodeLength) {
         mBlockTimecode <<= 8;
         mBlockTimecode |= *p++;
         mBlockTimecodeLength -= 1;
       } else {
@@ -185,16 +193,17 @@ bool WebMBufferedParser::Append(const un
           ReentrantMonitorAutoEnter mon(aReentrantMonitor);
           int64_t endOffset = mBlockOffset + mBlockSize +
                               mElement.mID.mLength + mElement.mSize.mLength;
           uint32_t idx = aMapping.IndexOfFirstElementGt(endOffset);
           if (idx == 0 || aMapping[idx - 1] != endOffset) {
             // Don't insert invalid negative timecodes.
             if (mBlockTimecode >= 0 || mClusterTimecode >= uint16_t(abs(mBlockTimecode))) {
               if (!mGotTimecodeScale) {
+                WEBM_DEBUG("Should get the TimecodeScale first");
                 return false;
               }
               uint64_t absTimecode = mClusterTimecode + mBlockTimecode;
               absTimecode *= mTimecodeScale;
               // Avoid creating an entry if the timecode is out of order
               // (invalid according to the WebM specification) so that
               // ordering invariants of aMapping are not violated.
               if (idx == 0 ||
@@ -261,16 +270,22 @@ WebMBufferedParser::EndSegmentOffset(int
 {
   if (mLastInitStartOffset > aOffset || mClusterOffset > aOffset) {
     return std::min(mLastInitStartOffset >= 0 ? mLastInitStartOffset : INT64_MAX,
                     mClusterOffset >= 0 ? mClusterOffset : INT64_MAX);
   }
   return mBlockEndOffset;
 }
 
+int64_t
+WebMBufferedParser::GetClusterOffset() const
+{
+  return mClusterOffset;
+}
+
 // SyncOffsetComparator and TimeComparator are slightly confusing, in that
 // the nsTArray they're used with (mTimeMapping) is sorted by mEndOffset and
 // these comparators are used on the other fields of WebMTimeDataOffset.
 // This is only valid because timecodes are required to be monotonically
 // increasing within a file (thus establishing an ordering relationship with
 // mTimecode), and mEndOffset is derived from mSyncOffset.
 struct SyncOffsetComparator {
   bool Equals(const WebMTimeDataOffset& a, const int64_t& b) const {
--- a/dom/media/webm/WebMBufferedParser.h
+++ b/dom/media/webm/WebMBufferedParser.h
@@ -62,35 +62,42 @@ struct WebMBufferedParser
     , mState(READ_ELEMENT_ID)
     , mNextState(READ_ELEMENT_ID)
     , mVIntRaw(false)
     , mLastInitStartOffset(-1)
     , mClusterSyncPos(0)
     , mVIntLeft(0)
     , mBlockSize(0)
     , mClusterTimecode(0)
-    , mClusterOffset(0)
+    , mClusterOffset(-1)
     , mClusterEndOffset(-1)
     , mBlockOffset(0)
     , mBlockTimecode(0)
     , mBlockTimecodeLength(0)
     , mSkipBytes(0)
     , mTimecodeScale(1000000)
     , mGotTimecodeScale(false)
+    , mGotClusterTimecode(false)
   {
     if (mStartOffset != 0) {
       mState = FIND_CLUSTER_SYNC;
     }
   }
 
   uint32_t GetTimecodeScale() {
     MOZ_ASSERT(mGotTimecodeScale);
     return mTimecodeScale;
   }
 
+  // Use this function when we would only feed media segment for the parser.
+  void AppendMediaSegmentOnly()
+  {
+    mGotTimecodeScale = true;
+  }
+
   // If this parser is not expected to parse a segment info, it must be told
   // the appropriate timecode scale to use from elsewhere.
   void SetTimecodeScale(uint32_t aTimecodeScale) {
     mTimecodeScale = aTimecodeScale;
     mGotTimecodeScale = true;
   }
 
   // Steps the parser through aLength bytes of data.  Always consumes
@@ -109,16 +116,19 @@ struct WebMBufferedParser
     return mCurrentOffset < aOffset;
   }
 
   // Returns the start offset of the init (EBML) or media segment (Cluster)
   // following the aOffset position. If none were found, returns mBlockEndOffset.
   // This allows to determine the end of the interval containg aOffset.
   int64_t EndSegmentOffset(int64_t aOffset);
 
+  // Return the Cluster offset, return -1 if we can't find the Cluster.
+  int64_t GetClusterOffset() const;
+
   // The offset at which this parser started parsing.  Used to merge
   // adjacent parsers, in which case the later parser adopts the earlier
   // parser's mStartOffset.
   int64_t mStartOffset;
 
   // Current offset within the stream.  Updated in chunks as Append() consumes
   // data.
   int64_t mCurrentOffset;
@@ -226,17 +236,17 @@ private:
   // block is skipped once the block timecode has been parsed.
   uint64_t mBlockSize;
 
   // Cluster-level timecode.
   uint64_t mClusterTimecode;
 
   // Start offset of the cluster currently being parsed.  Used as the sync
   // point offset for the offset-to-time mapping as each block timecode is
-  // been parsed.
+  // been parsed. -1 if unknown.
   int64_t mClusterOffset;
 
   // End offset of the cluster currently being parsed. -1 if unknown.
   int64_t mClusterEndOffset;
 
   // Start offset of the block currently being parsed.  Used as the byte
   // offset for the offset-to-time mapping once the block timecode has been
   // parsed.
@@ -255,16 +265,19 @@ private:
 
   // Timecode scale read from the segment info and used to scale absolute
   // timecodes.
   uint32_t mTimecodeScale;
 
   // True if we read the timecode scale from the segment info or have
   // confirmed that the default value is to be used.
   bool mGotTimecodeScale;
+
+  // True if we've read the cluster time code.
+  bool mGotClusterTimecode;
 };
 
 class WebMBufferedState final
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState)
 
 public:
   WebMBufferedState()
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -3538,54 +3538,54 @@ EditorBase::IsBlockNode(nsINode* aNode)
   // screwing around with the class hierarchy here in order
   // to not duplicate the code in GetNextNode/GetPrevNode
   // across both EditorBase/HTMLEditor.
   return false;
 }
 
 bool
 EditorBase::CanContain(nsINode& aParent,
-                       nsIContent& aChild)
+                       nsIContent& aChild) const
 {
   switch (aParent.NodeType()) {
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
       return TagCanContain(*aParent.NodeInfo()->NameAtom(), aChild);
   }
   return false;
 }
 
 bool
 EditorBase::CanContainTag(nsINode& aParent,
-                          nsAtom& aChildTag)
+                          nsAtom& aChildTag) const
 {
   switch (aParent.NodeType()) {
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
       return TagCanContainTag(*aParent.NodeInfo()->NameAtom(), aChildTag);
   }
   return false;
 }
 
 bool
 EditorBase::TagCanContain(nsAtom& aParentTag,
-                          nsIContent& aChild)
+                          nsIContent& aChild) const
 {
   switch (aChild.NodeType()) {
     case nsIDOMNode::TEXT_NODE:
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
       return TagCanContainTag(aParentTag, *aChild.NodeInfo()->NameAtom());
   }
   return false;
 }
 
 bool
 EditorBase::TagCanContainTag(nsAtom& aParentTag,
-                             nsAtom& aChildTag)
+                             nsAtom& aChildTag) const
 {
   return true;
 }
 
 bool
 EditorBase::IsRoot(nsIDOMNode* inNode)
 {
   NS_ENSURE_TRUE(inNode, false);
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -765,20 +765,20 @@ public:
   static inline bool NodeIsType(nsIDOMNode* aNode, nsAtom* aTag)
   {
     return GetTag(aNode) == aTag;
   }
 
   /**
    * Returns true if aParent can contain a child of type aTag.
    */
-  bool CanContain(nsINode& aParent, nsIContent& aChild);
-  bool CanContainTag(nsINode& aParent, nsAtom& aTag);
-  bool TagCanContain(nsAtom& aParentTag, nsIContent& aChild);
-  virtual bool TagCanContainTag(nsAtom& aParentTag, nsAtom& aChildTag);
+  bool CanContain(nsINode& aParent, nsIContent& aChild) const;
+  bool CanContainTag(nsINode& aParent, nsAtom& aTag) const;
+  bool TagCanContain(nsAtom& aParentTag, nsIContent& aChild) const;
+  virtual bool TagCanContainTag(nsAtom& aParentTag, nsAtom& aChildTag) const;
 
   /**
    * Returns true if aNode is our root node.
    */
   bool IsRoot(nsIDOMNode* inNode);
   bool IsRoot(nsINode* inNode);
   bool IsEditorRoot(nsINode* aNode);
 
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1532,16 +1532,45 @@ HTMLEditRules::WillLoadHTML(Selection* a
     }
     mHTMLEditor->DeleteNode(mBogusNode);
     mBogusNode = nullptr;
   }
 
   return NS_OK;
 }
 
+bool
+HTMLEditRules::CanContainParagraph(Element& aElement) const
+{
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return false;
+  }
+
+  if (mHTMLEditor->CanContainTag(aElement, *nsGkAtoms::p)) {
+    return true;
+  }
+
+  // Even if the element cannot have a <p> element as a child, it can contain
+  // <p> element as a descendant if it's one of the following elements.
+  if (aElement.IsAnyOfHTMLElements(nsGkAtoms::ol,
+                                   nsGkAtoms::ul,
+                                   nsGkAtoms::dl,
+                                   nsGkAtoms::table,
+                                   nsGkAtoms::thead,
+                                   nsGkAtoms::tbody,
+                                   nsGkAtoms::tfoot,
+                                   nsGkAtoms::tr)) {
+    return true;
+  }
+
+  // XXX Otherwise, Chromium checks the CSS box is a block, but we don't do it
+  //     for now.
+  return false;
+}
+
 nsresult
 HTMLEditRules::WillInsertBreak(Selection& aSelection,
                                bool* aCancel,
                                bool* aHandled)
 {
   MOZ_ASSERT(aCancel && aHandled);
   *aCancel = false;
   *aHandled = false;
@@ -1580,64 +1609,91 @@ HTMLEditRules::WillInsertBreak(Selection
   int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
 
   // Do nothing if the node is read-only
   if (!htmlEditor->IsModifiableNode(node)) {
     *aCancel = true;
     return NS_OK;
   }
 
-  // Identify the block
-  nsCOMPtr<Element> blockParent = htmlEditor->GetBlock(node);
-  NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
-
   // If the active editing host is an inline element, or if the active editing
   // host is the block parent itself and we're configured to use <br> as a
   // paragraph separator, just append a <br>.
   nsCOMPtr<Element> host = htmlEditor->GetActiveEditingHost();
   if (NS_WARN_IF(!host)) {
     return NS_ERROR_FAILURE;
   }
-  ParagraphSeparator separator = mHTMLEditor->GetDefaultParagraphSeparator();
-  if (!IsBlockNode(*host) ||
-      // The nodes that can contain p and div are the same.  If the editing
-      // host is a <p> or similar, we have to just insert a newline.
-      (!mHTMLEditor->CanContainTag(*host, *nsGkAtoms::p) &&
-       // These can't contain <p> as a child, but can as a descendant, so we
-       // don't have to fall back to inserting a newline.
-       !host->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul, nsGkAtoms::dl,
-                                  nsGkAtoms::table, nsGkAtoms::thead,
-                                  nsGkAtoms::tbody, nsGkAtoms::tfoot,
-                                  nsGkAtoms::tr)) ||
-      (host == blockParent && separator == ParagraphSeparator::br)) {
+
+  // Look for the nearest parent block.  However, don't return error even if
+  // there is no block parent here because in such case, i.e., editing host
+  // is an inline element, we should insert <br> simply.
+  RefPtr<Element> blockParent = HTMLEditor::GetBlock(node, host);
+
+  ParagraphSeparator separator = htmlEditor->GetDefaultParagraphSeparator();
+  bool insertBRElement;
+  // If there is no block parent in the editing host, i.e., the editing host
+  // itself is also a non-block element, we should insert a <br> element.
+  if (!blockParent) {
+    // XXX Chromium checks if the CSS box of the editing host is block.
+    insertBRElement = true;
+  }
+  // If only the editing host is block, and the default paragraph separator
+  // is <br> or the editing host cannot contain a <p> element, we should
+  // insert a <br> element.
+  else if (host == blockParent) {
+    insertBRElement =
+      separator == ParagraphSeparator::br || !CanContainParagraph(*host);
+  }
+  // If the nearest block parent is a single-line container declared in
+  // the execCommand spec and not the editing host, we should separate the
+  // block even if the default paragraph separator is <br> element.
+  else if (HTMLEditUtils::IsSingleLineContainer(*blockParent)) {
+    insertBRElement = false;
+  }
+  // Otherwise, unless there is no block ancestor which can contain <p>
+  // element, we shouldn't insert a <br> element here.
+  else {
+    insertBRElement = true;
+    for (Element* blockAncestor = blockParent;
+         blockAncestor && insertBRElement;
+         blockAncestor = HTMLEditor::GetBlockNodeParent(blockAncestor, host)) {
+      insertBRElement = !CanContainParagraph(*blockAncestor);
+    }
+  }
+
+  // If we cannot insert a <p>/<div> element at the selection, we should insert
+  // a <br> element instead.
+  if (insertBRElement) {
     nsresult rv = StandardBreakImpl(node, offset, aSelection);
     NS_ENSURE_SUCCESS(rv, rv);
     *aHandled = true;
     return NS_OK;
   }
+
   if (host == blockParent && separator != ParagraphSeparator::br) {
     // Insert a new block first
     MOZ_ASSERT(separator == ParagraphSeparator::div ||
                separator == ParagraphSeparator::p);
     nsresult rv = MakeBasicBlock(aSelection,
                                  ParagraphSeparatorElement(separator));
     // We warn on failure, but don't handle it, because it might be harmless.
     // Instead we just check that a new block was actually created.
-    Unused << NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                         "HTMLEditRules::MakeBasicBlock() failed");
 
     // Reinitialize node/offset in case they're not inside the new block
     if (NS_WARN_IF(!aSelection.GetRangeAt(0) ||
                    !aSelection.GetRangeAt(0)->GetStartContainer())) {
       return NS_ERROR_FAILURE;
     }
     node = *aSelection.GetRangeAt(0)->GetStartContainer();
     child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
     offset = aSelection.GetRangeAt(0)->StartOffset();
 
-    blockParent = mHTMLEditor->GetBlock(node);
+    blockParent = mHTMLEditor->GetBlock(node, host);
     if (NS_WARN_IF(!blockParent)) {
       return NS_ERROR_UNEXPECTED;
     }
     if (NS_WARN_IF(blockParent == host)) {
       // Didn't create a new block for some reason, fall back to <br>
       rv = StandardBreakImpl(node, offset, aSelection);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -168,16 +168,22 @@ protected:
                                nsIEditor::EStripWrappers aStripWrappers,
                                bool* aCancel, bool* aHandled);
   nsresult DidDeleteSelection(Selection* aSelection,
                               nsIEditor::EDirection aDir,
                               nsresult aResult);
   nsresult InsertBRIfNeeded(Selection* aSelection);
 
   /**
+   * CanContainParagraph() returns true if aElement can have a <p> element as
+   * its child or its descendant.
+   */
+  bool CanContainParagraph(Element& aElement) const;
+
+  /**
    * Insert a normal <br> element or a moz-<br> element to aNode when
    * aNode is a block and it has no children.
    *
    * @param aNode           Reference to a block parent.
    * @param aInsertMozBR    true if this should insert a moz-<br> element.
    *                        Otherwise, i.e., this should insert a normal <br>
    *                        element, false.
    */
--- a/editor/libeditor/HTMLEditUtils.cpp
+++ b/editor/libeditor/HTMLEditUtils.cpp
@@ -829,9 +829,35 @@ bool
 HTMLEditUtils::IsContainer(int32_t aTag)
 {
   NS_ASSERTION(aTag > eHTMLTag_unknown && aTag <= eHTMLTag_userdefined,
                "aTag out of range!");
 
   return kElements[aTag - 1].mIsContainer;
 }
 
+bool
+HTMLEditUtils::IsNonListSingleLineContainer(nsINode& aNode)
+{
+  return aNode.IsAnyOfHTMLElements(nsGkAtoms::address,
+                                   nsGkAtoms::div,
+                                   nsGkAtoms::h1,
+                                   nsGkAtoms::h2,
+                                   nsGkAtoms::h3,
+                                   nsGkAtoms::h4,
+                                   nsGkAtoms::h5,
+                                   nsGkAtoms::h6,
+                                   nsGkAtoms::listing,
+                                   nsGkAtoms::p,
+                                   nsGkAtoms::pre,
+                                   nsGkAtoms::xmp);
+}
+
+bool
+HTMLEditUtils::IsSingleLineContainer(nsINode& aNode)
+{
+  return IsNonListSingleLineContainer(aNode) ||
+         aNode.IsAnyOfHTMLElements(nsGkAtoms::li,
+                                   nsGkAtoms::dt,
+                                   nsGkAtoms::dd);
+}
+
 } // namespace mozilla
--- a/editor/libeditor/HTMLEditUtils.h
+++ b/editor/libeditor/HTMLEditUtils.h
@@ -11,17 +11,16 @@
 class nsIDOMNode;
 class nsINode;
 
 namespace mozilla {
 
 class HTMLEditUtils final
 {
 public:
-  // from nsHTMLEditRules:
   static bool IsInlineStyle(nsINode* aNode);
   static bool IsInlineStyle(nsIDOMNode *aNode);
   static bool IsFormatNode(nsINode* aNode);
   static bool IsFormatNode(nsIDOMNode* aNode);
   static bool IsNodeThatCanOutdent(nsIDOMNode* aNode);
   static bool IsHeader(nsINode& aNode);
   static bool IsHeader(nsIDOMNode* aNode);
   static bool IsParagraph(nsIDOMNode* aNode);
@@ -55,14 +54,22 @@ public:
   static bool IsMozDiv(nsIDOMNode* aNode);
   static bool IsMailCite(nsINode* aNode);
   static bool IsMailCite(nsIDOMNode* aNode);
   static bool IsFormWidget(nsINode* aNode);
   static bool IsFormWidget(nsIDOMNode* aNode);
   static bool SupportsAlignAttr(nsINode& aNode);
   static bool CanContain(int32_t aParent, int32_t aChild);
   static bool IsContainer(int32_t aTag);
+
+  /**
+   * See execCommand spec:
+   * https://w3c.github.io/editing/execCommand.html#non-list-single-line-container
+   * https://w3c.github.io/editing/execCommand.html#single-line-container
+   */
+  static bool IsNonListSingleLineContainer(nsINode& aNode);
+  static bool IsSingleLineContainer(nsINode& aNode);
 };
 
 } // namespace mozilla
 
 #endif // #ifndef HTMLEditUtils_h
 
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -743,51 +743,58 @@ HTMLEditor::IsBlockNode(nsINode* aNode)
 {
   return aNode && NodeIsBlockStatic(aNode);
 }
 
 /**
  * GetBlockNodeParent returns enclosing block level ancestor, if any.
  */
 Element*
-HTMLEditor::GetBlockNodeParent(nsINode* aNode)
+HTMLEditor::GetBlockNodeParent(nsINode* aNode,
+                               nsINode* aAncestorLimiter)
 {
   MOZ_ASSERT(aNode);
+  MOZ_ASSERT(!aAncestorLimiter ||
+             aNode == aAncestorLimiter ||
+             EditorUtils::IsDescendantOf(aNode, aAncestorLimiter),
+             "aNode isn't in aAncestorLimiter");
+
+  // The caller has already reached the limiter.
+  if (aNode == aAncestorLimiter) {
+    return nullptr;
+  }
 
   nsCOMPtr<nsINode> p = aNode->GetParentNode();
 
   while (p) {
     if (NodeIsBlockStatic(p)) {
       return p->AsElement();
     }
+    // Now, we have reached the limiter, there is no block in its ancestors.
+    if (p == aAncestorLimiter) {
+      return nullptr;
+    }
     p = p->GetParentNode();
   }
 
   return nullptr;
 }
 
-nsIDOMNode*
-HTMLEditor::GetBlockNodeParent(nsIDOMNode* aNode)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-
-  if (!node) {
-    NS_NOTREACHED("null node passed to GetBlockNodeParent()");
-    return nullptr;
-  }
-
-  return GetAsDOMNode(GetBlockNodeParent(node));
-}
-
 /**
  * Returns the node if it's a block, otherwise GetBlockNodeParent
  */
 Element*
-HTMLEditor::GetBlock(nsINode& aNode)
+HTMLEditor::GetBlock(nsINode& aNode,
+                     nsINode* aAncestorLimiter)
 {
+  MOZ_ASSERT(!aAncestorLimiter ||
+             &aNode == aAncestorLimiter ||
+             EditorUtils::IsDescendantOf(&aNode, aAncestorLimiter),
+             "aNode isn't in aAncestorLimiter");
+
   if (NodeIsBlockStatic(&aNode)) {
     return aNode.AsElement();
   }
   return GetBlockNodeParent(&aNode);
 }
 
 /**
  * IsNextCharInNodeWhitespace() checks the adjacent content in the same node to
@@ -3459,17 +3466,17 @@ HTMLEditor::EndOperation()
   // post processing
   nsresult rv = rules ? rules->AfterEdit(mAction, mDirection) : NS_OK;
   EditorBase::EndOperation();  // will clear mAction, mDirection
   return rv;
 }
 
 bool
 HTMLEditor::TagCanContainTag(nsAtom& aParentTag,
-                             nsAtom& aChildTag)
+                             nsAtom& aChildTag) const
 {
   int32_t childTagEnum;
   // XXX Should this handle #cdata-section too?
   if (&aChildTag == nsGkAtoms::textTagName) {
     childTagEnum = eHTMLTag_text;
   } else {
     childTagEnum = nsHTMLTags::AtomTagToId(&aChildTag);
   }
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -180,20 +180,30 @@ public:
 
   /**
    * This sets background on the appropriate container element (table, cell,)
    * or calls into nsTextEditor to set the page background.
    */
   nsresult SetCSSBackgroundColor(const nsAString& aColor);
   nsresult SetHTMLBackgroundColor(const nsAString& aColor);
 
-  // Block methods moved from EditorBase
-  static Element* GetBlockNodeParent(nsINode* aNode);
-  static nsIDOMNode* GetBlockNodeParent(nsIDOMNode* aNode);
-  static Element* GetBlock(nsINode& aNode);
+  /**
+   * GetBlockNodeParent() returns parent or nearest ancestor of aNode if
+   * there is a block parent.  If aAncestorLimiter is not nullptr,
+   * this stops looking for the result.
+   */
+  static Element* GetBlockNodeParent(nsINode* aNode,
+                                     nsINode* aAncestorLimiter = nullptr);
+  /**
+   * GetBlock() returns aNode itself, or parent or nearest ancestor of aNode
+   * if there is a block parent.  If aAncestorLimiter is not nullptr,
+   * this stops looking for the result.
+   */
+  static Element* GetBlock(nsINode& aNode,
+                           nsINode* aAncestorLimiter = nullptr);
 
   void IsNextCharInNodeWhitespace(nsIContent* aContent,
                                   int32_t aOffset,
                                   bool* outIsSpace,
                                   bool* outIsNBSP,
                                   nsIContent** outNode = nullptr,
                                   int32_t* outOffset = 0);
   void IsPrevCharInNodeWhitespace(nsIContent* aContent,
@@ -279,17 +289,17 @@ public:
    * with a call to EndOperation.
    */
   NS_IMETHOD EndOperation() override;
 
   /**
    * returns true if aParentTag can contain a child of type aChildTag.
    */
   virtual bool TagCanContainTag(nsAtom& aParentTag,
-                                nsAtom& aChildTag) override;
+                                nsAtom& aChildTag) const override;
 
   /**
    * Returns true if aNode is a container.
    */
   virtual bool IsContainer(nsINode* aNode) override;
   virtual bool IsContainer(nsIDOMNode* aNode) override;
 
   /**
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -421,18 +421,18 @@ HTMLEditor::DoInsertHTMLWithContext(cons
     }
 
     // Loop over the node list and paste the nodes:
     nsCOMPtr<nsIDOMNode> parentBlock, lastInsertNode, insertedContextParent;
     nsCOMPtr<nsINode> parentNodeNode = do_QueryInterface(parentNode);
     NS_ENSURE_STATE(parentNodeNode || !parentNode);
     if (IsBlockNode(parentNodeNode)) {
       parentBlock = parentNode;
-    } else {
-      parentBlock = GetBlockNodeParent(parentNode);
+    } else if (parentNodeNode) {
+      parentBlock = GetAsDOMNode(GetBlockNodeParent(parentNodeNode));
     }
 
     int32_t listCount = nodeList.Length();
     for (int32_t j = 0; j < listCount; j++) {
       bool bDidInsert = false;
       nsCOMPtr<nsIDOMNode> curNode = nodeList[j]->AsDOMNode();
 
       NS_ENSURE_TRUE(curNode, NS_ERROR_FAILURE);
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_2D_H
 #define _MOZILLA_GFX_2D_H
 
 #include "Types.h"
 #include "Point.h"
--- a/gfx/2d/AutoHelpersWin.h
+++ b/gfx/2d/AutoHelpersWin.h
@@ -1,12 +1,13 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-* 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/. */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_gfx_AutoHelpersWin_h
 #define mozilla_gfx_AutoHelpersWin_h
 
 #include <windows.h>
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/BaseCoord.h
+++ b/gfx/2d/BaseCoord.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASECOORD_H_
 #define MOZILLA_GFX_BASECOORD_H_
 
 #include "mozilla/Attributes.h"
 
--- a/gfx/2d/BaseMargin.h
+++ b/gfx/2d/BaseMargin.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASEMARGIN_H_
 #define MOZILLA_GFX_BASEMARGIN_H_
 
 #include <ostream>
 
--- a/gfx/2d/BasePoint.h
+++ b/gfx/2d/BasePoint.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASEPOINT_H_
 #define MOZILLA_GFX_BASEPOINT_H_
 
 #include <cmath>
 #include <ostream>
--- a/gfx/2d/BasePoint3D.h
+++ b/gfx/2d/BasePoint3D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_BASEPOINT3D_H_
 #define MOZILLA_BASEPOINT3D_H_
 
 #include "mozilla/Assertions.h"
 
--- a/gfx/2d/BasePoint4D.h
+++ b/gfx/2d/BasePoint4D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_BASEPOINT4D_H_
 #define MOZILLA_BASEPOINT4D_H_
 
 #include "mozilla/Assertions.h"
 
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASERECT_H_
 #define MOZILLA_GFX_BASERECT_H_
 
 #include <algorithm>
 #include <cmath>
--- a/gfx/2d/BaseSize.h
+++ b/gfx/2d/BaseSize.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_BASESIZE_H_
 #define MOZILLA_GFX_BASESIZE_H_
 
 #include <algorithm>
 #include <ostream>
--- a/gfx/2d/BezierUtils.cpp
+++ b/gfx/2d/BezierUtils.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-// vim:cindent:ts=2:et:sw=2:
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BezierUtils.h"
 
 #include "PathHelpers.h"
 
--- a/gfx/2d/BezierUtils.h
+++ b/gfx/2d/BezierUtils.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_BezierUtils_h_
 #define mozilla_BezierUtils_h_
 
 #include "mozilla/gfx/2D.h"
--- a/gfx/2d/BlurLS3.cpp
+++ b/gfx/2d/BlurLS3.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Blur.h"
 
 #include <string.h>
 
--- a/gfx/2d/BlurNEON.cpp
+++ b/gfx/2d/BlurNEON.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Blur.h"
 #include <arm_neon.h>
 
 namespace mozilla {
--- a/gfx/2d/BlurSSE2.cpp
+++ b/gfx/2d/BlurSSE2.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Blur.h"
 
 #include "SSEHelpers.h"
 
--- a/gfx/2d/BorrowedContext.h
+++ b/gfx/2d/BorrowedContext.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_BORROWED_CONTEXT_H
 #define _MOZILLA_GFX_BORROWED_CONTEXT_H
 
 #include "2D.h"
 
--- a/gfx/2d/CGTextDrawing.h
+++ b/gfx/2d/CGTextDrawing.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _MOZILLA_GFX_SKIACGPOPUPDRAWER_H
 #define _MOZILLA_GFX_SKIACGPOPUPDRAWER_H
 
 #include <ApplicationServices/ApplicationServices.h>
 #include "nsDebug.h"
 #include "mozilla/Vector.h"
--- a/gfx/2d/ConvolutionFilter.cpp
+++ b/gfx/2d/ConvolutionFilter.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "ConvolutionFilter.h"
 #include "skia/src/core/SkBitmapFilter.h"
 #include "skia/src/core/SkConvolver.h"
--- a/gfx/2d/ConvolutionFilter.h
+++ b/gfx/2d/ConvolutionFilter.h
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_CONVOLUTION_FILTER_H_
 #define MOZILLA_GFX_CONVOLUTION_FILTER_H_
 
 #include "mozilla/UniquePtr.h"
--- a/gfx/2d/Coord.h
+++ b/gfx/2d/Coord.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_COORD_H_
 #define MOZILLA_GFX_COORD_H_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TypeTraits.h" // For IsSame
--- a/gfx/2d/CriticalSection.h
+++ b/gfx/2d/CriticalSection.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_CRITICALSECTION_H_
 #define MOZILLA_GFX_CRITICALSECTION_H_
 
 #ifdef WIN32
 #include <windows.h>
--- a/gfx/2d/DataSourceSurface.cpp
+++ b/gfx/2d/DataSourceSurface.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "DataSourceSurfaceWrapper.h"
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/DataSourceSurfaceWrapper.h
+++ b/gfx/2d/DataSourceSurfaceWrapper.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_
 #define MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_
 
 #include "2D.h"
 
--- a/gfx/2d/DataSurfaceHelpers.cpp
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cstring>
 
 #include "2D.h"
 #include "DataSurfaceHelpers.h"
 #include "Logging.h"
--- a/gfx/2d/DataSurfaceHelpers.h
+++ b/gfx/2d/DataSurfaceHelpers.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_DATASURFACEHELPERS_H
 #define _MOZILLA_GFX_DATASURFACEHELPERS_H
 
 #include "2D.h"
 
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWCOMMAND_H_
 #define MOZILLA_GFX_DRAWCOMMAND_H_
 
 #include <math.h>
 
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawEventRecorder.h"
 #include "PathRecording.h"
 #include "RecordingTypes.h"
 
 namespace mozilla {
--- a/gfx/2d/DrawEventRecorder.h
+++ b/gfx/2d/DrawEventRecorder.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
 #define MOZILLA_GFX_DRAWEVENTRECORDER_H_
 
 #include "2D.h"
 #include "RecordedEvent.h"
--- a/gfx/2d/DrawTarget.cpp
+++ b/gfx/2d/DrawTarget.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "Logging.h"
 #include "PathHelpers.h"
 
 #include "DrawTargetCapture.h"
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetCairo.h"
 
 #include "SourceSurfaceCairo.h"
 #include "PathCairo.h"
 #include "HelpersCairo.h"
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_DRAWTARGET_CAIRO_H_
 #define _MOZILLA_GFX_DRAWTARGET_CAIRO_H_
 
 #include "2D.h"
 #include "cairo.h"
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetCapture.h"
 #include "DrawCommand.h"
 #include "gfxPlatform.h"
 
 namespace mozilla {
--- a/gfx/2d/DrawTargetCapture.h
+++ b/gfx/2d/DrawTargetCapture.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWTARGETCAPTURE_H_
 #define MOZILLA_GFX_DRAWTARGETCAPTURE_H_
 
 #include "2D.h"
 #include <vector>
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <initguid.h>
 #include "DrawTargetD2D1.h"
 #include "FilterNodeSoftware.h"
 #include "GradientStopsD2D.h"
 #include "SourceSurfaceD2D1.h"
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWTARGETD2D1_H_
 #define MOZILLA_GFX_DRAWTARGETD2D1_H_
 
 #include "2D.h"
 #include <d3d11.h>
--- a/gfx/2d/DrawTargetDual.cpp
+++ b/gfx/2d/DrawTargetDual.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-  * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      
 #include "DrawTargetDual.h"
 #include "Tools.h"
 #include "Logging.h"
 
 namespace mozilla {
--- a/gfx/2d/DrawTargetDual.h
+++ b/gfx/2d/DrawTargetDual.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-  * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      
 #ifndef MOZILLA_GFX_DRAWTARGETDUAL_H_
 #define MOZILLA_GFX_DRAWTARGETDUAL_H_
      
 #include <vector>
 #include <sstream>
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetRecording.h"
 #include "PathRecording.h"
 #include <stdio.h>
 
 #include "Logging.h"
--- a/gfx/2d/DrawTargetRecording.h
+++ b/gfx/2d/DrawTargetRecording.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWTARGETRECORDING_H_
 #define MOZILLA_GFX_DRAWTARGETRECORDING_H_
 
 #include "2D.h"
 #include "DrawEventRecorder.h"
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetSkia.h"
 #include "SourceSurfaceSkia.h"
 #include "ScaledFontBase.h"
 #include "ScaledFontCairo.h"
 #include "FilterNodeSoftware.h"
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_SOURCESURFACESKIA_H
 #define _MOZILLA_GFX_SOURCESURFACESKIA_H
 
 #include "skia/include/core/SkCanvas.h"
 #include "skia/include/core/SkSurface.h"
--- a/gfx/2d/DrawTargetTiled.cpp
+++ b/gfx/2d/DrawTargetTiled.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetTiled.h"
 #include "Logging.h"
 #include "PathHelpers.h"
 
 using namespace std;
--- a/gfx/2d/DrawTargetTiled.h
+++ b/gfx/2d/DrawTargetTiled.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWTARGETTILED_H_
 #define MOZILLA_GFX_DRAWTARGETTILED_H_
 
 #include "2D.h"
 
--- a/gfx/2d/DrawTargetWrapAndRecord.cpp
+++ b/gfx/2d/DrawTargetWrapAndRecord.cpp
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawTargetWrapAndRecord.h"
 #include "PathRecording.h"
 #include <stdio.h>
 
 #include "Logging.h"
--- a/gfx/2d/DrawTargetWrapAndRecord.h
+++ b/gfx/2d/DrawTargetWrapAndRecord.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_DRAWTARGETWRAPANDRECORD_H_
 #define MOZILLA_GFX_DRAWTARGETWRAPANDRECORD_H_
 
 #include "2D.h"
 #include "DrawEventRecorder.h"
--- a/gfx/2d/DrawingJob.cpp
+++ b/gfx/2d/DrawingJob.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DrawingJob.h"
 #include "JobScheduler.h"
 #include "mozilla/gfx/2D.h"
 
 namespace mozilla {
--- a/gfx/2d/DrawingJob.h
+++ b/gfx/2d/DrawingJob.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_COMMANDBUFFER_H_
 #define MOZILLA_GFX_COMMANDBUFFER_H_
 
 #include <stdint.h>
 
--- a/gfx/2d/ExtendInputEffectD2D1.cpp
+++ b/gfx/2d/ExtendInputEffectD2D1.cpp
@@ -1,12 +1,13 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-  * This Source Code Form is subject to the terms of the Mozilla Public
-  * License, v. 2.0. If a copy of the MPL was not distributed with this
-  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ExtendInputEffectD2D1.h"
 
 #include "Logging.h"
 
 #include "ShadersD2D1.h"
 #include "HelpersD2D.h"
 
--- a/gfx/2d/ExtendInputEffectD2D1.h
+++ b/gfx/2d/ExtendInputEffectD2D1.h
@@ -1,12 +1,13 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-  * This Source Code Form is subject to the terms of the Mozilla Public
-  * License, v. 2.0. If a copy of the MPL was not distributed with this
-  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_EXTENDINPUTEFFECTD2D1_H_
 #define MOZILLA_GFX_EXTENDINPUTEFFECTD2D1_H_
 
 #include <d2d1_1.h>
 #include <d2d1effectauthor.h>
 #include <d2d1effecthelpers.h>
 
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -1,9 +1,10 @@
-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "Swizzle.h"
 
 #ifdef USE_CAIRO
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FilterNodeD2D1.h"
 
 #include "Logging.h"
 
 #include "SourceSurfaceD2D1.h"
--- a/gfx/2d/FilterNodeD2D1.h
+++ b/gfx/2d/FilterNodeD2D1.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_FILTERNODED2D1_H_
 #define MOZILLA_GFX_FILTERNODED2D1_H_
 
 #include "2D.h"
 #include "Filters.h"
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cmath>
 #include "DataSurfaceHelpers.h"
 #include "FilterNodeSoftware.h"
 #include "2D.h"
 #include "Tools.h"
--- a/gfx/2d/FilterNodeSoftware.h
+++ b/gfx/2d/FilterNodeSoftware.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_FILTERNODESOFTWARE_H_
 #define _MOZILLA_GFX_FILTERNODESOFTWARE_H_
 
 #include "Filters.h"
 #include <vector>
--- a/gfx/2d/FilterProcessing.cpp
+++ b/gfx/2d/FilterProcessing.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FilterProcessing.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/FilterProcessing.h
+++ b/gfx/2d/FilterProcessing.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_FILTERPROCESSING_H_
 #define _MOZILLA_GFX_FILTERPROCESSING_H_
 
 #include "2D.h"
 #include "Filters.h"
--- a/gfx/2d/FilterProcessingSIMD-inl.h
+++ b/gfx/2d/FilterProcessingSIMD-inl.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FilterProcessing.h"
 
 #include "SIMD.h"
 #include "SVGTurbulenceRenderer-inl.h"
 
--- a/gfx/2d/FilterProcessingSSE2.cpp
+++ b/gfx/2d/FilterProcessingSSE2.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define SIMD_COMPILE_SSE2
 
 #include "FilterProcessingSIMD-inl.h"
 
 #ifndef USE_SSE2
--- a/gfx/2d/FilterProcessingScalar.cpp
+++ b/gfx/2d/FilterProcessingScalar.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define FILTER_PROCESSING_SCALAR
 
 #include "FilterProcessingSIMD-inl.h"
 #include "Logging.h"
 
--- a/gfx/2d/Filters.h
+++ b/gfx/2d/Filters.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_FILTERS_H_
 #define MOZILLA_GFX_FILTERS_H_
 
 #include "Types.h"
 #include "mozilla/RefPtr.h"
--- a/gfx/2d/FontVariation.h
+++ b/gfx/2d/FontVariation.h
@@ -1,10 +1,11 @@
-/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_FONTVARIATION_H_
 #define MOZILLA_GFX_FONTVARIATION_H_
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/GenericRefCounted.h
+++ b/gfx/2d/GenericRefCounted.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This header provides virtual, non-templated alternatives to MFBT's RefCounted<T>.
 // It intentionally uses MFBT coding style with the intention of moving there
 // should there be other use cases for it.
 
 #ifndef MOZILLA_GENERICREFCOUNTED_H_
--- a/gfx/2d/GradientStopsD2D.h
+++ b/gfx/2d/GradientStopsD2D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_GRADIENTSTOPSD2D_H_
 #define MOZILLA_GFX_GRADIENTSTOPSD2D_H_
 
 #include "2D.h"
 
--- a/gfx/2d/Helpers.h
+++ b/gfx/2d/Helpers.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_2D_HELPERS_H_
 #define MOZILLA_GFX_2D_HELPERS_H_
 
 #include "2D.h"
 
--- a/gfx/2d/HelpersCairo.h
+++ b/gfx/2d/HelpersCairo.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_HELPERSCAIRO_H_
 #define MOZILLA_GFX_HELPERSCAIRO_H_
 
 #include "2D.h"
 #include "cairo.h"
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_HELPERSD2D_H_
 #define MOZILLA_GFX_HELPERSD2D_H_
 
 #include <d2d1_1.h>
 
--- a/gfx/2d/HelpersSkia.h
+++ b/gfx/2d/HelpersSkia.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_HELPERSSKIA_H_
 #define MOZILLA_GFX_HELPERSSKIA_H_
 
 #include "2D.h"
 #include "skia/include/core/SkCanvas.h"
--- a/gfx/2d/HelpersWinFonts.h
+++ b/gfx/2d/HelpersWinFonts.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxPrefs.h"
 
 namespace mozilla {
 namespace gfx {
 
--- a/gfx/2d/ImageScaling.cpp
+++ b/gfx/2d/ImageScaling.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageScaling.h"
 #include "2D.h"
 #include "DataSurfaceHelpers.h"
 
 #include <math.h>
--- a/gfx/2d/ImageScaling.h
+++ b/gfx/2d/ImageScaling.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_IMAGESCALING_H
 #define _MOZILLA_GFX_IMAGESCALING_H
 
 #include "Types.h"
 
--- a/gfx/2d/ImageScalingSSE2.cpp
+++ b/gfx/2d/ImageScalingSSE2.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageScaling.h"
 #include "mozilla/Attributes.h"
 
 #include "SSEHelpers.h"
 
--- a/gfx/2d/IterableArena.h
+++ b/gfx/2d/IterableArena.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_ITERABLEARENA_H_
 #define MOZILLA_GFX_ITERABLEARENA_H_
 
 #include "mozilla/Move.h"
 #include "mozilla/Assertions.h"
--- a/gfx/2d/JobScheduler.cpp
+++ b/gfx/2d/JobScheduler.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JobScheduler.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/JobScheduler.h
+++ b/gfx/2d/JobScheduler.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_TASKSCHEDULER_H_
 #define MOZILLA_GFX_TASKSCHEDULER_H_
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/gfx/Types.h"
--- a/gfx/2d/JobScheduler_posix.cpp
+++ b/gfx/2d/JobScheduler_posix.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JobScheduler.h"
 #include "mozilla/gfx/Logging.h"
 
 using namespace std;
 
--- a/gfx/2d/JobScheduler_posix.h
+++ b/gfx/2d/JobScheduler_posix.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WIN32
 #ifndef MOZILLA_GFX_TASKSCHEDULER_POSIX_H_
 #define MOZILLA_GFX_TASKSCHEDULER_POSIX_H_
 
 #include <string>
--- a/gfx/2d/JobScheduler_win32.cpp
+++ b/gfx/2d/JobScheduler_win32.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JobScheduler.h"
 #include "mozilla/gfx/Logging.h"
 
 using namespace std;
 
--- a/gfx/2d/JobScheduler_win32.h
+++ b/gfx/2d/JobScheduler_win32.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef WIN32
 #ifndef MOZILLA_GFX_TASKSCHEDULER_WIN32_H_
 #define MOZILLA_GFX_TASKSCHEDULER_WIN32_H_
 
 #include <windows.h>
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_LOGGING_H_
 #define MOZILLA_GFX_LOGGING_H_
 
 #include <string>
 #include <sstream>
--- a/gfx/2d/LoggingConstants.h
+++ b/gfx/2d/LoggingConstants.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_LOGGING_CONSTANTS_H_
 #define MOZILLA_GFX_LOGGING_CONSTANTS_H_
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/LuminanceNEON.cpp
+++ b/gfx/2d/LuminanceNEON.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <arm_neon.h>
 #include "LuminanceNEON.h"
 
 using namespace mozilla::gfx;
--- a/gfx/2d/LuminanceNEON.h
+++ b/gfx/2d/LuminanceNEON.h
@@ -1,12 +1,13 @@
-/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* this source code form is subject to the terms of the mozilla public
- * license, v. 2.0. if a copy of the mpl was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __LUMINANCENEON_H__
 #define __LUMINANCENEON_H__
 
 #include "mozilla/gfx/Point.h"
 
 void
 ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
--- a/gfx/2d/MacIOSurface.cpp
+++ b/gfx/2d/MacIOSurface.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-// vim:set ts=2 sts=2 sw=2 et cin:
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MacIOSurface.h"
 #include <OpenGL/gl.h>
 #include <QuartzCore/QuartzCore.h>
 #include <dlfcn.h>
--- a/gfx/2d/MacIOSurface.h
+++ b/gfx/2d/MacIOSurface.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-// vim:set ts=2 sts=2 sw=2 et cin:
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MacIOSurface_h__
 #define MacIOSurface_h__
 #ifdef XP_DARWIN
 #include <QuartzCore/QuartzCore.h>
--- a/gfx/2d/Matrix.cpp
+++ b/gfx/2d/Matrix.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Matrix.h"
 #include "Quaternion.h"
 #include "Tools.h"
 #include <algorithm>
 #include <ostream>
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_MATRIX_H_
 #define MOZILLA_GFX_MATRIX_H_
 
 #include "Types.h"
 #include "Triangle.h"
--- a/gfx/2d/MatrixFwd.h
+++ b/gfx/2d/MatrixFwd.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef MOZILLA_GFX_MATRIX_FWD_H_
 #define MOZILLA_GFX_MATRIX_FWD_H_
 
 
--- a/gfx/2d/NumericTools.h
+++ b/gfx/2d/NumericTools.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_NUMERICTOOLS_H_
 #define MOZILLA_GFX_NUMERICTOOLS_H_
 
 namespace mozilla {
 
--- a/gfx/2d/Path.cpp
+++ b/gfx/2d/Path.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "PathAnalysis.h"
 #include "PathHelpers.h"
 
 namespace mozilla {
--- a/gfx/2d/PathAnalysis.h
+++ b/gfx/2d/PathAnalysis.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include <vector>
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/2d/PathCairo.cpp
+++ b/gfx/2d/PathCairo.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PathCairo.h"
 #include <math.h>
 #include "DrawTargetCairo.h"
 #include "Logging.h"
 #include "PathHelpers.h"
--- a/gfx/2d/PathCairo.h
+++ b/gfx/2d/PathCairo.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_PATH_CAIRO_H_
 #define MOZILLA_GFX_PATH_CAIRO_H_
 
 #include "2D.h"
 #include "cairo.h"
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PathD2D.h"
 #include "HelpersD2D.h"
 #include <math.h>
 #include "DrawTargetD2D1.h"
 #include "Logging.h"
--- a/gfx/2d/PathD2D.h
+++ b/gfx/2d/PathD2D.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_PATHD2D_H_
 #define MOZILLA_GFX_PATHD2D_H_
 
 #include <d2d1.h>
 
--- a/gfx/2d/PathHelpers.cpp
+++ b/gfx/2d/PathHelpers.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PathHelpers.h"
 
 namespace mozilla {
 namespace gfx {
 
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_PATHHELPERS_H_
 #define MOZILLA_GFX_PATHHELPERS_H_
 
 #include "2D.h"
 #include "UserData.h"
--- a/gfx/2d/PathRecording.cpp
+++ b/gfx/2d/PathRecording.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PathRecording.h"
 #include "DrawEventRecorder.h"
 #include "RecordedEventImpl.h"
 
 namespace mozilla {
--- a/gfx/2d/PathRecording.h
+++ b/gfx/2d/PathRecording.h
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_PATHRECORDING_H_
 #define MOZILLA_GFX_PATHRECORDING_H_
 
 #include "2D.h"
 #include <vector>
--- a/gfx/2d/PathSkia.cpp
+++ b/gfx/2d/PathSkia.cpp
@@ -1,10 +1,11 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PathSkia.h"
 #include <math.h>
 #include "DrawTargetSkia.h"
 #include "Logging.h"
 #include "HelpersSkia.h"
--- a/gfx/2d/PathSkia.h
+++ b/gfx/2d/PathSkia.h
@@ -1,10 +1,11 @@