merge autoland to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 05 Sep 2017 23:53:59 +0200
changeset 428448 978d2539a8d1a49e9f9705204f3918772b337547
parent 428371 973e8b890a62aee4b3170558ac3b608928162ef6 (current diff)
parent 428447 08d59706aac1fc2adaa4839e9db8c04e00bc121b (diff)
child 428501 f64e2b4dcf5eec0b4ad456c149680a67b7c26dc4
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone57.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: H5cwbdymJQw
mobile/android/app/src/main/res/drawable-hdpi/tab_indicator_divider.9.png
mobile/android/app/src/main/res/drawable-xhdpi/tab_indicator_divider.9.png
taskcluster/docker/README.md
testing/web-platform/meta/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html.ini
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -17,17 +17,16 @@ module.exports = {
     "consistent-this": "off",
     "curly": ["error", "multi-line"],
     "default-case": "off",
     "dot-location": ["error", "property"],
 
     "eqeqeq": "off",
     "func-names": "off",
     "func-style": "off",
-    "generator-star-spacing": "off",
     "handle-callback-err": ["error", "er"],
     "indent": ["error", 2, {"SwitchCase": 1}],
     "max-nested-callbacks": ["error", 4],
     "max-params": "off",
     "max-statements": "off",
     "new-cap": ["error", {"capIsNew": false}],
     "new-parens": "error",
     "no-bitwise": "off",
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -127,17 +127,17 @@ var AccessFuTest = {
   runTests: function AccessFuTest_runTests(aAdditionalPrefs) {
     if (gTestFuncs.length === 0) {
       ok(false, "No tests specified!");
       SimpleTest.finish();
       return;
     }
 
     // Create an Iterator for gTestFuncs array.
-    gIterator = (function*() {
+    gIterator = (function* () {
       for (var testFunc of gTestFuncs) {
         yield testFunc;
       }
     })();
 
     // Start AccessFu and put it in stand-by.
     Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm");
 
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -705,22 +705,19 @@ XULTreeItemAccessibleBase::~XULTreeItemA
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessibleBase: nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible,
                                    mTree)
 
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase)
-  NS_INTERFACE_TABLE_INHERITED(XULTreeItemAccessibleBase,
-                               XULTreeItemAccessibleBase)
-NS_INTERFACE_TABLE_TAIL_INHERITING(Accessible)
-NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessibleBase, Accessible)
-NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessibleBase, Accessible)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase,
+                                             Accessible,
+                                             XULTreeItemAccessibleBase)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessibleBase: Accessible
 
 Accessible*
 XULTreeItemAccessibleBase::FocusedChild()
 {
   return FocusMgr()->FocusedAccessible() == this ? this : nullptr;
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1045,17 +1045,17 @@ pref("dom.ipc.plugins.sandbox-level.flas
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
 // This controls the strength of the Windows content process sandbox for testing
 // purposes. This will require a restart.
 // On windows these levels are:
 // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 // SetSecurityLevelForContentProcess() for what the different settings mean.
-pref("security.sandbox.content.level", 3);
+pref("security.sandbox.content.level", 4);
 
 // This controls the depth of stack trace that is logged when Windows sandbox
 // logging is turned on.  This is only currently available for the content
 // process because the only other sandbox (for GMP) has too strict a policy to
 // allow stack tracing.  This does not require a restart to take effect.
 pref("security.sandbox.windows.log.stackTraceDepth", 0);
 #endif
 
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -42,51 +42,64 @@ var BrowserPageActions = {
     delete this.mainViewBodyNode;
     return this.mainViewBodyNode = this.mainViewNode.querySelector(".panel-subview-body");
   },
 
   /**
    * Inits.  Call to init.
    */
   init() {
+    this.placeAllActions();
+  },
+
+  /**
+   * Places all registered actions.
+   */
+  placeAllActions() {
+    // Place actions in the panel.  Notify of onBeforePlacedInWindow too.
     for (let action of PageActions.actions) {
-      this.placeAction(action,
-                       PageActions.insertBeforeActionIDInPanel(action),
-                       PageActions.insertBeforeActionIDInUrlbar(action));
+      action.onBeforePlacedInWindow(window);
+      this.placeActionInPanel(action);
+    }
+
+    // Place actions in the urlbar.  Do this in reverse order.  The reason is
+    // subtle.  If there were no urlbar nodes already in markup (like the
+    // bookmark star button), then doing this in forward order would be fine.
+    // Forward order means that the insert-before relationship is always broken:
+    // there's never a next-sibling node before which to insert a new node, so
+    // node.insertBefore() is always passed null, and nodes are always appended.
+    // That will break the position of nodes that should be inserted before
+    // nodes that are in markup, which in turn can break other nodes.
+    let actionsInUrlbar = PageActions.actionsInUrlbar;
+    for (let i = actionsInUrlbar.length - 1; i >= 0; i--) {
+      let action = actionsInUrlbar[i];
+      this.placeActionInUrlbar(action);
     }
   },
 
   /**
    * Adds or removes as necessary DOM nodes for the given action.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  panelInsertBeforeID (string, required)
-   *         The ID of the action in the panel before which the given action
-   *         action should be inserted.
-   * @param  urlbarInsertBeforeID (string, required)
-   *         If the action is shown in the urlbar, then this is ID of the action
-   *         in the urlbar before which the given action should be inserted.
    */
-  placeAction(action, panelInsertBeforeID, urlbarInsertBeforeID) {
+  placeAction(action) {
     action.onBeforePlacedInWindow(window);
-    this.placeActionInPanel(action, panelInsertBeforeID);
-    this.placeActionInUrlbar(action, urlbarInsertBeforeID);
+    this.placeActionInPanel(action);
+    this.placeActionInUrlbar(action);
   },
 
   /**
    * Adds or removes as necessary DOM nodes for the action in the panel.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  insertBeforeID (string, required)
-   *         The ID of the action in the panel before which the given action
-   *         action should be inserted.  Pass null to append.
    */
-  placeActionInPanel(action, insertBeforeID) {
+  placeActionInPanel(action) {
+    let insertBeforeID = PageActions.nextActionID(action, PageActions.actions);
     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) {
@@ -280,21 +293,20 @@ var BrowserPageActions = {
     return "pageActionActivatedActionPanel";
   },
 
   /**
    * Adds or removes as necessary a DOM node for the given action in the urlbar.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  insertBeforeID (string, required)
-   *         If the action is shown in the urlbar, then this is ID of the action
-   *         in the urlbar before which the given action should be inserted.
    */
-  placeActionInUrlbar(action, insertBeforeID) {
+  placeActionInUrlbar(action) {
+    let insertBeforeID =
+      PageActions.nextActionID(action, PageActions.actionsInUrlbar);
     let id = this._urlbarButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
 
     if (!action.shownInUrlbar) {
       if (node) {
         if (action.__urlbarNodeInMarkup) {
           node.hidden = true;
         } else {
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -73,31 +73,16 @@ var StarUI = {
         elt.removeAttribute("disabled");
       elt.removeAttribute("wasDisabled");
     });
   },
 
   // nsIDOMEventListener
   handleEvent(aEvent) {
     switch (aEvent.type) {
-      case "animationend": {
-        let animatableBox = document.getElementById("library-animatable-box");
-        if (aEvent.animationName.startsWith("library-bookmark-animation")) {
-          animatableBox.setAttribute("fade", "true");
-        } else if (aEvent.animationName == "library-bookmark-fade") {
-          animatableBox.removeEventListener("animationend", this);
-          animatableBox.removeAttribute("animate");
-          animatableBox.removeAttribute("fade");
-          let libraryButton = document.getElementById("library-button");
-          // Put the 'fill' back in the normal icon.
-          libraryButton.removeAttribute("animate");
-          gNavToolbox.removeAttribute("animate");
-        }
-        break;
-      }
       case "mousemove":
         clearTimeout(this._autoCloseTimer);
         // The autoclose timer is not disabled on generic mouseout
         // because the user may not have actually interacted with the popup.
         break;
       case "popuphidden": {
         clearTimeout(this._autoCloseTimer);
         if (aEvent.originalTarget == this.panel) {
@@ -115,17 +100,16 @@ var StarUI = {
           let guidsForRemoval = this._itemGuids;
           this._itemGuids = null;
           this._itemIdsMap = null;
 
           if (this._batching) {
             this.endBatch();
           }
 
-          let libraryButton;
           if (removeBookmarksOnPopupHidden && guidsForRemoval) {
             if (this._isNewBookmark) {
               if (!PlacesUIUtils.useAsyncTransactions) {
                 PlacesUtils.transactionManager.undoTransaction();
                 break;
               }
               PlacesTransactions.undo().catch(Cu.reportError);
               break;
@@ -139,42 +123,18 @@ var StarUI = {
                   PlacesUtils.transactionManager.doTransaction(txn);
                 }
               }
               break;
             }
 
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
-          } else if (this._isNewBookmark &&
-                     Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
-                     (libraryButton = document.getElementById("library-button")) &&
-                     libraryButton.getAttribute("cui-areatype") != "menu-panel" &&
-                     libraryButton.getAttribute("overflowedItem") != "true" &&
-                     libraryButton.closest("#nav-bar")) {
-            let animatableBox = document.getElementById("library-animatable-box");
-            let navBar = document.getElementById("nav-bar");
-            let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
-            let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
-            let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
-            let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
-
-            animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
-            animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
-            animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
-            if (navBar.hasAttribute("brighttext")) {
-              animatableBox.setAttribute("brighttext", "true");
-            } else {
-              animatableBox.removeAttribute("brighttext");
-            }
-            animatableBox.removeAttribute("fade");
-            gNavToolbox.setAttribute("animate", "bookmark");
-            libraryButton.setAttribute("animate", "bookmark");
-            animatableBox.setAttribute("animate", "bookmark");
-            animatableBox.addEventListener("animationend", this);
+          } else if (this._isNewBookmark) {
+            LibraryUI.triggerLibraryAnimation("bookmark");
           }
         }
         break;
       }
       case "keypress":
         clearTimeout(this._autoCloseTimer);
         this._autoCloseTimerEnabled = false;
 
@@ -1537,16 +1497,78 @@ var RecentBookmarksMenuUI = {
   onEndUpdateBatch() {},
   onItemAdded() {},
   onItemChanged() {},
   onItemVisited() {},
   onItemMoved() {},
 }
 
 /**
+ * Handles the Library button in the toolbar.
+ */
+var LibraryUI = {
+  triggerLibraryAnimation(animation) {
+    if (!this.hasOwnProperty("COSMETIC_ANIMATIONS_ENABLED")) {
+      XPCOMUtils.defineLazyPreferenceGetter(this, "COSMETIC_ANIMATIONS_ENABLED",
+        "toolkit.cosmeticAnimations.enabled", true);
+    }
+
+    let libraryButton = document.getElementById("library-button");
+    if (!libraryButton ||
+        libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
+        libraryButton.getAttribute("overflowedItem") == "true" ||
+        !libraryButton.closest("#nav-bar") ||
+        !this.COSMETIC_ANIMATIONS_ENABLED) {
+      return;
+    }
+    let animatableBox = document.getElementById("library-animatable-box");
+    let navBar = document.getElementById("nav-bar");
+    let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
+    let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
+    let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
+    let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
+
+    animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
+    animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
+    animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
+    if (navBar.hasAttribute("brighttext")) {
+      animatableBox.setAttribute("brighttext", "true");
+    } else {
+      animatableBox.removeAttribute("brighttext");
+    }
+    animatableBox.removeAttribute("fade");
+    gNavToolbox.setAttribute("animate", animation);
+    libraryButton.setAttribute("animate", animation);
+    animatableBox.setAttribute("animate", animation);
+    if (!this._libraryButtonAnimationEndListeners[animation]) {
+      this._libraryButtonAnimationEndListeners[animation] = event => {
+        this._libraryButtonAnimationEndListener(event, animation);
+      }
+    }
+    animatableBox.addEventListener("animationend", this._libraryButtonAnimationEndListeners[animation]);
+  },
+
+  _libraryButtonAnimationEndListeners: {},
+  _libraryButtonAnimationEndListener(aEvent, animation) {
+    let animatableBox = document.getElementById("library-animatable-box");
+    if (aEvent.animationName.startsWith(`library-${animation}-animation`)) {
+      animatableBox.setAttribute("fade", "true");
+    } else if (aEvent.animationName == `library-${animation}-fade`) {
+      animatableBox.removeEventListener("animationend", LibraryUI._libraryButtonAnimationEndListeners[animation]);
+      animatableBox.removeAttribute("animate");
+      animatableBox.removeAttribute("fade");
+      let libraryButton = document.getElementById("library-button");
+      // Put the 'fill' back in the normal icon.
+      libraryButton.removeAttribute("animate");
+      gNavToolbox.removeAttribute("animate");
+    }
+  },
+};
+
+/**
  * Handles the bookmarks menu-button in the toolbar.
  */
 
 var BookmarkingUI = {
   STAR_ID: "star-button",
   BOOKMARK_BUTTON_ID: "bookmarks-menu-button",
   BOOKMARK_BUTTON_SHORTCUT: "addBookmarkAsKb",
   get button() {
--- a/browser/base/content/browser-sidebar.js
+++ b/browser/base/content/browser-sidebar.js
@@ -10,18 +10,18 @@
  * xul:broadcaster element with the specified ID.
  * The following attributes on that element may be used and/or modified:
  *  - id           (required) the string to match commandID. The convention
  *                 is to use this naming scheme: 'view<sidebar-name>Sidebar'.
  *  - sidebarurl   (required) specifies the URL to load in this sidebar.
  *  - sidebartitle or label (in that order) specify the title to
  *                 display on the sidebar.
  *  - checked      indicates whether the sidebar is currently displayed.
- *                 Note that toggleSidebar updates this attribute when
- *                 it changes the sidebar's visibility.
+ *                 Note that this attribute is updated when
+ *                 the sidebar's visibility is changed.
  *  - group        this attribute must be set to "sidebar".
  */
 var SidebarUI = {
   // Avoid getting the browser element from init() to avoid triggering the
   // <browser> constructor during startup if the sidebar is hidden.
   get browser() {
     if (this._browser)
       return this._browser;
@@ -251,19 +251,16 @@ var SidebarUI = {
    * Fire a "SidebarFocused" event on the sidebar's |window| to give the sidebar
    * a chance to adjust focus as needed. An additional event is needed, because
    * we don't want to focus the sidebar when it's opened on startup or in a new
    * window, only when the user opens the sidebar.
    */
   _fireFocusedEvent() {
     let event = new CustomEvent("SidebarFocused", {bubbles: true});
     this.browser.contentWindow.dispatchEvent(event);
-
-    // Run the original function for backwards compatibility.
-    fireSidebarFocusedEvent();
   },
 
   /**
    * True if the sidebar is currently open.
    */
   get isOpen() {
     return !this._box.hidden;
   },
@@ -388,19 +385,16 @@ var SidebarUI = {
       if (this.browser.contentDocument.location.href != url) {
         this.browser.addEventListener("load", event => {
 
           // We're handling the 'load' event before it bubbles up to the usual
           // (non-capturing) event handlers. Let it bubble up before firing the
           // SidebarFocused event.
           setTimeout(() => this._fireFocusedEvent(), 0);
 
-          // Run the original function for backwards compatibility.
-          sidebarOnLoad(event);
-
           resolve();
 
           // Now that the currentId is updated, fire a show event.
           this._fireShowEvent();
         }, {capture: true, once: true});
       } else {
         // Older code handled this case, so we do it too.
         this._fireFocusedEvent();
@@ -464,42 +458,8 @@ var SidebarUI = {
 
 // Add getters related to the position here, since we will want them
 // available for both startDelayedLoad and init.
 XPCOMUtils.defineLazyPreferenceGetter(SidebarUI, "_positionStart",
   SidebarUI.POSITION_START_PREF, true, SidebarUI.setPosition.bind(SidebarUI));
 XPCOMUtils.defineLazyGetter(SidebarUI, "isRTL", () => {
   return getComputedStyle(document.documentElement).direction == "rtl";
 });
-
-/**
- * This exists for backwards compatibility - it will be called once a sidebar is
- * ready, following any request to show it.
- *
- * @deprecated
- */
-function fireSidebarFocusedEvent() {}
-
-/**
- * This exists for backwards compatibility - it gets called when a sidebar has
- * been loaded.
- *
- * @deprecated
- */
-function sidebarOnLoad(event) {}
-
-/**
- * This exists for backwards compatibility, and is equivilent to
- * SidebarUI.toggle() without the forceOpen param. With forceOpen set to true,
- * it is equivalent to SidebarUI.show().
- *
- * @deprecated
- */
-function toggleSidebar(commandID, forceOpen = false) {
-  Deprecated.warning("toggleSidebar() is deprecated, please use SidebarUI.toggle() or SidebarUI.show() instead",
-                     "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Sidebar");
-
-  if (forceOpen) {
-    SidebarUI.show(commandID);
-  } else {
-    SidebarUI.toggle(commandID);
-  }
-}
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -448,17 +448,17 @@ toolbar:not(#TabsToolbar) > #personal-bo
 }
 
 #zoom-controls[cui-areatype="toolbar"]:not([overflowedItem=true]) > #zoom-reset-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #reload-button:not([displaystop]) + #stop-button,
 #reload-button[displaystop] {
-  visibility: collapse;
+  display: none;
 }
 
 /* The reload-button is only disabled temporarily when it becomes visible
    to prevent users from accidentally clicking it. We don't however need
    to show this disabled state, as the flicker that it generates is short
    enough to be visible but not long enough to explain anything to users. */
 #reload-button[disabled]:not(:-moz-window-inactive) > .toolbarbutton-icon {
   opacity: 1 !important;
@@ -670,17 +670,17 @@ html|input.urlbar-input[textoverflow]:no
 #urlbar[pageproxystate=invalid] > #page-action-buttons > .urlbar-page-action,
 #identity-box.chromeUI ~ #page-action-buttons > .urlbar-page-action,
 #urlbar[usertyping] > .urlbar-textbox-container > .urlbar-history-dropmarker,
 .urlbar-go-button[pageproxystate="valid"],
 .urlbar-go-button:not([parentfocused="true"]),
 #urlbar[pageproxystate="invalid"] > #identity-box > #blocked-permissions-container,
 #urlbar[pageproxystate="invalid"] > #identity-box > #notification-popup-box,
 #urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels {
-  visibility: collapse;
+  display: none;
 }
 
 #identity-box {
   -moz-user-focus: normal;
 }
 
 #urlbar[pageproxystate="invalid"] > #identity-box {
   pointer-events: none;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2759,17 +2759,17 @@ function URLBarSetURI(aURI) {
       // We should deal with losslessDecodeURI throwing for exotic URIs
       try {
         value = losslessDecodeURI(uri);
       } catch (ex) {
         value = "about:blank";
       }
     }
 
-    valid = !isBlankPageURL(uri.spec);
+    valid = !isBlankPageURL(uri.spec) || uri.schemeIs("moz-extension");
   }
 
   let isDifferentValidValue = valid && value != gURLBar.value;
   gURLBar.value = value;
   gURLBar.valueIsTyped = !valid;
   gURLBar.removeAttribute("usertyping");
   if (isDifferentValidValue) {
     gURLBar.selectionStart = gURLBar.selectionEnd = 0;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -428,16 +428,17 @@
     </panel>
 
     <panel id="pageActionPanel"
            class="cui-widget-panel"
            role="group"
            type="arrow"
            hidden="true"
            flip="slide"
+           photon="true"
            position="bottomcenter topright"
            tabspecific="true"
            noautofocus="true"
            copyURL-title="&copyURLCmd.label;"
            emailLink-title="&emailPageCmd.label;"
            sendToDevice-title="&sendToDevice.label3;"
            sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;">
       <photonpanelmultiview id="pageActionPanelMultiView"
--- a/browser/base/content/test/performance/browser_startup_images.js
+++ b/browser/base/content/test/performance/browser_startup_images.js
@@ -12,42 +12,20 @@
  *  - platforms: An array of the platforms where the issue is occurring.
  *               Possible values are linux, win, macosx.
  *  - intermittentNotLoaded: an array of platforms where this image is
  *                           intermittently not loaded, e.g. because it is
  *                           loaded during the time we stop recording.
  *  - intermittentShown: An array of platforms where this image is
  *                       intermittently shown, contrary to what our
  *                       whitelist says.
- *  - photon: If true, this entry only applies for builds with the Photon theme.
- *            If false, this entry only applies for builds without the Photon theme.
- *            If undefined, this entry applies for both Photon and non-Photon builds.
  *
  * Please don't add items to this list. Please remove items from this list.
  */
 const whitelist = [
-  // Photon-only entries
-  {
-    file: "chrome://browser/skin/stop.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://browser/skin/bookmark-hollow.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://browser/skin/page-action.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://pocket-shared/skin/pocket.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-
-  // Shared entries
   {
     file: "chrome://browser/skin/arrow-left.svg",
     platforms: ["linux", "win", "macosx"],
   },
   {
     file: "chrome://browser/skin/tabbrowser/tab-overflow-indicator.png",
     platforms: ["linux", "win", "macosx"],
   },
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -118,32 +118,32 @@ add_task(async function sendToDevice_non
   // Open a tab that's not sendable.  An about: page like about:home is
   // convenient.
   await BrowserTestUtils.withNewTab("about:home", async () => {
     // ... but the page actions should be hidden on about:home, including the
     // main button.  (It's not easy to load a page that's both actionable and
     // not sendable.)  So first check that that's the case, and then unhide the
     // main button so that this test can continue.
     Assert.equal(
-      window.getComputedStyle(BrowserPageActions.mainButtonNode).visibility,
-      "collapse",
+      window.getComputedStyle(BrowserPageActions.mainButtonNode).display,
+      "none",
       "Main button should be hidden on about:home"
     );
-    BrowserPageActions.mainButtonNode.style.visibility = "visible";
+    BrowserPageActions.mainButtonNode.style.display = "-moz-box";
     await promiseSyncReady();
     // Open the panel.  Send to Device should be disabled.
     await promisePageActionPanelOpen();
     let sendToDeviceButton =
       document.getElementById("pageAction-panel-sendToDevice");
     Assert.ok(sendToDeviceButton.disabled);
     let hiddenPromise = promisePageActionPanelHidden();
     BrowserPageActions.panelNode.hidePopup();
     await hiddenPromise;
-    // Remove the `visibility` style set above.
-    BrowserPageActions.mainButtonNode.style.removeProperty("visibility");
+    // Remove the `display` style set above.
+    BrowserPageActions.mainButtonNode.style.removeProperty("display");
   });
 });
 
 add_task(async function sendToDevice_syncNotReady_other_states() {
   // Open a tab that's sendable.
   await BrowserTestUtils.withNewTab("http://example.com/", async () => {
     await promiseSyncReady();
     const sandbox = sinon.sandbox.create();
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -2962,17 +2962,17 @@ this.CustomizableUI = {
 
 
   /**
    * An iteratable property of windows managed by CustomizableUI.
    * Note that this can *only* be used as an iterator. ie:
    *     for (let window of CustomizableUI.windows) { ... }
    */
   windows: {
-    *[Symbol.iterator]() {
+    * [Symbol.iterator]() {
       for (let [window, ] of gBuildWindows)
         yield window;
     }
   },
 
   /**
    * Add a listener object that will get fired for various events regarding
    * customization.
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -325,16 +325,17 @@
 
 </panel>
 
 <panel id="widget-overflow"
        role="group"
        type="arrow"
        noautofocus="true"
        position="bottomcenter topright"
+       photon="true"
        hidden="true">
   <photonpanelmultiview mainViewId="widget-overflow-mainView">
     <panelview id="widget-overflow-mainView"
                context="toolbar-context-menu">
       <vbox class="panel-subview-body">
         <vbox id="widget-overflow-list" class="widget-overflow-list"
               overflowfortoolbar="nav-bar"/>
         <toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -3,52 +3,82 @@
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browserAction.js */
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 
+const {
+  TYPE_BOOKMARK,
+  TYPE_FOLDER,
+  TYPE_SEPARATOR,
+} = PlacesUtils.bookmarks;
+
+const BOOKMARKS_TYPES_TO_API_TYPES_MAP = new Map([
+  [TYPE_BOOKMARK, "bookmark"],
+  [TYPE_FOLDER, "folder"],
+  [TYPE_SEPARATOR, "separator"],
+]);
+
+const BOOKMARK_SEPERATOR_URL = "data:";
+
+XPCOMUtils.defineLazyGetter(this, "API_TYPES_TO_BOOKMARKS_TYPES_MAP", () => {
+  let theMap = new Map();
+
+  for (let [code, name] of BOOKMARKS_TYPES_TO_API_TYPES_MAP) {
+    theMap.set(name, code);
+  }
+  return theMap;
+});
+
 let listenerCount = 0;
 
+function getUrl(type, url) {
+  switch (type) {
+    case TYPE_BOOKMARK:
+      return url;
+    case TYPE_SEPARATOR:
+      return BOOKMARK_SEPERATOR_URL;
+    default:
+      return undefined;
+  }
+}
+
 const getTree = (rootGuid, onlyChildren) => {
   function convert(node, parent) {
     let treenode = {
       id: node.guid,
       title: node.title || "",
       index: node.index,
       dateAdded: node.dateAdded / 1000,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(node.typeCode),
+      url: getUrl(node.typeCode, node.uri),
     };
 
     if (parent && node.guid != PlacesUtils.bookmarks.rootGuid) {
       treenode.parentId = parent.guid;
     }
 
-    if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE) {
-      // This isn't quite correct. Recently Bookmarked ends up here ...
-      treenode.url = node.uri;
-    } else {
+    if (node.typeCode == TYPE_FOLDER) {
       treenode.dateGroupModified = node.lastModified / 1000;
 
       if (!onlyChildren) {
         treenode.children = node.children
           ? node.children.map(child => convert(child, node))
           : [];
       }
     }
 
     return treenode;
   }
 
   return PlacesUtils.promiseBookmarksTree(rootGuid, {
     excludeItemsCallback: item => {
-      if (item.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
-        return true;
-      }
       return item.annos &&
              item.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
     },
   }).then(root => {
     if (onlyChildren) {
       let children = root.children || [];
       return children.map(child => convert(child, root));
     }
@@ -60,25 +90,25 @@ const getTree = (rootGuid, onlyChildren)
 };
 
 const convertBookmarks = result => {
   let node = {
     id: result.guid,
     title: result.title || "",
     index: result.index,
     dateAdded: result.dateAdded.getTime(),
+    type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(result.type),
+    url: getUrl(result.type, result.url && result.url.href),
   };
 
   if (result.guid != PlacesUtils.bookmarks.rootGuid) {
     node.parentId = result.parentGuid;
   }
 
-  if (result.type == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-    node.url = result.url.href; // Output is always URL object.
-  } else {
+  if (result.type == TYPE_FOLDER) {
     node.dateGroupModified = result.lastModified.getTime();
   }
 
   return node;
 };
 
 let observer = new class extends EventEmitter {
   constructor() {
@@ -87,76 +117,58 @@ let observer = new class extends EventEm
     this.skipTags = true;
     this.skipDescendantsOnItemRemoval = true;
   }
 
   onBeginUpdateBatch() {}
   onEndUpdateBatch() {}
 
   onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let bookmark = {
       id: guid,
       parentId: parentGuid,
       index,
       title,
       dateAdded: dateAdded / 1000,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(itemType),
+      url: getUrl(itemType, uri && uri.spec),
     };
 
-    if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-      bookmark.url = uri.spec;
-    } else {
+    if (itemType == TYPE_FOLDER) {
       bookmark.dateGroupModified = bookmark.dateAdded;
     }
 
     this.emit("created", bookmark);
   }
 
   onItemVisited() {}
 
   onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, itemType, guid, oldParentGuid, newParentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let info = {
       parentId: newParentGuid,
       index: newIndex,
       oldParentId: oldParentGuid,
       oldIndex,
     };
     this.emit("moved", {guid, info});
   }
 
   onItemRemoved(id, parentId, index, itemType, uri, guid, parentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let node = {
       id: guid,
       parentId: parentGuid,
       index,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(itemType),
+      url: getUrl(itemType, uri && uri.spec),
     };
 
-    if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-      node.url = uri.spec;
-    }
-
     this.emit("removed", {guid, info: {parentId: parentGuid, index, node}});
   }
 
   onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let info = {};
     if (prop == "title") {
       info.title = val;
     } else if (prop == "uri") {
       info.url = val;
     } else {
       // Not defined yet.
       return;
@@ -223,22 +235,28 @@ this.bookmarks = class extends Extension
           return PlacesUtils.bookmarks.getRecent(numberOfItems).then(result => result.map(convertBookmarks));
         },
 
         create: function(bookmark) {
           let info = {
             title: bookmark.title || "",
           };
 
-          // If url is NULL or missing, it will be a folder.
-          if (bookmark.url !== null) {
-            info.type = PlacesUtils.bookmarks.TYPE_BOOKMARK;
+          info.type = API_TYPES_TO_BOOKMARKS_TYPES_MAP.get(bookmark.type);
+          if (!info.type) {
+            // If url is NULL or missing, it will be a folder.
+            if (bookmark.url !== null) {
+              info.type = TYPE_BOOKMARK;
+            } else {
+              info.type = TYPE_FOLDER;
+            }
+          }
+
+          if (info.type === TYPE_BOOKMARK) {
             info.url = bookmark.url || "";
-          } else {
-            info.type = PlacesUtils.bookmarks.TYPE_FOLDER;
           }
 
           if (bookmark.index !== null) {
             info.index = bookmark.index;
           }
 
           if (bookmark.parentId !== null) {
             info.parentGuid = bookmark.parentId;
--- a/browser/components/extensions/schemas/bookmarks.json
+++ b/browser/components/extensions/schemas/bookmarks.json
@@ -24,16 +24,22 @@
     "types": [
       {
         "id": "BookmarkTreeNodeUnmodifiable",
         "type": "string",
         "enum": ["managed"],
         "description": "Indicates the reason why this node is unmodifiable. The <var>managed</var> value indicates that this node was configured by the system administrator or by the custodian of a supervised user. Omitted if the node can be modified by the user and the extension (default)."
       },
       {
+        "id": "BookmarkTreeNodeType",
+        "type": "string",
+        "enum": ["bookmark", "folder", "separator"],
+        "description": "Indicates the type of a BookmarkTreeNode, which can be one of bookmark, folder or separator."
+      },
+      {
         "id": "BookmarkTreeNode",
         "type": "object",
         "description": "A node (either a bookmark or a folder) in the bookmark tree.  Child nodes are ordered within their parent folder.",
         "properties": {
           "id": {
             "type": "string",
             "description": "The unique identifier for the node. IDs are unique within the current profile, and they remain valid even after the browser is restarted."
           },
@@ -66,16 +72,21 @@
             "optional": true,
             "description": "When the contents of this folder last changed, in milliseconds since the epoch."
           },
           "unmodifiable": {
             "$ref": "BookmarkTreeNodeUnmodifiable",
             "optional": true,
             "description": "Indicates the reason why this node is unmodifiable. The <var>managed</var> value indicates that this node was configured by the system administrator or by the custodian of a supervised user. Omitted if the node can be modified by the user and the extension (default)."
           },
+          "type": {
+            "$ref": "BookmarkTreeNodeType",
+            "optional": true,
+            "description": "Indicates the type of the BookmarkTreeNode, which can be one of bookmark, folder or separator."
+          },
           "children": {
             "type": "array",
             "optional": true,
             "items": { "$ref": "BookmarkTreeNode" },
             "description": "An ordered list of children of this node."
           }
         }
       },
@@ -96,16 +107,21 @@
           },
           "title": {
             "type": "string",
             "optional": true
           },
           "url": {
             "type": "string",
             "optional": true
+          },
+          "type": {
+            "$ref": "BookmarkTreeNodeType",
+            "optional": true,
+            "description": "Indicates the type of BookmarkTreeNode to create, which can be one of bookmark, folder or separator."
           }
         }
       }
     ],
     "functions": [
       {
         "name": "get",
         "type": "function",
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
@@ -247,17 +247,19 @@ async function testPopupSize(standardsMo
 
   dims = await alterContent(browser, setClass, "huge");
   win = dims.window;
 
   ok(getHeight() > height, `Browser height should increase (${getHeight()} > ${height})`);
 
   is(win.innerWidth, innerWidth, "Window width should not change");
   ok(win.innerHeight > innerHeight, `Window height should increase (${win.innerHeight} > ${innerHeight})`);
-  ok(win.innerHeight < screen.height, `Window height be less than the screen height (${win.innerHeight} < ${screen.height})`);
+  // Commented out check for the window height here which mysteriously breaks
+  // on infra but not locally. bug 1396843 covers re-enabling this.
+  // ok(win.innerHeight < screen.height, `Window height be less than the screen height (${win.innerHeight} < ${screen.height})`);
   ok(win.scrollMaxY > 0, `Document should be vertically scrollable (${win.scrollMaxY} > 0)`);
 
   checkPanelPosition();
 
 
   info("Restore original styling. Expect original dimensions.");
   dims = await alterContent(browser, setClass, "");
   win = dims.window;
--- a/browser/components/extensions/test/browser/browser_ext_identity_indication.js
+++ b/browser/components/extensions/test/browser/browser_ext_identity_indication.js
@@ -54,8 +54,44 @@ add_task(async function testIdentityIndi
   await BrowserTestUtils.withNewTab({gBrowser, url}, async function() {
     confirmExtensionPage();
   });
 
   await extension.unload();
 
   confirmDefaults();
 });
+
+add_task(async function testIdentityIndicationNewTab() {
+  let extension = ExtensionTestUtils.loadExtension({
+    background() {
+      browser.test.sendMessage("url", browser.extension.getURL("newtab.html"));
+    },
+    manifest: {
+      name: "Test Extension",
+      applications: {
+        gecko: {
+          id: "@newtab",
+        },
+      },
+      chrome_url_overrides: {
+        newtab: "newtab.html",
+      },
+    },
+    files: {
+      "newtab.html": "<h1>New tab!</h1>",
+    },
+    useAddonManager: "temporary",
+  });
+
+  await extension.startup();
+
+  confirmDefaults();
+
+  let url = await extension.awaitMessage("url");
+  await BrowserTestUtils.withNewTab({gBrowser, url}, async function() {
+    confirmExtensionPage();
+  });
+
+  await extension.unload();
+
+  confirmDefaults();
+});
--- a/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
@@ -6,16 +6,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/PlacesUtils.jsm");
 
 add_task(async function test_bookmarks() {
   function background() {
     let unsortedId, ourId;
     let initialBookmarkCount = 0;
     let createdBookmarks = new Set();
     let createdFolderId;
+    let createdSeparatorId;
     let collectedEvents = [];
     const nonExistentId = "000000000000";
     const bookmarkGuids = {
       menuGuid:    "menu________",
       toolbarGuid: "toolbar_____",
       unfiledGuid: "unfiled_____",
     };
 
@@ -23,42 +24,45 @@ add_task(async function test_bookmarks()
       browser.test.assertEq(ourId, bookmark.id, "Bookmark has the expected Id");
       browser.test.assertTrue("parentId" in bookmark, "Bookmark has a parentId");
       browser.test.assertEq(0, bookmark.index, "Bookmark has the expected index"); // We assume there are no other bookmarks.
       browser.test.assertEq("http://example.org/", bookmark.url, "Bookmark has the expected url");
       browser.test.assertEq("test bookmark", bookmark.title, "Bookmark has the expected title");
       browser.test.assertTrue("dateAdded" in bookmark, "Bookmark has a dateAdded");
       browser.test.assertFalse("dateGroupModified" in bookmark, "Bookmark does not have a dateGroupModified");
       browser.test.assertFalse("unmodifiable" in bookmark, "Bookmark is not unmodifiable");
+      browser.test.assertEq("bookmark", bookmark.type, "Bookmark is of type bookmark");
     }
 
     function checkBookmark(expected, bookmark) {
       browser.test.assertEq(expected.url, bookmark.url, "Bookmark has the expected url");
       browser.test.assertEq(expected.title, bookmark.title, "Bookmark has the expected title");
       browser.test.assertEq(expected.index, bookmark.index, "Bookmark has expected index");
+      browser.test.assertEq("bookmark", bookmark.type, "Bookmark is of type bookmark");
       if ("parentId" in expected) {
         browser.test.assertEq(expected.parentId, bookmark.parentId, "Bookmark has the expected parentId");
       }
     }
 
     function expectedError() {
       browser.test.fail("Did not get expected error");
     }
 
-    function checkOnCreated(id, parentId, index, title, url, dateAdded) {
+    function checkOnCreated(id, parentId, index, title, url, dateAdded, type = "bookmark") {
       let createdData = collectedEvents.pop();
       browser.test.assertEq("onCreated", createdData.event, "onCreated was the last event received");
       browser.test.assertEq(id, createdData.id, "onCreated event received the expected id");
       let bookmark = createdData.bookmark;
       browser.test.assertEq(id, bookmark.id, "onCreated event received the expected bookmark id");
       browser.test.assertEq(parentId, bookmark.parentId, "onCreated event received the expected bookmark parentId");
       browser.test.assertEq(index, bookmark.index, "onCreated event received the expected bookmark index");
       browser.test.assertEq(title, bookmark.title, "onCreated event received the expected bookmark title");
       browser.test.assertEq(url, bookmark.url, "onCreated event received the expected bookmark url");
       browser.test.assertEq(dateAdded, bookmark.dateAdded, "onCreated event received the expected bookmark dateAdded");
+      browser.test.assertEq(type, bookmark.type, "onCreated event received the expected bookmark type");
     }
 
     function checkOnChanged(id, url, title) {
       // If both url and title are changed, then url is fired last.
       let changedData = collectedEvents.pop();
       browser.test.assertEq("onChanged", changedData.event, "onChanged was the last event received");
       browser.test.assertEq(id, changedData.id, "onChanged event received the expected id");
       browser.test.assertEq(url, changedData.info.url, "onChanged event received the expected url");
@@ -75,28 +79,29 @@ add_task(async function test_bookmarks()
       browser.test.assertEq(id, movedData.id, "onMoved event received the expected id");
       let info = movedData.info;
       browser.test.assertEq(parentId, info.parentId, "onMoved event received the expected parentId");
       browser.test.assertEq(oldParentId, info.oldParentId, "onMoved event received the expected oldParentId");
       browser.test.assertEq(index, info.index, "onMoved event received the expected index");
       browser.test.assertEq(oldIndex, info.oldIndex, "onMoved event received the expected oldIndex");
     }
 
-    function checkOnRemoved(id, parentId, index, url) {
+    function checkOnRemoved(id, parentId, index, url, type = "folder") {
       let removedData = collectedEvents.pop();
       browser.test.assertEq("onRemoved", removedData.event, "onRemoved was the last event received");
       browser.test.assertEq(id, removedData.id, "onRemoved event received the expected id");
       let info = removedData.info;
       browser.test.assertEq(parentId, removedData.info.parentId, "onRemoved event received the expected parentId");
       browser.test.assertEq(index, removedData.info.index, "onRemoved event received the expected index");
       let node = info.node;
       browser.test.assertEq(id, node.id, "onRemoved event received the expected node id");
       browser.test.assertEq(parentId, node.parentId, "onRemoved event received the expected node parentId");
       browser.test.assertEq(index, node.index, "onRemoved event received the expected node index");
       browser.test.assertEq(url, node.url, "onRemoved event received the expected node url");
+      browser.test.assertEq(type, node.type, "onRemoved event received the expected node type");
     }
 
     browser.bookmarks.onChanged.addListener((id, info) => {
       collectedEvents.push({event: "onChanged", id, info});
     });
 
     browser.bookmarks.onCreated.addListener((id, bookmark) => {
       collectedEvents.push({event: "onCreated", id, bookmark});
@@ -121,17 +126,17 @@ add_task(async function test_bookmarks()
           nonExistentIdError.message.includes("Bookmark not found"),
           "Expected error thrown when trying to get a bookmark using a non-existent Id"
         );
       });
     }).then(() => {
       return browser.bookmarks.search({});
     }).then(results => {
       initialBookmarkCount = results.length;
-      return browser.bookmarks.create({title: "test bookmark", url: "http://example.org"});
+      return browser.bookmarks.create({title: "test bookmark", url: "http://example.org", type: "bookmark"});
     }).then(result => {
       ourId = result.id;
       checkOurBookmark(result);
       browser.test.assertEq(1, collectedEvents.length, "1 expected event received");
       checkOnCreated(ourId, bookmarkGuids.unfiledGuid, 0, "test bookmark", "http://example.org/", result.dateAdded);
 
       return browser.bookmarks.get(ourId);
     }).then(results => {
@@ -142,21 +147,22 @@ add_task(async function test_bookmarks()
       return browser.bookmarks.get(unsortedId);
     }).then(results => {
       let folder = results[0];
       browser.test.assertEq(1, results.length, "1 bookmark was returned");
 
       browser.test.assertEq(unsortedId, folder.id, "Folder has the expected id");
       browser.test.assertTrue("parentId" in folder, "Folder has a parentId");
       browser.test.assertTrue("index" in folder, "Folder has an index");
-      browser.test.assertFalse("url" in folder, "Folder does not have a url");
+      browser.test.assertEq(undefined, folder.url, "Folder does not have a url");
       browser.test.assertEq("Other Bookmarks", folder.title, "Folder has the expected title");
       browser.test.assertTrue("dateAdded" in folder, "Folder has a dateAdded");
       browser.test.assertTrue("dateGroupModified" in folder, "Folder has a dateGroupModified");
       browser.test.assertFalse("unmodifiable" in folder, "Folder is not unmodifiable"); // TODO: Do we want to enable this?
+      browser.test.assertEq("folder", folder.type, "Folder has a type of folder");
 
       return browser.bookmarks.getChildren(unsortedId);
     }).then(results => {
       browser.test.assertEq(1, results.length, "The folder has one child");
       checkOurBookmark(results[0]);
 
       return browser.bookmarks.update(nonExistentId, {title: "new test title"}).then(expectedError, error => {
         browser.test.assertTrue(
@@ -165,16 +171,17 @@ add_task(async function test_bookmarks()
         );
 
         return browser.bookmarks.update(ourId, {title: "new test title", url: "http://example.com/"});
       });
     }).then(result => {
       browser.test.assertEq("new test title", result.title, "Updated bookmark has the expected title");
       browser.test.assertEq("http://example.com/", result.url, "Updated bookmark has the expected URL");
       browser.test.assertEq(ourId, result.id, "Updated bookmark has the expected id");
+      browser.test.assertEq("bookmark", result.type, "Updated bookmark has a type of bookmark");
 
       browser.test.assertEq(2, collectedEvents.length, "2 expected events received");
       checkOnChanged(ourId, "http://example.com/", "new test title");
 
       return Promise.resolve().then(() => {
         return browser.bookmarks.update(ourId, {url: "this is not a valid url"});
       }).then(expectedError, error => {
         browser.test.assertTrue(
@@ -186,16 +193,18 @@ add_task(async function test_bookmarks()
     }).then(results => {
       browser.test.assertEq(1, results.length, "getTree returns one result");
       let bookmark = results[0].children.find(bookmarkItem => bookmarkItem.id == unsortedId);
       browser.test.assertEq(
           "Other Bookmarks",
           bookmark.title,
           "Folder returned from getTree has the expected title"
       );
+      browser.test.assertEq("folder", bookmark.type,
+                            "Folder returned from getTree has the expected type");
 
       return browser.bookmarks.create({parentId: "invalid"}).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Invalid bookmark"),
           "Expected error thrown when trying to create a bookmark with an invalid parentId"
         );
         browser.test.assertTrue(
             error.message.includes(`"parentGuid":"invalid"`),
@@ -203,17 +212,17 @@ add_task(async function test_bookmarks()
         );
       });
     }).then(() => {
       return browser.bookmarks.remove(ourId);
     }).then(result => {
       browser.test.assertEq(undefined, result, "Removing a bookmark returns undefined");
 
       browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
-      checkOnRemoved(ourId, bookmarkGuids.unfiledGuid, 0, "http://example.com/");
+      checkOnRemoved(ourId, bookmarkGuids.unfiledGuid, 0, "http://example.com/", "bookmark");
 
       return browser.bookmarks.get(ourId).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Bookmark not found"),
           "Expected error thrown when trying to get a removed bookmark"
         );
       });
     }).then(() => {
@@ -223,83 +232,91 @@ add_task(async function test_bookmarks()
           "Expected error thrown when trying removed a non-existent bookmark"
         );
       });
     }).then(() => {
       // test bookmarks.search
       return Promise.all([
         browser.bookmarks.create({title: "MØzillä", url: "http://møzîllä.örg/"}),
         browser.bookmarks.create({title: "Example", url: "http://example.org/"}),
-        browser.bookmarks.create({title: "Mozilla Folder"}),
+        browser.bookmarks.create({title: "Mozilla Folder", type: "folder"}),
         browser.bookmarks.create({title: "EFF", url: "http://eff.org/"}),
         browser.bookmarks.create({title: "Menu Item", url: "http://menu.org/", parentId: bookmarkGuids.menuGuid}),
         browser.bookmarks.create({title: "Toolbar Item", url: "http://toolbar.org/", parentId: bookmarkGuids.toolbarGuid}),
       ]);
     }).then(results => {
       browser.test.assertEq(6, collectedEvents.length, "6 expected events received");
       checkOnCreated(results[5].id, bookmarkGuids.toolbarGuid, 0, "Toolbar Item", "http://toolbar.org/", results[5].dateAdded);
       checkOnCreated(results[4].id, bookmarkGuids.menuGuid, 0, "Menu Item", "http://menu.org/", results[4].dateAdded);
       checkOnCreated(results[3].id, bookmarkGuids.unfiledGuid, 0, "EFF", "http://eff.org/", results[3].dateAdded);
-      checkOnCreated(results[2].id, bookmarkGuids.unfiledGuid, 0, "Mozilla Folder", undefined, results[2].dateAdded);
+      checkOnCreated(results[2].id, bookmarkGuids.unfiledGuid, 0, "Mozilla Folder", undefined, results[2].dateAdded, "folder");
       checkOnCreated(results[1].id, bookmarkGuids.unfiledGuid, 0, "Example", "http://example.org/", results[1].dateAdded);
       checkOnCreated(results[0].id, bookmarkGuids.unfiledGuid, 0, "MØzillä", "http://xn--mzll-ooa1dud.xn--rg-eka/", results[0].dateAdded);
 
       for (let result of results) {
         if (result.title !== "Mozilla Folder") {
           createdBookmarks.add(result.id);
         }
       }
       let folderResult = results[2];
       createdFolderId = folderResult.id;
       return Promise.all([
         browser.bookmarks.create({title: "Mozilla", url: "http://allizom.org/", parentId: createdFolderId}),
+        browser.bookmarks.create({parentId: createdFolderId, type: "separator"}),
         browser.bookmarks.create({title: "Mozilla Corporation", url: "http://allizom.com/", parentId: createdFolderId}),
         browser.bookmarks.create({title: "Firefox", url: "http://allizom.org/firefox/", parentId: createdFolderId}),
       ]).then(newBookmarks => {
-        browser.test.assertEq(3, collectedEvents.length, "3 expected events received");
-        checkOnCreated(newBookmarks[2].id, createdFolderId, 0, "Firefox", "http://allizom.org/firefox/", newBookmarks[2].dateAdded);
-        checkOnCreated(newBookmarks[1].id, createdFolderId, 0, "Mozilla Corporation", "http://allizom.com/", newBookmarks[1].dateAdded);
+        browser.test.assertEq(4, collectedEvents.length, "4 expected events received");
+        checkOnCreated(newBookmarks[3].id, createdFolderId, 0, "Firefox", "http://allizom.org/firefox/", newBookmarks[3].dateAdded);
+        checkOnCreated(newBookmarks[2].id, createdFolderId, 0, "Mozilla Corporation", "http://allizom.com/", newBookmarks[2].dateAdded);
+        checkOnCreated(newBookmarks[1].id, createdFolderId, 0, "", "data:", newBookmarks[1].dateAdded, "separator");
         checkOnCreated(newBookmarks[0].id, createdFolderId, 0, "Mozilla", "http://allizom.org/", newBookmarks[0].dateAdded);
 
         return browser.bookmarks.create({
           title: "About Mozilla",
           url: "http://allizom.org/about/",
           parentId: createdFolderId,
           index: 1,
         });
       }).then(result => {
         browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
         checkOnCreated(result.id, createdFolderId, 1, "About Mozilla", "http://allizom.org/about/", result.dateAdded);
 
         // returns all items on empty object
         return browser.bookmarks.search({});
       }).then(bookmarksSearchResults => {
-        browser.test.assertTrue(bookmarksSearchResults.length >= 9, "At least as many bookmarks as added were returned by search({})");
+        browser.test.assertTrue(bookmarksSearchResults.length >= 10, "At least as many bookmarks as added were returned by search({})");
 
         return Promise.resolve().then(() => {
           return browser.bookmarks.remove(createdFolderId);
         }).then(expectedError, error => {
           browser.test.assertTrue(
             error.message.includes("Cannot remove a non-empty folder"),
             "Expected error thrown when trying to remove a non-empty folder"
           );
           return browser.bookmarks.getSubTree(createdFolderId);
         });
       });
     }).then(results => {
       browser.test.assertEq(1, results.length, "Expected number of nodes returned by getSubTree");
       browser.test.assertEq("Mozilla Folder", results[0].title, "Folder has the expected title");
       browser.test.assertEq(bookmarkGuids.unfiledGuid, results[0].parentId, "Folder has the expected parentId");
+      browser.test.assertEq("folder", results[0].type, "Folder has the expected type");
       let children = results[0].children;
-      browser.test.assertEq(4, children.length, "Expected number of bookmarks returned by getSubTree");
+      browser.test.assertEq(5, children.length, "Expected number of bookmarks returned by getSubTree");
       browser.test.assertEq("Firefox", children[0].title, "Bookmark has the expected title");
+      browser.test.assertEq("bookmark", children[0].type, "Bookmark has the expected type");
       browser.test.assertEq("About Mozilla", children[1].title, "Bookmark has the expected title");
+      browser.test.assertEq("bookmark", children[1].type, "Bookmark has the expected type");
       browser.test.assertEq(1, children[1].index, "Bookmark has the expected index");
       browser.test.assertEq("Mozilla Corporation", children[2].title, "Bookmark has the expected title");
-      browser.test.assertEq("Mozilla", children[3].title, "Bookmark has the expected title");
+      browser.test.assertEq("", children[3].title, "Separator has the expected title");
+      browser.test.assertEq("data:", children[3].url, "Separator has the expected url");
+      browser.test.assertEq("separator", children[3].type, "Separator has the expected type");
+      browser.test.assertEq("Mozilla", children[4].title, "Bookmark has the expected title");
 
       // throws an error for invalid query objects
       Promise.resolve().then(() => {
         return browser.bookmarks.search();
       }).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Incorrect argument types for bookmarks.search"),
           "Expected error thrown when trying to search with no arguments"
@@ -372,16 +389,17 @@ add_task(async function test_bookmarks()
       browser.test.assertEq(1, results.length, "Expected number of results returned for toolbar item search");
       checkBookmark({title: "Toolbar Item", url: "http://toolbar.org/", index: 0, parentId: bookmarkGuids.toolbarGuid}, results[0]);
 
       // finds folders
       return browser.bookmarks.search("Mozilla Folder");
     }).then(results => {
       browser.test.assertEq(1, results.length, "Expected number of folders returned");
       browser.test.assertEq("Mozilla Folder", results[0].title, "Folder has the expected title");
+      browser.test.assertEq("folder", results[0].type, "Folder has the expected type");
 
       // is case-insensitive
       return browser.bookmarks.search("corporation");
     }).then(results => {
       browser.test.assertEq(1, results.length, "Expected number of results returnedfor case-insensitive search");
       browser.test.assertEq("Mozilla Corporation", results[0].title, "Bookmark has the expected title");
 
       // is case-insensitive for non-ascii
@@ -416,23 +434,23 @@ add_task(async function test_bookmarks()
     }).then(results => {
       browser.test.assertEq(results.length, 1, "Expected number of results returned for normalized url field");
       checkBookmark({title: "Mozilla Corporation", url: "http://allizom.com/", index: 2}, results[0]);
 
       // accepts a title field
       return browser.bookmarks.search({title: "Mozilla"});
     }).then(results => {
       browser.test.assertEq(results.length, 1, "Expected number of results returned for title field");
-      checkBookmark({title: "Mozilla", url: "http://allizom.org/", index: 3}, results[0]);
+      checkBookmark({title: "Mozilla", url: "http://allizom.org/", index: 4}, results[0]);
 
       // can combine title and query
       return browser.bookmarks.search({title: "Mozilla", query: "allizom"});
     }).then(results => {
       browser.test.assertEq(1, results.length, "Expected number of results returned for title and query fields");
-      checkBookmark({title: "Mozilla", url: "http://allizom.org/", index: 3}, results[0]);
+      checkBookmark({title: "Mozilla", url: "http://allizom.org/", index: 4}, results[0]);
 
       // uses AND conditions
       return browser.bookmarks.search({title: "EFF", query: "allizom"});
     }).then(results => {
       browser.test.assertEq(
         0,
         results.length,
         "Expected number of results returned for non-matching title and query fields"
@@ -527,40 +545,52 @@ add_task(async function test_bookmarks()
       return browser.bookmarks.search({title: "Mozilla Folder"}).then(result => {
         return browser.bookmarks.removeTree(result[0].id);
       }).then(() => {
         browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
         checkOnRemoved(createdFolderId, bookmarkGuids.unfiledGuid, 1);
 
         return browser.bookmarks.search({}).then(searchResults => {
           browser.test.assertEq(
-            startBookmarkCount - 4,
+            startBookmarkCount - 5,
             searchResults.length,
             "Expected number of results returned after removeTree");
         });
       });
     }).then(() => {
       return browser.bookmarks.create({title: "Empty Folder"});
     }).then(result => {
-      let emptyFolderId = result.id;
+      createdFolderId = result.id;
 
       browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
-      checkOnCreated(emptyFolderId, bookmarkGuids.unfiledGuid, 3, "Empty Folder", undefined, result.dateAdded);
+      checkOnCreated(createdFolderId, bookmarkGuids.unfiledGuid, 3, "Empty Folder", undefined, result.dateAdded, "folder");
 
       browser.test.assertEq("Empty Folder", result.title, "Folder has the expected title");
-      return browser.bookmarks.remove(emptyFolderId).then(() => {
-        browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
-        checkOnRemoved(emptyFolderId, bookmarkGuids.unfiledGuid, 3);
+      browser.test.assertEq("folder", result.type, "Folder has the expected type");
 
-        return browser.bookmarks.get(emptyFolderId).then(expectedError, error => {
-          browser.test.assertTrue(
-            error.message.includes("Bookmark not found"),
-            "Expected error thrown when trying to get a removed folder"
-          );
-        });
+      return browser.bookmarks.create({parentId: createdFolderId, type: "separator"});
+    }).then(result => {
+      createdSeparatorId = result.id;
+      browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
+      checkOnCreated(createdSeparatorId, createdFolderId, 0, "", "data:", result.dateAdded, "separator");
+      return browser.bookmarks.remove(createdSeparatorId);
+    }).then(() => {
+      browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
+      checkOnRemoved(createdSeparatorId, createdFolderId, 0, "data:", "separator");
+
+      return browser.bookmarks.remove(createdFolderId);
+    }).then(() => {
+      browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
+      checkOnRemoved(createdFolderId, bookmarkGuids.unfiledGuid, 3);
+
+      return browser.bookmarks.get(createdFolderId).then(expectedError, error => {
+        browser.test.assertTrue(
+          error.message.includes("Bookmark not found"),
+          "Expected error thrown when trying to get a removed folder"
+        );
       });
     }).then(() => {
       return browser.bookmarks.getChildren(nonExistentId).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("root is null"),
           "Expected error thrown when trying to getChildren for a non-existent folder"
         );
       });
--- a/browser/components/migration/ESEDBReader.jsm
+++ b/browser/components/migration/ESEDBReader.jsm
@@ -352,17 +352,17 @@ ESEDB.prototype = {
 
     if (rv > 0) {
       log.error("Got warning " + rv + " calling OpenTableW");
     }
     ESE.FailSafeCloseTable(this._sessionId, tableId);
     return true;
   },
 
-  *tableItems(tableName, columns) {
+  * tableItems(tableName, columns) {
     if (!this._opened) {
       throw new Error("The database was closed!");
     }
 
     let tableOpened = false;
     let tableId;
     try {
       tableId = this._openTable(tableName);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -826,40 +826,16 @@ BrowserGlue.prototype = {
       },
     ];
 
     let nb = win.document.getElementById("high-priority-global-notificationbox");
     nb.appendNotification(message, "unsigned-addons-disabled", "",
                           nb.PRIORITY_WARNING_MEDIUM, buttons);
   },
 
-  _notifyDisabledNonMpc() {
-    let win = RecentWindow.getMostRecentBrowserWindow();
-    if (!win)
-      return;
-
-    // This is only going to be on Nightly and only for the 55 and 56
-    // cycles, and it points to a wiki page that is not localized, so
-    // no need to localize the message here...
-    let message = "Due to performance testing, we have disabled some of your add-ons. They can be re-enabled in your browser settings.";
-    let buttons = [
-      {
-        label: "Manage Add-Ons",
-        accessKey: "M",
-        callback() {
-          win.BrowserOpenAddonsMgr("addons://list/extension");
-        }
-      },
-    ];
-
-    let nb = win.document.getElementById("high-priority-global-notificationbox");
-    nb.appendNotification(message, "non-mpc-addons-disabled", "",
-                          nb.PRIORITY_WARNING_MEDIUM, buttons);
-  },
-
   _firstWindowTelemetry(aWindow) {
     let scaling = aWindow.devicePixelRatio * 100;
     try {
       Services.telemetry.getHistogramById("DISPLAY_SCALING").add(scaling);
     } catch (ex) {}
   },
 
   // the first browser window has finished initializing
@@ -1047,20 +1023,16 @@ BrowserGlue.prototype = {
           if (addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
             this._notifyUnsignedAddonsDisabled();
             break;
           }
         }
       });
     }
 
-    if (AddonManager.nonMpcDisabled) {
-      this._notifyDisabledNonMpc();
-    }
-
     if (AppConstants.MOZ_CRASHREPORTER) {
       UnsubmittedCrashHandler.init();
     }
 
     this._sanitizer.onStartup();
     E10SAccessibilityCheck.onWindowsRestored();
 
     this._scheduleStartupIdleTasks();
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -905,17 +905,17 @@
 
   <hbox align="center">
     <checkbox id="useRecommendedPerformanceSettings"
               label="&useRecommendedPerformanceSettings2.label;"
               accesskey="&useRecommendedPerformanceSettings2.accesskey;"
               preference="browser.preferences.defaultPerformanceSettings.enabled"/>
     <label id="performanceSettingsLearnMore" class="learnMore text-link">&performanceSettingsLearnMore.label;</label>
   </hbox>
-  <description class="indent">&useRecommendedPerformanceSettings2.description;</description>
+  <description class="indent tip-caption">&useRecommendedPerformanceSettings2.description;</description>
 
   <vbox id="performanceSettings" class="indent" hidden="true">
     <checkbox id="allowHWAccel"
               label="&allowHWAccel.label;"
               accesskey="&allowHWAccel.accesskey;"
               preference="layers.acceleration.disabled"/>
     <hbox align="center">
       <label id="limitContentProcess" accesskey="&limitContentProcessOption.accesskey;" control="contentProcessCount">&limitContentProcessOption.label;</label>
@@ -926,18 +926,18 @@
           <menuitem label="3" value="3"/>
           <menuitem label="4" value="4"/>
           <menuitem label="5" value="5"/>
           <menuitem label="6" value="6"/>
           <menuitem label="7" value="7"/>
         </menupopup>
       </menulist>
     </hbox>
-    <description id="contentProcessCountEnabledDescription">&limitContentProcessOption.description;</description>
-    <description id="contentProcessCountDisabledDescription">&limitContentProcessOption.disabledDescription;<label class="text-link" href="https://wiki.mozilla.org/Electrolysis">&limitContentProcessOption.disabledDescriptionLink;</label></description>
+    <description id="contentProcessCountEnabledDescription" class="tip-caption">&limitContentProcessOption.description;</description>
+    <description id="contentProcessCountDisabledDescription" class="tip-caption">&limitContentProcessOption.disabledDescription;<label class="text-link" href="https://wiki.mozilla.org/Electrolysis">&limitContentProcessOption.disabledDescriptionLink;</label></description>
   </vbox>
 </groupbox>
 
 <hbox id="browsingCategory"
       class="subcategory"
       hidden="true"
       data-category="paneGeneral">
   <label class="header-name" flex="1">&browsing.label;</label>
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -175,17 +175,17 @@
       <key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand="gSearchResultsPane.searchInput.focus();"/>
     </keyset>
 
     <html:a class="help-button" target="_blank" aria-label="&helpButton2.label;">&helpButton2.label;</html:a>
 
     <vbox class="main-content" flex="1" align="start">
       <vbox class="pane-container">
         <hbox class="search-container" pack="end">
-          <textbox type="search" id="searchInput" hidden="true" clickSelectsAll="true"/>
+          <textbox type="search" id="searchInput" style="width: &searchField.width;" hidden="true" clickSelectsAll="true"/>
         </hbox>
         <prefpane id="mainPrefPane">
 #include searchResults.xul
 #include main.xul
 #include search.xul
 #include privacy.xul
 #include containers.xul
 #include sync.xul
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -697,17 +697,17 @@
     </description>
     <description flex="1">
       <checkbox id="submitHealthReportBox" label="&enableHealthReport1.label;"
                 accesskey="&enableHealthReport1.accesskey;"/>
       <label id="FHRLearnMore"
              class="learnMore text-link">&healthReportLearnMore.label;</label>
     </description>
 #ifndef MOZ_TELEMETRY_REPORTING
-    <description id="TelemetryDisabledDesc" class="indent" control="telemetryGroup">&healthReportingDisabled.label;</description>
+    <description id="TelemetryDisabledDesc" class="indent tip-caption" control="telemetryGroup">&healthReportingDisabled.label;</description>
 #endif
   </vbox>
 #ifdef MOZ_CRASHREPORTER
   <hbox align="center">
     <checkbox id="automaticallySubmitCrashesBox"
               preference="browser.crashReports.unsubmittedCheck.autoSubmit"
               label="&alwaysSubmitCrashReports1.label;"
               accesskey="&alwaysSubmitCrashReports1.accesskey;"/>
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -40,31 +40,31 @@
       data-category="paneSync">
   <label class="header-name" flex="1">&paneSync1.title;</label>
 </hbox>
 
 <deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
   <groupbox id="noFxaAccount">
     <hbox>
       <vbox flex="1">
-        <label id="noFxaCaption">&signedOut.caption;</label>
+        <caption><label id="noFxaCaption">&signedOut.caption;</label></caption>
         <description id="noFxaDescription" flex="1">&signedOut.description;</description>
       </vbox>
       <vbox>
         <image class="fxaSyncIllustration"/>
       </vbox>
     </hbox>
     <hbox id="fxaNoLoginStatus" align="center" flex="1">
       <vbox>
         <image class="fxaProfileImage"/>
       </vbox>
       <vbox flex="1">
         <hbox align="center" flex="1">
           <hbox align="center" flex="1">
-            <label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label>
+            <caption><label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label></caption>
           </hbox>
           <button id="noFxaSignIn"
                   class="accessory-button"
                   label="&signedOut.accountBox.signin2;"
                   accesskey="&signedOut.accountBox.signin2.accesskey;"/>
         </hbox>
         <hbox align="center" flex="1">
           <html:a id="noFxaSignUp"
@@ -99,18 +99,18 @@
             <!-- logged in and verified and all is good -->
             <hbox id="fxaLoginVerified" align="center" flex="1">
               <image class="fxaProfileImage actionable"
                      role="button"
                      onclick="gSyncPane.openChangeProfileImage(event);"
                      onkeypress="gSyncPane.openChangeProfileImage(event);"
                      tooltiptext="&profilePicture.tooltip;"/>
               <vbox flex="1" pack="center">
-                <hbox flex="1" align="center">
-                  <label id="fxaDisplayName" hidden="true"/>
+                <hbox flex="1" align="baseline">
+                  <caption><label id="fxaDisplayName" hidden="true"/></caption>
                   <label class="fxaEmailAddress" flex="1" crop="end"/>
                   <button id="fxaUnlinkButton"
                           class="accessory-button"
                           label="&disconnect3.label;"
                           accesskey="&disconnect3.accesskey;"/>
                 </hbox>
                 <hbox>
                   <html:a id="verifiedManage" class="openLink"
--- a/browser/components/syncedtabs/test/browser/head.js
+++ b/browser/components/syncedtabs/test/browser/head.js
@@ -5,12 +5,12 @@ Cu.import("resource://gre/modules/Servic
 
 
 // Load mocking/stubbing library, sinon
 // docs: http://sinonjs.org/docs/
 /* global sinon */
 let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
 loader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
 
-registerCleanupFunction(function*() {
+registerCleanupFunction(function* () {
   // Cleanup window or the test runner will throw an error
   delete window.sinon;
 });
--- a/browser/extensions/formautofill/.eslintrc.js
+++ b/browser/extensions/formautofill/.eslintrc.js
@@ -30,19 +30,16 @@ module.exports = {
     "object-curly-spacing": ["error", "never"],
 
     // No space padding in parentheses
     "space-in-parens": ["error", "never"],
 
     // Require braces around blocks that start a new line
     "curly": ["error", "all"],
 
-    // Require function* name()
-    "generator-star-spacing": ["error", {"before": false, "after": true}],
-
     // Two space indent
     "indent": ["error", 2, {"SwitchCase": 1}],
 
     // Always require parenthesis for new calls
     "new-parens": "error",
 
     // No expressions where a statement is expected
     "no-unused-expressions": "error",
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -94,16 +94,17 @@ var PocketPageAction = {
       this.pageAction = PageActions.addAction(new PageActions.Action({
         id,
         title: gPocketBundle.GetStringFromName("saveToPocketCmd.label"),
         shownInUrlbar: true,
         wantsIframe: true,
         urlbarIDOverride: "pocket-button-box",
         anchorIDOverride: "pocket-button",
         _insertBeforeActionID: PageActions.ACTION_ID_BOOKMARK_SEPARATOR,
+        _urlbarInsertBeforeActionID: PageActions.ACTION_ID_BOOKMARK,
         _urlbarNodeInMarkup: true,
         onBeforePlacedInWindow(window) {
           let doc = window.document;
 
           if (doc.getElementById("pocket-button-box")) {
             return;
           }
 
@@ -159,17 +160,17 @@ var PocketPageAction = {
           PocketPageAction.urlbarNode = urlbarNode;
           PocketPageAction.urlbarNode.setAttribute("open", "true");
           if (Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
             PocketPageAction.urlbarNode.setAttribute("animate", "true");
           }
         },
         onIframeHiding(iframe, panel) {
           if (iframe.getAttribute("itemAdded") == "true") {
-            PocketPageAction.startLibraryAnimation(iframe.ownerDocument);
+            iframe.ownerGlobal.LibraryUI.triggerLibraryAnimation("pocket");
           }
         },
         onIframeHidden(iframe, panel) {
           if (!PocketPageAction.urlbarNode) {
             return;
           }
           PocketPageAction.urlbarNode.removeAttribute("animate");
           PocketPageAction.urlbarNode.removeAttribute("open");
@@ -191,64 +192,16 @@ var PocketPageAction = {
       if (pocketButtonBox) {
         pocketButtonBox.remove();
       }
     }
 
     this.pageAction.remove();
     this.pageAction = null;
   },
-
-  startLibraryAnimation(doc) {
-    let libraryButton = doc.getElementById("library-button");
-    if (!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") ||
-        !libraryButton ||
-        libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
-        libraryButton.getAttribute("overflowedItem") == "true" ||
-        !libraryButton.closest("#nav-bar")) {
-      return;
-    }
-
-    let animatableBox = doc.getElementById("library-animatable-box");
-    let navBar = doc.getElementById("nav-bar");
-    let libraryIcon = doc.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
-    let dwu = doc.defaultView.getInterface(Ci.nsIDOMWindowUtils);
-    let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
-    let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
-
-    animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
-    animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
-    animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
-    if (navBar.hasAttribute("brighttext")) {
-      animatableBox.setAttribute("brighttext", "true");
-    } else {
-      animatableBox.removeAttribute("brighttext");
-    }
-    animatableBox.removeAttribute("fade");
-    doc.defaultView.gNavToolbox.setAttribute("animate", "pocket");
-    libraryButton.setAttribute("animate", "pocket");
-    animatableBox.setAttribute("animate", "pocket");
-    animatableBox.addEventListener("animationend", PocketPageAction.onLibraryButtonAnimationEnd);
-  },
-
-  onLibraryButtonAnimationEnd(event) {
-    let doc = event.target.ownerDocument;
-    let libraryButton = doc.getElementById("library-button");
-    let animatableBox = doc.getElementById("library-animatable-box");
-    if (event.animationName.startsWith("library-pocket-animation")) {
-      animatableBox.setAttribute("fade", "true");
-    } else if (event.animationName == "library-pocket-fade") {
-      animatableBox.removeEventListener("animationend", PocketPageAction.onLibraryButtonAnimationEnd);
-      // Put the 'fill' back in the normal icon.
-      libraryButton.removeAttribute("animate");
-      animatableBox.removeAttribute("animate");
-      animatableBox.removeAttribute("fade");
-      event.target.ownerGlobal.gNavToolbox.removeAttribute("animate");
-    }
-  },
 };
 
 // PocketContextMenu
 // When the context menu is opened check if we need to build and enable pocket UI.
 var PocketContextMenu = {
   init() {
     Services.obs.addObserver(this, "on-build-contextmenu");
   },
--- a/browser/extensions/pocket/skin/shared/pocket.css
+++ b/browser/extensions/pocket/skin/shared/pocket.css
@@ -95,20 +95,16 @@
   width: 260px;
 }
 
 #pocket-button-box[animate="true"]:-moz-locale-dir(rtl) > #pocket-animatable-box > #pocket-animatable-image,
 #pocket-button[open="true"][animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]):-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
   animation-name: pocket-animation-rtl;
 }
 
-#library-button[animate="pocket"] > .toolbarbutton-icon {
-  fill: transparent;
-}
-
 @keyframes library-pocket-animation {
   from {
     transform: translateX(0);
     fill: inherit;
   }
   25% {
     fill: inherit;
   }
@@ -146,46 +142,16 @@
   from {
     fill: #ef4056;
   }
   to {
     fill: inherit;
   }
 }
 
-.toolbarbutton-animatable-box[animate="pocket"] {
-  position: absolute;
-  overflow: hidden;
-  /* Position the sprite at the y-position of the library-button, then adjust
-     based on the size difference between half of the button height and half
-     of the sprite height. */
-  top: calc(var(--library-button-y) + var(--library-button-height) / 2 - 27px);
-  /* Since .toolbarbutton-icon uses a different width than the animatable box,
-     we need to set a margin relative to the difference in widths.
-     margin-left is used here even in RTL because the item is positioned using `left` */
-  left: calc(var(--library-icon-x) + (16px + 2 * var(--toolbarbutton-inner-padding) - 22px) / 2);
-  /* Set the min- and max- width and height of the box equal to that
-     of each frame of the SVG sprite. Setting the width and height via
-     the `width` and `height` CSS properties causes an assertion for
-     `inline-size less than zero: 'aContainingBlockISize >= 0'` (bug 1379332). */
-  min-width: 22px;
-  max-width: 22px;
-  /* Height of each frame within the SVG sprite. The sprite must have equal amount
-     of space above and below the icon to allow it to vertically center with the
-     sprite's icon on top of the toolbar icon when using position:absolute;. */
-  min-height: 54px;
-  max-height: 54px;
-  z-index: 2;
-}
-
-.toolbarbutton-animatable-box[animate="pocket"] > .toolbarbutton-animatable-image {
-  height: var(--toolbarbutton-height); /* Height must be equal to height of toolbarbutton padding-box */
-  min-height: 54px; /* Minimum height must be equal to the height of the SVG sprite */
-}
-
 .toolbarbutton-animatable-box[animate="pocket"] > .toolbarbutton-animatable-image {
   background-image: url("chrome://pocket-shared/skin/library-pocket-animation.svg");
   width: 1078px;
   animation-name: library-pocket-animation;
   animation-duration: 800ms;
   animation-timing-function: steps(48);
 }
 
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
@@ -8,16 +8,21 @@
 <!-- LOCALIZATION NOTE (prefWindow.titleGNOME): This is not used for in-content preferences -->
 <!ENTITY  prefWindow.titleGNOME   "&brandShortName; Preferences">
 <!-- When making changes to prefWindow.styleWin test both Windows Classic and
      Luna since widget heights are different based on the OS theme -->
 <!ENTITY  prefWinMinSize.styleWin2      "width: 42em; min-height: 37.5em;">
 <!ENTITY  prefWinMinSize.styleMac       "width: 47em; min-height: 40em;">
 <!ENTITY  prefWinMinSize.styleGNOME     "width: 45.5em; min-height: 40.5em;">
 
+<!-- LOCALIZATION NOTE: (searchField.width): This is used to determine the width
+     of the search field in about:preferences, in order to make entire placeholder
+     string visible -->
+<!ENTITY  searchField.width             "15.4em">
+
 <!ENTITY  paneSearchResults.title       "Search Results">
 <!ENTITY  paneGeneral.title             "General">
 <!ENTITY  paneSearch.title              "Search">
 <!ENTITY  paneFilesApplications.title   "Files &amp; Applications">
 <!ENTITY  panePrivacySecurity.title     "Privacy &amp; Security">
 <!ENTITY  paneContainers.title          "Container Tabs">
 <!ENTITY  paneUpdates.title             "Updates">
 
--- a/browser/locales/searchplugins/diec2.xml
+++ b/browser/locales/searchplugins/diec2.xml
@@ -2,14 +2,14 @@
    - 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/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>DIEC2</ShortName>
 <Description>Diccionari de l'Institut d'Estudis Catalans</Description>
 <InputEncoding>ISO-8859-1</InputEncoding>
 <Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAFfKj%2FFAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167%2B3t%2B9f7vOec5%2FzOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP%2FwBr28AAgBw1S4kEsfh%2F4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv%2BCpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH%2BOD%2BQ5%2Bbk4eZm52zv9MWi%2FmvwbyI%2BIfHf%2FryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3%2FldM9sJoFoK0Hr5i3k4%2FEAenqFQyDwdHAoLC%2B0lYqG9MOOLPv8z4W%2Fgi372%2FEAe%2Ftt68ABxmkCZrcCjg%2F1xYW52rlKO58sEQjFu9%2Bcj%2FseFf%2F2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R%2BW%2FQmTdw0ArIZPwE62B7XLbMB%2B7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv%2FmPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5%2BASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1%2BTSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q%2B0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw%2BS3FDrFiOJMCaIkUqSUEko1ZT%2FlBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC%2FpdLoJ3YMeRZfQl9Jr6Afp5%2BmD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA%2BYb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV%2Bjvl%2F9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1%2BrTfaetq%2B2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z%2Bo%2B02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y%2FDMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS%2BKc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw%2BlXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r%2B00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle%2B70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l%2Bs7pAz7GPgKfep%2BHvqa%2BIt89viN%2B1n6Zfgf8nvs7%2Bsv9j%2Fi%2F4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww%2BFUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX%2BX0UKSoyqi7qUbRTdHF09yzWrORZ%2B2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY%2BybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP%2BWDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D%2BmiGT0Z1xjMJT1IreZEZkrkj801WRNberM%2FZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c%2FPbFWyFTNGjtFKuUA4WTC%2BoK3hbGFt4uEi9SFrUM99m%2Fur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl%2FVfPV5bdra3kq3yu3rSOuk626s91m%2Fr0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e%2B2Sba1r%2Fdd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q%2F5n7duEd3T8Wej3ulewf2Re%2FranRvbNyvv7%2ByCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9%2BmfHvjUOihzsPcw83fmX%2B39QjrSHkr0jq%2Fdawto22gPaG97%2BiMo50dXh1Hvrf%2Ffu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1%2F3yfPe549d8Lxw9CL3Ytslt0utPa49R35w%2FeFIr1tv62X3y%2B1XPK509E3rO9Hv03%2F6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r%2Fy%2B2v3qB%2FoP6n%2B0%2FrFlwG3g%2BGDAYM%2FDWQ%2FvDgmHnv6U%2F9OH4dJHzEfVI0YjjY%2BdHx8bDRq98mTOk%2BGnsqcTz8p%2BVv9563Or59%2F94vtLz1j82PAL%2BYvPv655qfNy76uprzrHI8cfvM55PfGm%2FK3O233vuO%2B638e9H5ko%2FED%2BUPPR%2BmPHp9BP9z7nfP78L%2FeE8%2Fsl0p8zAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn%2FAACA6QAAdTAAAOpgAAA6mAAAF2%2BSX8VGAAADAFBMVEX%2F%2F%2F%2F%2F%2F8z%2F%2F5n%2F%2F2b%2F%2FzP%2F%2FwD%2FzP%2F%2FzMz%2FzJn%2FzGb%2FzDP%2FzAD%2Fmf%2F%2Fmcz%2FmZn%2FmWb%2FmTP%2FmQD%2FZv%2F%2FZsz%2FZpn%2FZmb%2FZjP%2FZgD%2FM%2F%2F%2FM8z%2FM5n%2FM2b%2FMzP%2FMwD%2FAP%2F%2FAMz%2FAJn%2FAGb%2FADP%2FAADM%2F%2F%2FM%2F8zM%2F5nM%2F2bM%2FzPM%2FwDMzP%2FMzMzMzJnMzGbMzDPMzADMmf%2FMmczMmZnMmWbMmTPMmQDMZv%2FMZszMZpnMZmbMZjPMZgDMM%2F%2FMM8zMM5nMM2bMMzPMMwDMAP%2FMAMzMAJnMAGbMADPMAACZ%2F%2F%2BZ%2F8yZ%2F5mZ%2F2aZ%2FzOZ%2FwCZzP%2BZzMyZzJmZzGaZzDOZzACZmf%2BZmcyZmZmZmWaZmTOZmQCZZv%2BZZsyZZpmZZmaZZjOZZgCZM%2F%2BZM8yZM5mZM2aZMzOZMwCZAP%2BZAMyZAJmZAGaZADOZAABm%2F%2F9m%2F8xm%2F5lm%2F2Zm%2FzNm%2FwBmzP9mzMxmzJlmzGZmzDNmzABmmf9mmcxmmZlmmWZmmTNmmQBmZv9mZsxmZplmZmZmZjNmZgBmM%2F9mM8xmM5lmM2ZmMzNmMwBmAP9mAMxmAJlmAGZmADNmAAAz%2F%2F8z%2F8wz%2F5kz%2F2Yz%2FzMz%2FwAzzP8zzMwzzJkzzGYzzDMzzAAzmf8zmcwzmZkzmWYzmTMzmQAzZv8zZswzZpkzZmYzZjMzZgAzM%2F8zM8wzM5kzM2YzMzMzMwAzAP8zAMwzAJkzAGYzADMzAAAA%2F%2F8A%2F8wA%2F5kA%2F2YA%2FzMA%2FwAAzP8AzMwAzJkAzGYAzDMAzAAAmf8AmcwAmZkAmWYAmTMAmQAAZv8AZswAZpkAZmYAZjMAZgAAM%2F8AM8wAM5kAM2YAMzMAMwAAAP8AAMwAAJkAAGYAADMAAAD6Fxj8FRb7FBX5EhT8BQf7BQf5Bwj9Cgv8DBD7DQ%2F5DxH6EhX9ExT6ExX8FBb18ez84N3%2B6%2Br5Cgn4Dgz7Dw%2F2Ew%2F5EhH5ExH2FRH3FRL9ExP5FBT9FhX8FRX6FRX4FxX8Fhb7Fxb2Gxj5HRr2HRn3HRv%2F%2F%2F8AAAD5ITrYAAAA%2F3RSTlP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwBm%2FIpZAAAA7ElEQVR42mL4d4PhHwMAAAD%2F%2F2K4cYOFSRAAAAD%2F%2F2L494zhLRPDV4a%2FAAAAAP%2F%2FYrzBwMDAwPDrGQMTw98vDEwM3xkZAAAAAP%2F%2FYvzHdIuL9SOrIhMDw39R8f%2B8DAz%2FGH78ZvjxnoHhHwMEAFiWQx0AQSgAgOeT5IjMSOb%2Fv8Zut7ARwcL124%2BQW%2BRWJbdcfMLSlyFMx3RJknoaQvd22P35qZBjFQBBKArDvxe3ahIi8P3fKZwFJZzjhmAN3qXDNxx%2Bhr0KFDgF6ErXoytbAg%2BUx1zLDFFNcDNkMW0HAeJtwjtDXk3z4Ebit28Ab35LCW4dGm8AAAAASUVORK5CYII%3D</Image>
-<Url type="text/html" method="GET" template="http://dlc.iec.cat/results.asp" resultdomain="iec.cat">
+<Url type="text/html" method="GET" template="https://dlc.iec.cat/results.asp" resultdomain="iec.cat">
   <Param name="txtEntrada" value="{searchTerms}"/>
   <Param name="OperEntrada" value="0"/>
 </Url>
-<SearchForm>http://dlc.iec.cat</SearchForm>
+<SearchForm>https://dlc.iec.cat</SearchForm>
 </SearchPlugin>
--- a/browser/modules/PageActions.jsm
+++ b/browser/modules/PageActions.jsm
@@ -4,54 +4,65 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [
   "PageActions",
   // PageActions.Action
   // PageActions.Button
   // PageActions.Subview
+  // PageActions.ACTION_ID_BOOKMARK
   // PageActions.ACTION_ID_BOOKMARK_SEPARATOR
   // PageActions.ACTION_ID_BUILT_IN_SEPARATOR
 ];
 
 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, "BinarySearch",
   "resource://gre/modules/BinarySearch.jsm");
 
 
+const ACTION_ID_BOOKMARK = "bookmark";
 const ACTION_ID_BOOKMARK_SEPARATOR = "bookmarkSeparator";
 const ACTION_ID_BUILT_IN_SEPARATOR = "builtInSeparator";
 
 const PREF_PERSISTED_ACTIONS = "browser.pageActions.persistedActions";
 
 
 this.PageActions = {
   /**
    * Inits.  Call to init.
    */
   init() {
     let callbacks = this._deferredAddActionCalls;
     delete this._deferredAddActionCalls;
 
     this._loadPersistedActions();
 
-    // Add the built-in actions, which are defined below in this file.
+    // Register the built-in actions, which are defined below in this file.
     for (let options of gBuiltInActions) {
       if (!this.actionForID(options.id)) {
-        this.addAction(new Action(options));
+        this._registerAction(new Action(options));
       }
     }
 
+    // Now place them all in each window.  Instead of splitting the register and
+    // place steps, we could simply call addAction, which does both, but doing
+    // it this way means that all windows initially place their actions the same
+    // way -- placeAllActions -- regardless of whether they're open when this
+    // method is called or opened later.
+    for (let bpa of allBrowserPageActions()) {
+      bpa.placeAllActions();
+    }
+
     // These callbacks are deferred until init happens and all built-in actions
     // are added.
     while (callbacks && callbacks.length) {
       callbacks.shift()();
     }
   },
 
   _deferredAddActionCalls: [],
@@ -90,16 +101,37 @@ this.PageActions = {
   /**
    * The list of non-built-in actions.  Not live.  (array of Action objects)
    */
   get nonBuiltInActions() {
     return this._nonBuiltInActions.slice();
   },
 
   /**
+   * The list of actions in the urlbar, sorted in the order in which they should
+   * appear there.  Not live.  (array of Action objects)
+   */
+  get actionsInUrlbar() {
+    if (!this._persistedActions) {
+      // This is the case before init is called.  No one should be calling us
+      // then, but return something sensible.
+      return [];
+    }
+    // Remember that IDs in idsInUrlbar may belong to actions that aren't
+    // currently registered.
+    return this._persistedActions.idsInUrlbar.reduce((actions, id) => {
+      let action = this.actionForID(id);
+      if (action) {
+        actions.push(action);
+      }
+      return actions;
+    }, []);
+  },
+
+  /**
    * Gets an action.
    *
    * @param  id (string, required)
    *         The ID of the action to get.
    * @return The Action object, or null if none.
    */
   actionForID(id) {
     return this._actionsByID.get(id);
@@ -123,177 +155,135 @@ this.PageActions = {
   addAction(action) {
     if (this._deferredAddActionCalls) {
       // init() hasn't been called yet.  Defer all additions until it's called,
       // at which time _deferredAddActionCalls will be deleted.
       this._deferredAddActionCalls.push(() => this.addAction(action));
       return action;
     }
 
+    let hadSep = this.actions.some(a => a.id == ACTION_ID_BUILT_IN_SEPARATOR);
+
+    this._registerAction(action);
+
+    let sep = null;
+    if (!hadSep) {
+      sep = this.actions.find(a => a.id == ACTION_ID_BUILT_IN_SEPARATOR);
+    }
+
+    for (let bpa of allBrowserPageActions()) {
+      if (sep) {
+        // There are now both built-in and non-built-in actions, so place the
+        // separator between the two groups.
+        bpa.placeAction(sep);
+      }
+      bpa.placeAction(action);
+    }
+
+    return action;
+  },
+
+  _registerAction(action) {
     if (this.actionForID(action.id)) {
       throw new Error(`Action with ID '${action.id}' already added`);
     }
     this._actionsByID.set(action.id, action);
 
-    // The IDs of the actions in the panel and urlbar before which the new
-    // action shoud be inserted.  null means at the end, or it's irrelevant.
-    let panelInsertBeforeID = null;
-    let urlbarInsertBeforeID = null;
-
-    let oldBuiltInCount = this._builtInActions.length;
-    let oldNonBuiltInCount = this._nonBuiltInActions.length;
-
     // Insert the action into the appropriate list, either _builtInActions or
-    // _nonBuiltInActions, and find panelInsertBeforeID.
+    // _nonBuiltInActions.
 
     // Keep in mind that _insertBeforeActionID may be present but null, which
     // means the action should be appended to the built-ins.
     if ("__insertBeforeActionID" in action) {
       // A "semi-built-in" action, probably an action from an extension
       // bundled with the browser.  Right now we simply assume that no other
       // consumers will use _insertBeforeActionID.
       let index =
         !action.__insertBeforeActionID ? -1 :
         this._builtInActions.findIndex(a => {
           return a.id == action.__insertBeforeActionID;
         });
       if (index < 0) {
         // Append the action.
         index = this._builtInActions.length;
-        if (this._nonBuiltInActions.length) {
-          panelInsertBeforeID = ACTION_ID_BUILT_IN_SEPARATOR;
-        }
-      } else {
-        panelInsertBeforeID = this._builtInActions[index].id;
       }
       this._builtInActions.splice(index, 0, action);
     } 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);
-      if (this._nonBuiltInActions.length) {
-        panelInsertBeforeID = ACTION_ID_BUILT_IN_SEPARATOR;
-      }
     } 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);
       }, this._nonBuiltInActions, action);
-      if (index < this._nonBuiltInActions.length) {
-        panelInsertBeforeID = this._nonBuiltInActions[index].id;
-      }
       this._nonBuiltInActions.splice(index, 0, action);
     }
 
     if (this._persistedActions.ids[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
       // the public version is set.
       action._shownInUrlbar =
         this._persistedActions.idsInUrlbar.includes(action.id);
     } else {
       // The action is new.  Store it in the persisted actions.
       this._persistedActions.ids[action.id] = true;
       if (action.shownInUrlbar) {
-        this._persistedActions.idsInUrlbar.push(action.id);
+        // Also store it in idsInUrlbar.
+        let index =
+          !action.__urlbarInsertBeforeActionID ? -1 :
+          this._persistedActions.idsInUrlbar.indexOf(
+            action.__urlbarInsertBeforeActionID
+          );
+        if (index < 0) {
+          // Append the action.
+          index = this._persistedActions.idsInUrlbar.length;
+        }
+        this._persistedActions.idsInUrlbar.splice(index, 0, action.id);
       }
       this._storePersistedActions();
     }
-
-    if (action.shownInUrlbar) {
-      urlbarInsertBeforeID = this.insertBeforeActionIDInUrlbar(action);
-    }
-
-    // If there are now both built-in and non-built-in actions, add a separator
-    // in the panel between the two groups.
-    let placeBuiltInSeparator =
-      (oldNonBuiltInCount == 0 &&
-       this._nonBuiltInActions.length &&
-       this._builtInActions.length) ||
-      (oldBuiltInCount == 0 &&
-       this._builtInActions.length &&
-       this._nonBuiltInActions.length);
-
-    for (let win of browserWindows()) {
-      if (placeBuiltInSeparator) {
-        let sep = new Action({
-          id: ACTION_ID_BUILT_IN_SEPARATOR,
-          _isSeparator: true,
-        });
-        let sepPanelInsertBeforeID =
-          this._nonBuiltInActions.length ? this._nonBuiltInActions[0].id : null;
-        browserPageActions(win).placeAction(sep, sepPanelInsertBeforeID, null);
-      }
-      browserPageActions(win).placeAction(action, panelInsertBeforeID,
-                                          urlbarInsertBeforeID);
-    }
-
-    return action;
   },
 
   _builtInActions: [],
   _nonBuiltInActions: [],
   _actionsByID: new Map(),
 
   /**
-   * Returns the ID of the action among the actions in the panel before which
-   * the given action should be inserted.
+   * The DOM nodes of actions should be ordered properly, both in the panel and
+   * the urlbar.  This method returns the ID of the action that comes after the
+   * given action in the given array.  You can use the returned ID to get a DOM
+   * node ID to pass to node.insertBefore().
    *
+   * Pass PageActions.actions to get the ID of the next action in the panel.
+   * Pass PageActions.actionsInUrlbar to get the ID of the next action in the
+   * urlbar.
+   *
+   * @param  action
+   *         The action whose node you want to insert into your DOM.
+   * @param  actionArray
+   *         The relevant array of actions, either PageActions.actions or
+   *         actionsInUrlbar.
    * @return The ID of the action before which the given action should be
    *         inserted.  If the given action should be inserted last, returns
    *         null.
    */
-  insertBeforeActionIDInPanel(action) {
-    let index = this._builtInActions.findIndex(a => {
-      return a.id == action.id;
-    });
-    if (index >= 0) {
-      return this._builtInActions[index + 1] ||
-             this._nonBuiltInActions.length ? ACTION_ID_BUILT_IN_SEPARATOR
-                                            : null;
-    }
-
-    index = this._nonBuiltInActions.findIndex(a => {
-      return a.id == action.id;
-    });
-    if (index >= 0) {
-      return this._nonBuiltInActions[index + 1] || null;
-    }
-
-    return null;
-  },
-
-  /**
-   * Returns the ID of the action among the current registered actions in the
-   * urlbar before which the given action should be inserted, ignoring whether
-   * the given action's shownInUrlbar is true or false.
-   *
-   * @return The ID of the action before which the given action should be
-   *         inserted.  If the given action should be inserted last or it should
-   *         not be inserted at all, returns null.
-   */
-  insertBeforeActionIDInUrlbar(action) {
-    // First, find the index of the given action.
-    let idsInUrlbar = this._persistedActions.idsInUrlbar;
-    let index = idsInUrlbar.indexOf(action.id);
+  nextActionID(action, actionArray) {
+    let index = actionArray.findIndex(a => a.id == action.id);
     if (index < 0) {
       return null;
     }
-    // Now start at the next index and find the ID of the first action that's
-    // currently registered.  Remember that IDs in idsInUrlbar may belong to
-    // actions that aren't currently registered.
-    for (let i = index + 1; i < idsInUrlbar.length; i++) {
-      let id = idsInUrlbar[i];
-      if (this.actionForID(id)) {
-        return id;
-      }
+    let nextAction = actionArray[index + 1];
+    if (!nextAction) {
+      return null;
     }
-    return null;
+    return nextAction.id;
   },
 
   /**
    * Call this when an action is removed.
    *
    * @param  action (Action object, required)
    *         The action that was removed.
    */
@@ -315,50 +305,50 @@ this.PageActions = {
     // Remove the action from persisted storage.
     delete this._persistedActions.ids[action.id];
     let index = this._persistedActions.idsInUrlbar.indexOf(action.id);
     if (index >= 0) {
       this._persistedActions.idsInUrlbar.splice(index, 1);
     }
     this._storePersistedActions();
 
-    for (let win of browserWindows()) {
-      browserPageActions(win).removeAction(action);
+    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 win of browserWindows()) {
-      browserPageActions(win).updateActionIconURL(action);
+    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 win of browserWindows()) {
-      browserPageActions(win).updateActionTitle(action);
+    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.
@@ -375,19 +365,18 @@ this.PageActions = {
       if (index < 0) {
         this._persistedActions.idsInUrlbar.push(action.id);
       }
     } else if (index >= 0) {
       this._persistedActions.idsInUrlbar.splice(index, 1);
     }
     this._storePersistedActions();
 
-    let insertBeforeID = this.insertBeforeActionIDInUrlbar(action);
-    for (let win of browserWindows()) {
-      browserPageActions(win).placeActionInUrlbar(action, insertBeforeID);
+    for (let bpa of allBrowserPageActions()) {
+      bpa.placeActionInUrlbar(action);
     }
   },
 
   _storePersistedActions() {
     let json = JSON.stringify(this._persistedActions);
     Services.prefs.setStringPref(PREF_PERSISTED_ACTIONS, json);
   },
 
@@ -504,20 +493,25 @@ function Action(options) {
     subview: false,
     tooltip: false,
     urlbarIDOverride: false,
     wantsIframe: false,
 
     // private
 
     // (string, optional)
-    // The ID of another action before which to insert this new action.  Applies
-    // to the page action panel only, not the urlbar.
+    // The ID of another action before which to insert this new action in the
+    // panel.
     _insertBeforeActionID: false,
 
+    // (string, optional)
+    // The ID of another action before which to insert this new action in the
+    // urlbar.
+    _urlbarInsertBeforeActionID: false,
+
     // (bool, optional)
     // True if this isn't really an action but a separator to be shown in the
     // page action panel.
     _isSeparator: false,
 
     // (bool, optional)
     // True if the action's urlbar button is defined in markup.  In that case, a
     // node with the action's urlbar node ID should already exist in the DOM
@@ -895,32 +889,32 @@ Button.prototype = {
       this._onCommand(event, buttonNode);
     }
   }
 };
 
 this.PageActions.Button = Button;
 
 
-// This is only necessary so that Pocket and the test can specify it for
-// action._insertBeforeActionID.
+// These are only necessary so that Pocket and the test can use them.
+this.PageActions.ACTION_ID_BOOKMARK = ACTION_ID_BOOKMARK;
 this.PageActions.ACTION_ID_BOOKMARK_SEPARATOR = ACTION_ID_BOOKMARK_SEPARATOR;
 
 // This is only necessary so that the test can access it.
 this.PageActions.ACTION_ID_BUILT_IN_SEPARATOR = ACTION_ID_BUILT_IN_SEPARATOR;
 
 
 // Sorted in the order in which they should appear in the page action panel.
 // Does not include the page actions of extensions bundled with the browser.
 // They're added by the relevant extension code.
 var gBuiltInActions = [
 
   // bookmark
   {
-    id: "bookmark",
+    id: ACTION_ID_BOOKMARK,
     urlbarIDOverride: "star-button-box",
     _urlbarNodeInMarkup: true,
     title: "",
     shownInUrlbar: true,
     nodeAttributes: {
       observes: "bookmarkThisPageBroadcaster",
     },
     onShowingInPanel(buttonNode) {
@@ -1005,23 +999,29 @@ function browserPageActions(obj) {
     return obj.BrowserPageActions;
   }
   return obj.ownerGlobal.BrowserPageActions;
 }
 
 /**
  * A generator function for all open browser windows.
  */
-function* browserWindows() {
+function* allBrowserWindows() {
   let windows = Services.wm.getEnumerator("navigator:browser");
   while (windows.hasMoreElements()) {
     yield windows.getNext();
   }
 }
 
+function* allBrowserPageActions() {
+  for (let win of allBrowserWindows()) {
+    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
  * the given schema, then an error is thrown.
  *
  * @param  obj
  *         The object to set properties on.
--- a/browser/modules/test/browser/browser_PageActions.js
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -757,16 +757,93 @@ add_task(async function nonBuiltFirst() 
   Assert.deepEqual(
     Array.map(BrowserPageActions.mainViewBodyNode.childNodes, n => n.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.
+  let actions = [0, 1, 2].map(i => {
+    return PageActions.addAction(new PageActions.Action({
+      id: `test-urlbarOrderNewWindow-${i}`,
+      title: `Test urlbarOrderNewWindow ${i}`,
+      shownInUrlbar: true,
+    }));
+  });
+
+  // Make sure PageActions knows they're appended to the urlbar actions.
+  Assert.deepEqual(
+    PageActions._persistedActions.idsInUrlbar.slice(
+      PageActions._persistedActions.idsInUrlbar.length - actions.length
+    ),
+    actions.map(a => a.id),
+    "PageActions._persistedActions.idsInUrlbar has new actions appended"
+  );
+  Assert.deepEqual(
+    PageActions.actionsInUrlbar.slice(
+      PageActions.actionsInUrlbar.length - actions.length
+    ).map(a => a.id),
+    actions.map(a => a.id),
+    "PageActions.actionsInUrlbar has new actions appended"
+  );
+
+  // Reach into _persistedActions to move the new actions to the front of the
+  // urlbar, same as if the user moved them.  That way we can test that insert-
+  // before IDs are correctly non-null when the urlbar nodes are inserted in the
+  // new window below.
+  PageActions._persistedActions.idsInUrlbar.splice(
+    PageActions._persistedActions.idsInUrlbar.length - actions.length,
+    actions.length
+  );
+  for (let i = 0; i < actions.length; i++) {
+    PageActions._persistedActions.idsInUrlbar.splice(i, 0, actions[i].id);
+  }
+
+  // Save the right-ordered IDs to use below, just in case they somehow get
+  // changed when the new window opens, which shouldn't happen, but maybe
+  // there's bugs.
+  let ids = PageActions._persistedActions.idsInUrlbar.slice();
+
+  // 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"
+  );
+
+  // 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)),
+    "Expected actions in new window's urlbar"
+  );
+
+  // Done, clean up.
+  await BrowserTestUtils.closeWindow(win);
+  for (let action of actions) {
+    action.remove();
+  }
+});
+
+
 function promisePageActionPanelOpen() {
   let button = document.getElementById("pageActionButton");
   // The main page action button is hidden for some URIs, so make sure it's
   // visible before trying to click it.
   let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIDOMWindowUtils);
   return BrowserTestUtils.waitForCondition(() => {
     info("Waiting for main page action button to have non-0 size");
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -44,20 +44,21 @@
   max-height: 0;
   transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
 }
 
 #navigator-toolbox > toolbar[customizing]:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
   outline: 1px dashed;
   outline-offset: -3px;
   -moz-outline-radius: 2px;
+}
+
+#navigator-toolbox > toolbar[customizing]:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):empty {
   /* Avoid the toolbar having no height when there's no items in it */
   min-height: 22px;
-  /* There's no border in customize mode, so we don't need extra padding. */
-  padding-bottom: 0;
 }
 
 /* Library animation */
 
 #navigator-toolbox[animate] {
   position: relative;
 }
 
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -237,17 +237,16 @@ panelview {
 }
 
 #appMenu-popup > arrowscrollbox > scrollbox,
 #PanelUI-popup > arrowscrollbox > scrollbox {
   overflow: visible;
 }
 
 #appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
-#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
 panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
   overflow: hidden;
 }
 
 #PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box {
   padding: 0;
 }
@@ -1696,18 +1695,16 @@ toolbaritem[overflowedItem=true],
   margin-inline-end: 3px;
 }
 
 menuitem[checked="true"].subviewbutton > .menu-iconic-left {
   visibility: hidden;
 }
 
 .panel-mainview[panelid=customizationui-widget-panel],
-#customizationui-widget-multiview > .panel-viewcontainer,
-#customizationui-widget-multiview > .panel-viewcontainer > .panel-viewstack,
 #PanelUI-panicView > .panel-subview-body,
 #PanelUI-panicView {
   overflow: visible;
 }
 
 #PanelUI-panicView.cui-widget-panelview {
   min-width: 280px;
 }
@@ -2033,20 +2030,16 @@ photonpanelmultiview .PanelUI-subView .p
   display: none !important;
 }
 
 photonpanelmultiview .PanelUI-subView toolbarseparator {
   margin-inline-start: 0;
   margin-inline-end: 0;
 }
 
-photonpanelmultiview#customizationui-widget-multiview > .panel-viewcontainer {
-  overflow: hidden;
-}
-
 /* This is explicitly overriding the overflow properties set above. */
 photonpanelmultiview .cui-widget-panelview {
   overflow-x: visible;
   overflow-y: visible;
 }
 
 photonpanelmultiview #panelMenu_pocket {
   display: none;
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -25,41 +25,29 @@
 
 #mainPrefPane {
   width: 100%;
   padding: 0;
   font: message-box;
   color: currentColor;
 }
 
-#mainPrefPane groupbox,
-#mainPrefPane deck,
-#mainPrefPane description {
-  font-size: 1.36rem;
-}
-
 groupbox + groupbox {
   margin-top: 16px;
 }
 
 groupbox + groupbox > .groupbox-body,
 groupbox + vbox groupbox > .groupbox-body {
   margin-top: 4px;
 }
 
 .groupbox-title {
   margin-top: 16px;
 }
 
-input,
-description.indent,
-.indent > description {
-  font-size: 1.18rem !important;
-}
-
 description.indent,
 .indent > description {
   color: #737373;
 }
 
 button,
 treecol,
 html|option {
@@ -114,21 +102,16 @@ separator.thin:not([orient="vertical"]) 
  */
 
 .subcategory:not([hidden]) ~ .subcategory {
   margin-top: 32px;
   padding-top: 15px;
   border-top: 1px solid rgba(12, 12, 13, 0.15);
 }
 
-.header-name {
-  font-size: 2rem;
-  font-weight: 300;
-}
-
 /* Category List */
 
 #category-general > .category-icon {
   list-style-image: url("chrome://browser/skin/preferences/in-content/general.svg");
 }
 
 #category-search > .category-icon {
   list-style-image: url("chrome://browser/skin/preferences/in-content/search.svg");
@@ -149,16 +132,21 @@ separator.thin:not([orient="vertical"]) 
   justify-content: space-between;
 }
 
 .header[hidden=true] {
   display: none;
 }
 
 /* General Pane */
+
+#isDefaultLabel {
+  font-weight: 600;
+}
+
 #startupPageBox {
   padding-top: 32px;
 }
 
 #browserHomePage {
   margin-inline-start: 0;
   margin-inline-end: 0;
 }
@@ -170,21 +158,16 @@ separator.thin:not([orient="vertical"]) 
 .homepage-button:last-of-type {
   margin-inline-end: 0;
 }
 
 #getStarted {
   font-size: 90%;
 }
 
-#isNotDefaultLabel,
-#signedOutAccountBoxTitle {
-  font-weight: 600;
-}
-
 #downloadFolder {
   margin-inline-start: 0;
 }
 
 #browserHomePage:-moz-locale-dir(rtl) input {
   unicode-bidi: plaintext;
   direction: rtl;
 }
@@ -498,17 +481,16 @@ separator.thin:not([orient="vertical"]) 
   margin-bottom: 0;
 }
 
 #tosPP-small-ToS {
   margin-bottom: 14px;
 }
 
 #noFxaCaption {
-  font-weight: bold;
   line-height: 30px;
   margin-top: 0;
   margin-bottom: 4px;
 }
 
 #noFxaSignIn {
   margin-inline-start: 8px;
 }
@@ -526,31 +508,26 @@ separator.thin:not([orient="vertical"]) 
 .separator {
   border-bottom: 1px solid var(--in-content-box-border-color);
 }
 
 #fxaGroup {
   margin-bottom: 32px;
 }
 
-#signedOutAccountBoxTitle {
-  font-weight: bold;
-}
-
 .openLink {
   line-height: 30px;
   cursor: pointer;
 }
 
 .openLink:visited {
   color: var(--in-content-link-color);
 }
 
 #fxaDisplayName {
-  font-weight: bold;
   margin-inline-end: 10px !important;
 }
 
 .fxaEmailAddress {
   margin-inline-end: 8px !important;
 }
 
 .fxaLoginRejectedWarning {
@@ -605,17 +582,16 @@ separator.thin:not([orient="vertical"]) 
 
 .help-button {
   position: fixed;
   left: 0;
   bottom: 36px;
   background-image: url("chrome://global/skin/icons/help.svg");
   -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
-  font-size: 13px;
   line-height: 36px;
   height: 36px;
   width: 168px;
   background-position: left 10px top 10px;
   background-size: 16px;
   padding-inline-start: 38px;
   margin-inline-start: 34px;
   white-space: nowrap;
@@ -660,17 +636,16 @@ separator.thin:not([orient="vertical"]) 
   position: sticky;
   background-color: var(--in-content-page-background);
   width: 100%;
   top: 0;
   z-index: 1;
 }
 
 #searchInput {
-  width: 250px;
   margin: 20px 0 30px 0;
 }
 
 #searchInput .textbox-search-icons:not([selectedIndex="1"]) {
   display: none;
 }
 
 .search-tooltip {
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -453,21 +453,21 @@ toolbar[brighttext] .toolbarbutton-1 {
   from {
     fill: var(--toolbarbutton-icon-fill-attention);
   }
   to {
     fill: inherit;
   }
 }
 
-#library-button[animate="bookmark"] > .toolbarbutton-icon {
+#library-button[animate] > .toolbarbutton-icon {
   fill: transparent;
 }
 
-.toolbarbutton-animatable-box[animate="bookmark"] {
+.toolbarbutton-animatable-box[animate] {
   position: absolute;
   overflow: hidden;
   /* Position the sprite at the y-position of the library-button, then adjust
      based on the size difference between half of the button height and half
      of the sprite height. */
   top: calc(var(--library-button-y) + var(--library-button-height) / 2 - 27px);
   /* Set a margin relative to the difference in widths of the .toolbarbutton-icon
      and the .toolbar-animatable-box. This is correct even in RTL because the item
@@ -477,19 +477,22 @@ toolbar[brighttext] .toolbarbutton-1 {
      of each frame of the SVG sprite (must use min- and max- due to bug 1379332). */
   min-width: 22px;
   max-width: 22px;
   min-height: 54px;
   max-height: 54px;
   z-index: 2;
 }
 
-.toolbarbutton-animatable-box[animate="bookmark"] > .toolbarbutton-animatable-image {
+.toolbarbutton-animatable-box[animate] > .toolbarbutton-animatable-image {
   height: var(--toolbarbutton-height);
   min-height: 54px; /* Minimum height must be equal to the height of the SVG sprite */
+}
+
+.toolbarbutton-animatable-box[animate="bookmark"] > .toolbarbutton-animatable-image {
   background-image: url("chrome://browser/skin/library-bookmark-animation.svg");
   width: 1078px;
   animation-name: library-bookmark-animation;
   animation-duration: 800ms;
   animation-timing-function: steps(48);
   -moz-context-properties: fill, stroke;
   stroke: var(--toolbarbutton-icon-fill-attention);
 }
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -1,16 +1,19 @@
 /* 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/. */
 
 :root {
   --toolbarbutton-hover-background: hsla(240,5%,5%,.1);
   --toolbarbutton-active-background: hsla(240,5%,5%,.15);
 
+  --toolbarbutton-hover-transition-duration: 150ms;
+  --toolbarbutton-active-transition-duration: 10ms;
+
   --toolbarbutton-inner-padding: 6px;
 
   --backbutton-background: hsla(0,100%,100%,.8);
   --backbutton-hover-background: var(--backbutton-background);
   --backbutton-active-background: var(--toolbarbutton-active-background);
   --backbutton-border-color: hsla(240,5%,5%,.3);
 
   /* This default value of --toolbarbutton-height is defined to prevent
@@ -105,17 +108,17 @@ toolbar .toolbarbutton-1 > menupopup.cui
 .findbar-button > .toolbarbutton-text,
 toolbarbutton.bookmark-item:not(.subviewbutton),
 toolbar .toolbarbutton-1 > .toolbarbutton-icon,
 toolbar .toolbarbutton-1 > .toolbarbutton-text,
 toolbar .toolbarbutton-1 > .toolbarbutton-badge-stack {
   padding: var(--toolbarbutton-inner-padding);
   border-radius: var(--toolbarbutton-border-radius);
   transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
+  transition-duration: var(--toolbarbutton-hover-transition-duration);
 }
 
 toolbar .toolbarbutton-1 > .toolbarbutton-icon {
   /* horizontal padding + actual icon width */
   max-width: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
 }
 
 .bookmark-item > .toolbarbutton-menu-dropmarker,
@@ -173,17 +176,17 @@ toolbar .toolbarbutton-1:not([disabled=t
 
 .findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
 toolbarbutton.bookmark-item:not(.subviewbutton):hover:active:not([disabled="true"]),
 toolbarbutton.bookmark-item[open="true"],
 toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
 toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
 toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
   background-color: var(--toolbarbutton-active-background);
-  transition-duration: 10ms;
+  transition-duration: var(--toolbarbutton-active-transition-duration);
   color: inherit;
 }
 
 toolbar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
   background-color: var(--toolbarbutton-hover-background);
   transition: background-color .4s;
 }
 
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -113,18 +113,16 @@
 #pageAction-urlbar-sendToDevice-fxa {
   list-style-image: url("chrome://browser/skin/sync.svg");
 }
 
 /* URL bar and page action buttons */
 
 #page-action-buttons {
   -moz-box-align: center;
-  /* Add more space between the last icon and the urlbar's edge. */
-  margin-inline-end: 3px;
 }
 
 #pageActionSeparator {
   /* This draws the separator the same way that #urlbar-display-box draws its
      left and right borders, which end up looking like separators.  It might not
      be the best way in this case, but it makes sure that all these vertical
      lines in the urlbar look the same: same height, vertical position, etc. */
   border-inline-start: 1px solid var(--urlbar-separator-color);
@@ -153,28 +151,49 @@
 
 #userContext-icons,
 #urlbar-zoom-button {
   margin-left: 6px;
   margin-right: 6px;
 }
 
 .urlbar-icon {
-  padding: 0 6px;
-  /* 16x16 icon with border-box sizing */
   width: 28px;
-  height: 16px;
+  height: 28px;
+  /* 28x28 box - 16x16 image = 12x12 padding, 6 on each side */
+  padding: 6px;
   -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
   fill-opacity: 0.6;
   color: inherit;
+  transition-property: background-color;
+  transition-duration: var(--toolbarbutton-hover-transition-duration);
+}
+
+:root[uidensity=compact] .urlbar-icon {
+  width: 24px;
+  height: 24px;
+  /* 24x24 box - 16x16 image = 8x8 padding, 4 on each side */
+  padding: 4px;
+}
+
+:root[uidensity=touch] .urlbar-icon {
+  width: 30px;
+  height: 30px;
+  /* 30x30 box - 16x16 image = 14x14 padding, 7 on each side */
+  padding: 7px;
 }
 
 .urlbar-icon:hover {
-  fill-opacity: 0.8;
+  background-color: hsla(0,0%,80%,.4);
+}
+
+.urlbar-icon:hover:active {
+  background-color: hsla(0,0%,80%,.45);
+  transition-duration: var(--toolbarbutton-active-transition-duration);
 }
 
 .urlbar-go-button,
 .search-go-button {
   list-style-image: url("chrome://browser/skin/back.svg");
   width: 26px;
 }
 
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -174,21 +174,18 @@ skip-if = (os == "win" && debug) # bug 9
 [browser_rules_inherited-properties_02.js]
 [browser_rules_inherited-properties_03.js]
 [browser_rules_inherited-properties_04.js]
 [browser_rules_inline-source-map.js]
 [browser_rules_invalid.js]
 [browser_rules_invalid-source-map.js]
 [browser_rules_keybindings.js]
 [browser_rules_keyframes-rule_01.js]
-skip-if = stylo # Bug 1394994
 [browser_rules_keyframes-rule_02.js]
-skip-if = stylo # Bug 1394994
 [browser_rules_keyframeLineNumbers.js]
-skip-if = stylo # Bug 1394994
 [browser_rules_lineNumbers.js]
 [browser_rules_livepreview.js]
 [browser_rules_mark_overridden_01.js]
 [browser_rules_mark_overridden_02.js]
 [browser_rules_mark_overridden_03.js]
 [browser_rules_mark_overridden_04.js]
 [browser_rules_mark_overridden_05.js]
 [browser_rules_mark_overridden_06.js]
@@ -213,17 +210,16 @@ skip-if = stylo # Bug 1394994
 [browser_rules_search-filter-computed-list_01.js]
 [browser_rules_search-filter-computed-list_02.js]
 [browser_rules_search-filter-computed-list_03.js]
 [browser_rules_search-filter-computed-list_04.js]
 [browser_rules_search-filter-computed-list_expander.js]
 [browser_rules_search-filter-overridden-property.js]
 [browser_rules_search-filter_01.js]
 [browser_rules_search-filter_02.js]
-skip-if = stylo # Bug 1394994
 [browser_rules_search-filter_03.js]
 [browser_rules_search-filter_04.js]
 [browser_rules_search-filter_05.js]
 [browser_rules_search-filter_06.js]
 [browser_rules_search-filter_07.js]
 [browser_rules_search-filter_08.js]
 [browser_rules_search-filter_09.js]
 [browser_rules_search-filter_10.js]
--- a/devtools/server/actors/breakpoint.js
+++ b/devtools/server/actors/breakpoint.js
@@ -135,25 +135,38 @@ let BreakpointActor = ActorClassWithSpec
    *
    * @param frame Debugger.Frame
    *        The stack frame that contained the breakpoint.
    */
   hit: function (frame) {
     // Don't pause if we are currently stepping (in or over) or the frame is
     // black-boxed.
     let generatedLocation = this.threadActor.sources.getFrameLocation(frame);
-    let { originalSourceActor } = this.threadActor.unsafeSynchronize(
+    let {
+      originalSourceActor,
+      originalLine,
+      originalColumn
+    } = this.threadActor.unsafeSynchronize(
       this.threadActor.sources.getOriginalLocation(generatedLocation));
     let url = originalSourceActor.url;
 
     if (this.threadActor.sources.isBlackBoxed(url)
         || frame.onStep) {
       return undefined;
     }
 
+    // If we're trying to pop this frame, and we see a breakpoint at
+    // the spot at which popping started, ignore it.  See bug 970469.
+    const locationAtFinish = frame.onPop && frame.onPop.originalLocation;
+    if (locationAtFinish &&
+        locationAtFinish.originalLine === originalLine &&
+        locationAtFinish.originalColumn === originalColumn) {
+      return undefined;
+    }
+
     let reason = {};
 
     if (this.threadActor._hiddenBreakpoints.has(this.actorID)) {
       reason.type = "pauseOnDOMEvents";
     } else if (!this.condition) {
       reason.type = "breakpoint";
       // TODO: add the rest of the breakpoints on that line (bug 676602).
       reason.actors = [ this.actorID ];
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -770,19 +770,19 @@ const ThreadActor = ActorClassWithSpec(t
       let url = originalSourceActor.url;
 
       return this.sources.isBlackBoxed(url)
         ? undefined
         : pauseAndRespond(frame);
     };
   },
 
-  _makeOnPop: function (
-    { thread, pauseAndRespond, createValueGrip: createValueGripHook }) {
-    return function (completion) {
+  _makeOnPop: function ({ thread, pauseAndRespond, createValueGrip: createValueGripHook,
+                          startLocation }) {
+    const result = function (completion) {
       // onPop is called with 'this' set to the current frame.
 
       const generatedLocation = thread.sources.getFrameLocation(this);
       const { originalSourceActor } = thread.unsafeSynchronize(
         thread.sources.getOriginalLocation(generatedLocation));
       const url = originalSourceActor.url;
 
       if (thread.sources.isBlackBoxed(url)) {
@@ -802,16 +802,27 @@ const ThreadActor = ActorClassWithSpec(t
         } else if (completion.hasOwnProperty("yield")) {
           packet.why.frameFinished.return = createValueGripHook(completion.yield);
         } else {
           packet.why.frameFinished.throw = createValueGripHook(completion.throw);
         }
         return packet;
       });
     };
+
+    // When stepping out, we don't want to stop at a breakpoint that
+    // happened to be set exactly at the spot where we stepped out.
+    // See bug 970469.  We record the original location here and check
+    // it when a breakpoint is hit.  Furthermore we store this on the
+    // function because, while we could store it directly on the
+    // frame, if we did we'd also have to find the appropriate spot to
+    // clear it.
+    result.originalLocation = startLocation;
+
+    return result;
   },
 
   _makeOnStep: function ({ thread, pauseAndRespond, startFrame,
                            startLocation, steppingType }) {
     // Breaking in place: we should always pause.
     if (steppingType === "break") {
       return function () {
         return pauseAndRespond(this);
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -543,51 +543,49 @@ var StyleSheetActor = protocol.ActorClas
    * Fetch the source map for this stylesheet.
    *
    * @return {Promise}
    *         A promise that resolves with a SourceMapConsumer, or null.
    */
   _fetchSourceMap: function () {
     let deferred = defer();
 
-    this._getText().then(sheetContent => {
-      let url = this._extractSourceMapUrl(sheetContent);
-      if (!url) {
-        // no source map for this stylesheet
-        deferred.resolve(null);
-        return;
-      }
+    let url = this.rawSheet.sourceMapURL;
+    if (!url) {
+      // no source map for this stylesheet
+      deferred.resolve(null);
+      return deferred.promise;
+    }
 
-      url = normalize(url, this.safeHref);
-      let options = {
-        loadFromCache: false,
-        policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
-        window: this.window
-      };
+    url = normalize(url, this.safeHref);
+    let options = {
+      loadFromCache: false,
+      policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
+      window: this.window
+    };
 
-      let map = fetch(url, options).then(({content}) => {
-        // Fetching the source map might have failed with a 404 or other. When
-        // this happens, SourceMapConsumer may fail with a JSON.parse error.
-        let consumer;
-        try {
-          consumer = new SourceMapConsumer(content);
-        } catch (e) {
-          deferred.reject(new Error(
-            `Source map at ${url} not found or invalid`));
-          return null;
-        }
-        this._setSourceMapRoot(consumer, url, this.safeHref);
-        this._sourceMap = promise.resolve(consumer);
+    let map = fetch(url, options).then(({content}) => {
+      // Fetching the source map might have failed with a 404 or other. When
+      // this happens, SourceMapConsumer may fail with a JSON.parse error.
+      let consumer;
+      try {
+        consumer = new SourceMapConsumer(content);
+      } catch (e) {
+        deferred.reject(new Error(
+          `Source map at ${url} not found or invalid`));
+        return null;
+      }
+      this._setSourceMapRoot(consumer, url, this.safeHref);
+      this._sourceMap = promise.resolve(consumer);
 
-        deferred.resolve(consumer);
-        return consumer;
-      }, deferred.reject);
+      deferred.resolve(consumer);
+      return consumer;
+    }, deferred.reject);
 
-      this._sourceMap = map;
-    }, deferred.reject);
+    this._sourceMap = map;
 
     return deferred.promise;
   },
 
   /**
    * Clear and unmanage the original source actors for this stylesheet.
    */
   _clearOriginalSources: function () {
@@ -609,36 +607,16 @@ var StyleSheetActor = protocol.ActorClas
         ? scriptURL
         : absSourceMapURL);
     sourceMap.sourceRoot = sourceMap.sourceRoot
       ? normalize(sourceMap.sourceRoot, base)
       : base;
   },
 
   /**
-   * Get the source map url specified in the text of a stylesheet.
-   *
-   * @param  {string} content
-   *         The text of the style sheet.
-   * @return {string}
-   *         Url of source map.
-   */
-  _extractSourceMapUrl: function (content) {
-    // If a SourceMap response header was saved on the style sheet, use it.
-    if (this.rawSheet.sourceMapURL) {
-      return this.rawSheet.sourceMapURL;
-    }
-    let matches = /sourceMappingURL\=([^\s\*]*)/.exec(content);
-    if (matches) {
-      return matches[1];
-    }
-    return null;
-  },
-
-  /**
    * Protocol method that gets the location in the original source of a
    * line, column pair in this stylesheet, if its source mapped, otherwise
    * a promise of the same location.
    */
   getOriginalLocation: function (line, column) {
     return this.getSourceMap().then((sourceMap) => {
       if (sourceMap) {
         return sourceMap.originalPositionFor({ line: line, column: column });
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -762,16 +762,30 @@ function stepIn(client, threadClient) {
  */
 function stepOver(client, threadClient) {
   dumpn("Stepping over.");
   return threadClient.stepOver()
     .then(() => waitForPause(client));
 }
 
 /**
+ * Resume JS execution for a step out and wait for the pause after the step
+ * has been taken.
+ *
+ * @param DebuggerClient client
+ * @param ThreadClient threadClient
+ * @returns Promise
+ */
+function stepOut(client, threadClient) {
+  dumpn("Stepping out.");
+  return threadClient.stepOut()
+    .then(() => waitForPause(client));
+}
+
+/**
  * Get the list of `count` frames currently on stack, starting at the index
  * `first` for the specified thread.
  *
  * @param ThreadClient threadClient
  * @param Number first
  * @param Number count
  * @returns Promise
  */
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Check that step out doesn't double stop on a breakpoint.  Bug 970469.
+ */
+
+var gDebuggee;
+var gClient;
+var gCallback;
+
+function run_test() {
+  do_test_pending();
+  run_test_with_server(DebuggerServer, function () {
+    run_test_with_server(WorkerDebuggerServer, do_test_finished);
+  });
+}
+
+function run_test_with_server(server, callback) {
+  gCallback = callback;
+  initTestDebuggerServer(server);
+  gDebuggee = addTestGlobal("test-stepping", server);
+  gClient = new DebuggerClient(server.connectPipe());
+  gClient.connect(testStepOutWithBreakpoint);
+}
+
+async function testStepOutWithBreakpoint() {
+  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
+                                                                       "test-stepping");
+  ok(!attachResponse.error, "Should not get an error attaching");
+
+  dumpn("Evaluating test code and waiting for first debugger statement");
+  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  equal(dbgStmt.frame.where.line, 3, "Should be at debugger statement on line 3");
+
+  dumpn("Setting breakpoint in innerFunction");
+  const source = threadClient.source(dbgStmt.frame.where.source);
+  await source.setBreakpoint({ line: 7 });
+
+  dumpn("Step in to innerFunction");
+  const step1 = await stepIn(gClient, threadClient);
+  equal(step1.frame.where.line, 7);
+
+  dumpn("Step out of innerFunction");
+  const step2 = await stepOut(gClient, threadClient);
+  // The bug was that we'd stop again at the breakpoint on line 7.
+  equal(step2.frame.where.line, 10);
+
+  finishClient(gClient, gCallback);
+}
+
+function evaluateTestCode() {
+  /* eslint-disable */
+  Cu.evalInSandbox(
+    `                                   //  1
+    function outerFunction() {          //  2
+      debugger; innerFunction();        //  3
+    }                                   //  4
+                                        //  5
+    function innerFunction() {          //  6
+      let x = 0;                        //  7
+      let y = 72;                       //  8
+      return x+y;                       //  9
+    }                                   // 10
+    outerFunction();                    // 11
+    `,                                  // 12
+    gDebuggee,
+    "1.8",
+    "test_stepping-08-test-code.js",
+    1
+  );
+  /* eslint-enable */
+}
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -180,16 +180,17 @@ reason = only ran on B2G
 [test_interrupt.js]
 [test_stepping-01.js]
 [test_stepping-02.js]
 [test_stepping-03.js]
 [test_stepping-04.js]
 [test_stepping-05.js]
 [test_stepping-06.js]
 [test_stepping-07.js]
+[test_stepping-08.js]
 [test_framebindings-01.js]
 [test_framebindings-02.js]
 [test_framebindings-03.js]
 [test_framebindings-04.js]
 [test_framebindings-05.js]
 [test_framebindings-06.js]
 [test_framebindings-07.js]
 [test_pause_exceptions-01.js]
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -876,42 +876,42 @@ EffectCompositor::UpdateCascadeResults(S
   nsCSSPropertyIDSet& propertiesForAnimationsLevel =
     aEffectSet.PropertiesForAnimationsLevel();
 
   // Record which compositor-animatable properties were originally set so we can
   // compare for changes later.
   std::bitset<LayerAnimationInfo::kRecords>
     prevCompositorPropertiesWithImportantRules =
       compositorPropertiesInSet(propertiesWithImportantRules);
-  std::bitset<LayerAnimationInfo::kRecords>
-    prevCompositorPropertiesForAnimationsLevel =
-      compositorPropertiesInSet(propertiesForAnimationsLevel);
+
+  nsCSSPropertyIDSet prevPropertiesForAnimationsLevel =
+    propertiesForAnimationsLevel;
 
   propertiesWithImportantRules.Empty();
   propertiesForAnimationsLevel.Empty();
 
-  bool hasCompositorPropertiesForTransition = false;
+  nsCSSPropertyIDSet propertiesForTransitionsLevel;
 
   for (const KeyframeEffectReadOnly* effect : sortedEffectList) {
     MOZ_ASSERT(effect->GetAnimation(),
                "Effects on a target element should have an Animation");
     CascadeLevel cascadeLevel = effect->GetAnimation()->CascadeLevel();
 
     for (const AnimationProperty& prop : effect->Properties()) {
       if (overriddenProperties.HasProperty(prop.mProperty)) {
         propertiesWithImportantRules.AddProperty(prop.mProperty);
       }
-      if (cascadeLevel == EffectCompositor::CascadeLevel::Animations) {
-        propertiesForAnimationsLevel.AddProperty(prop.mProperty);
-      }
 
-      if (nsCSSProps::PropHasFlags(prop.mProperty,
-                                   CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
-          cascadeLevel == EffectCompositor::CascadeLevel::Transitions) {
-        hasCompositorPropertiesForTransition = true;
+      switch (cascadeLevel) {
+        case EffectCompositor::CascadeLevel::Animations:
+          propertiesForAnimationsLevel.AddProperty(prop.mProperty);
+          break;
+        case EffectCompositor::CascadeLevel::Transitions:
+          propertiesForTransitionsLevel.AddProperty(prop.mProperty);
+          break;
       }
     }
   }
 
   aEffectSet.MarkCascadeUpdated();
 
   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
   if (!presContext) {
@@ -924,25 +924,33 @@ EffectCompositor::UpdateCascadeResults(S
   // the compositor or pull animations back from the compositor.
   if (prevCompositorPropertiesWithImportantRules !=
         compositorPropertiesInSet(propertiesWithImportantRules)) {
     presContext->EffectCompositor()->
       RequestRestyle(aElement, aPseudoType,
                      EffectCompositor::RestyleType::Layer,
                      EffectCompositor::CascadeLevel::Animations);
   }
-  // If we have transition properties for compositor and if the same propery
-  // for animations level is newly added or removed, we need to update layers
-  // for transitions level because composite order has been changed now.
-  if (hasCompositorPropertiesForTransition &&
-      prevCompositorPropertiesForAnimationsLevel !=
-        compositorPropertiesInSet(propertiesForAnimationsLevel)) {
+
+  // If we have transition properties and if the same propery for animations
+  // level is newly added or removed, we need to update the transition level
+  // rule since the it will be added/removed from the rule tree.
+  nsCSSPropertyIDSet changedPropertiesForAnimationLevel =
+    prevPropertiesForAnimationsLevel.Xor(propertiesForAnimationsLevel);
+  nsCSSPropertyIDSet commonProperties =
+    propertiesForTransitionsLevel.Intersect(
+      changedPropertiesForAnimationLevel);
+  if (!commonProperties.IsEmpty()) {
+    EffectCompositor::RestyleType restyleType =
+      compositorPropertiesInSet(changedPropertiesForAnimationLevel).none()
+      ? EffectCompositor::RestyleType::Standard
+      : EffectCompositor::RestyleType::Layer;
     presContext->EffectCompositor()->
       RequestRestyle(aElement, aPseudoType,
-                     EffectCompositor::RestyleType::Layer,
+                     restyleType,
                      EffectCompositor::CascadeLevel::Transitions);
   }
 }
 
 /* static */ void
 EffectCompositor::SetPerformanceWarning(
   const nsIFrame *aFrame,
   nsCSSPropertyID aProperty,
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -275,17 +275,18 @@ private:
   static nsCSSPropertyIDSet
   GetOverriddenProperties(StyleBackendType aBackendType,
                           EffectSet& aEffectSet,
                           dom::Element* aElement,
                           CSSPseudoElementType aPseudoType,
                           nsStyleContext* aStyleContext);
 
   // Update the mPropertiesWithImportantRules and
-  // mPropertiesForAnimationsLevel members of the given EffectSet.
+  // mPropertiesForAnimationsLevel members of the given EffectSet, and also
+  // request any restyles required by changes to the cascade result.
   //
   // This can be expensive so we should only call it if styles that apply
   // above the animation level of the cascade might have changed. For all
   // other cases we should call MaybeUpdateCascadeResults.
   //
   // As with MaybeUpdateCascadeResults, |aStyleContext| is only used
   // when |aBackendType| is StyleBackendType::Gecko. When |aBackendType| is
   // StyleBackendType::Servo, it is ignored.
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -95,16 +95,17 @@ support-files =
 [css-transitions/test_effect-target.html]
 [css-transitions/test_element-get-animations.html]
 [css-transitions/test_event-dispatch.html]
 [css-transitions/test_keyframeeffect-getkeyframes.html]
 [css-transitions/test_pseudoElement-get-animations.html]
 [css-transitions/test_setting-effect.html]
 [document-timeline/test_document-timeline.html]
 [document-timeline/test_request_animation_frame.html]
+[mozilla/test_cascade.html]
 [mozilla/test_cubic_bezier_limits.html]
 [mozilla/test_deferred_start.html]
 [mozilla/test_disable_animations_api_core.html]
 [mozilla/test_disabled_properties.html]
 [mozilla/test_discrete-animations.html]
 [mozilla/test_distance_of_transform.html]
 [mozilla/test_document-timeline-origin-time-range.html]
 [mozilla/test_hide_and_show.html]
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/mozilla/test_cascade.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
+<style>
+@keyframes margin-left {
+  from { margin-left: 20px; }
+  to   { margin-left: 80px; }
+}
+</style>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(function(t) {
+  var div = addDiv(t, { style: 'transition: margin-left 100s; ' +
+                               'margin-left: 80px' });
+  var cs = getComputedStyle(div);
+
+  assert_equals(cs.marginLeft, '80px', 'initial margin-left');
+
+  div.style.marginLeft = "20px";
+  assert_equals(cs.marginLeft, '80px', 'margin-left transition at 0s');
+
+  div.style.animation = "margin-left 2s";
+  assert_equals(cs.marginLeft, '20px',
+                'margin-left animation overrides transition at 0s');
+
+  div.style.animation = "none";
+  assert_equals(cs.marginLeft, '80px',
+                'margin-left animation stops overriding transition at 0s');
+}, 'Animation overrides/stops overriding transition immediately');
+
+</script>
+</body>
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -21,19 +21,21 @@
 #include "nsIDOMMutationEvent.h"
 #include "nsXULElement.h"
 #include "nsContentUtils.h"
 #include "nsStyleUtil.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_QUERY_INTERFACE_INHERITED(nsStyledElement,
-                                  nsStyledElementBase,
-                                  nsStyledElement)
+// Use the CC variant of this, even though this class does not define
+// a new CC participant, to make QIing to the CC interfaces faster.
+NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
+                                                   nsStyledElementBase,
+                                                   nsStyledElement)
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 bool
 nsStyledElement::ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -92,18 +92,20 @@ private:
   int32_t mNameSpaceID;
   nsCOMPtr<nsIAtom> mAttrName;
 };
 
 nsTextNode::~nsTextNode()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode,
-                            nsIDOMText, nsIDOMCharacterData)
+// Use the CC variant of this, even though this class does not define
+// a new CC participant, to make QIing to the CC interfaces faster.
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode,
+                                             nsIDOMText, nsIDOMCharacterData)
 
 JSObject*
 nsTextNode::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return TextBinding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -53,24 +53,20 @@ HTMLAnchorElement::~HTMLAnchorElement()
 
 bool
 HTMLAnchorElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
          nsGenericHTMLElement::IsInteractiveHTMLContent(aIgnoreTabindex);
 }
 
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement)
-  NS_INTERFACE_TABLE_INHERITED(HTMLAnchorElement,
-                               nsIDOMHTMLAnchorElement,
-                               Link)
-NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
-
-NS_IMPL_ADDREF_INHERITED(HTMLAnchorElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLAnchorElement, Element)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement,
+                                             nsGenericHTMLElement,
+                                             nsIDOMHTMLAnchorElement,
+                                             Link)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAnchorElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAnchorElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -23,36 +23,24 @@ HTMLAreaElement::HTMLAreaElement(already
   , Link(this)
 {
 }
 
 HTMLAreaElement::~HTMLAreaElement()
 {
 }
 
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLAreaElement)
-  NS_INTERFACE_TABLE_INHERITED(HTMLAreaElement,
-                               nsIDOMHTMLAreaElement,
-                               Link)
-NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
-
-NS_IMPL_ADDREF_INHERITED(HTMLAreaElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLAreaElement, Element)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLAreaElement,
+                                             nsGenericHTMLElement,
+                                             nsIDOMHTMLAreaElement,
+                                             Link)
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAreaElement)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAreaElement,
-                                                  nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLAreaElement,
-                                                nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLAreaElement,
+                                   nsGenericHTMLElement,
+                                   mRelList)
 
 NS_IMPL_ELEMENT_CLONE(HTMLAreaElement)
 
 
 NS_IMPL_STRING_ATTR(HTMLAreaElement, Alt, alt)
 NS_IMPL_STRING_ATTR(HTMLAreaElement, Coords, coords)
 NS_IMPL_URI_ATTR(HTMLAreaElement, Href, href)
 NS_IMPL_BOOL_ATTR(HTMLAreaElement, NoHref, nohref)
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -71,26 +71,20 @@ HTMLButtonElement::~HTMLButtonElement()
 }
 
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLButtonElement,
                                    nsGenericHTMLFormElementWithState,
                                    mValidity)
 
-NS_IMPL_ADDREF_INHERITED(HTMLButtonElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLButtonElement, Element)
-
-
-// QueryInterface implementation for HTMLButtonElement
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLButtonElement)
-  NS_INTERFACE_TABLE_INHERITED(HTMLButtonElement,
-                               nsIDOMHTMLButtonElement,
-                               nsIConstraintValidation)
-NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLButtonElement,
+                                             nsGenericHTMLFormElementWithState,
+                                             nsIDOMHTMLButtonElement,
+                                             nsIConstraintValidation)
 
 void
 HTMLButtonElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
 
   UpdateState(true);
 }
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -399,22 +399,19 @@ HTMLCanvasElement::~HTMLCanvasElement()
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
                                    mCurrentContext, mPrintCallback,
                                    mPrintState, mOriginalCanvas,
                                    mOffscreenCanvas)
 
-NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element)
-
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement)
-  NS_INTERFACE_TABLE_INHERITED(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
-NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement,
+                                             nsGenericHTMLElement,
+                                             nsIDOMHTMLCanvasElement)
 
 NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
 
 /* virtual */ JSObject*
 HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/html/HTMLEmbedElement.cpp
+++ b/dom/html/HTMLEmbedElement.cpp
@@ -50,31 +50,26 @@ HTMLEmbedElement::~HTMLEmbedElement()
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLEmbedElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLEmbedElement,
                                                   nsGenericHTMLElement)
 nsObjectLoadingContent::Traverse(tmp, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_ADDREF_INHERITED(HTMLEmbedElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLEmbedElement, Element)
-
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLEmbedElement)
-NS_INTERFACE_TABLE_INHERITED(HTMLEmbedElement,
-                             nsIRequestObserver,
-                             nsIStreamListener,
-                             nsIFrameLoaderOwner,
-                             nsIObjectLoadingContent,
-                             imgINotificationObserver,
-                             nsIImageLoadingContent,
-                             imgIOnloadBlocker,
-                             nsIChannelEventSink)
-NS_INTERFACE_TABLE_TO_MAP_SEGUE
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLEmbedElement,
+                                             nsGenericHTMLElement,
+                                             nsIRequestObserver,
+                                             nsIStreamListener,
+                                             nsIFrameLoaderOwner,
+                                             nsIObjectLoadingContent,
+                                             imgINotificationObserver,
+                                             nsIImageLoadingContent,
+                                             imgIOnloadBlocker,
+                                             nsIChannelEventSink)
 
 NS_IMPL_ELEMENT_CLONE(HTMLEmbedElement)
 
 #ifdef XP_MACOSX
 
 NS_IMETHODIMP
 HTMLEmbedElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
--- a/dom/media/ADTSDecoder.cpp
+++ b/dom/media/ADTSDecoder.cpp
@@ -16,21 +16,19 @@ ADTSDecoder::IsEnabled()
   RefPtr<PDMFactory> platform = new PDMFactory();
   return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"),
                                     /* DecoderDoctorDiagnostics* */ nullptr);
 }
 
 /* static */ bool
 ADTSDecoder::IsSupportedType(const MediaContainerType& aContainerType)
 {
-  if (aContainerType.Type() == MEDIAMIMETYPE("audio/aac")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/aacp")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/x-aac")) {
-    return
-      IsEnabled()
-      && (aContainerType.ExtendedType().Codecs().IsEmpty()
-          || aContainerType.ExtendedType().Codecs() == "aac");
+  if (aContainerType.Type() == MEDIAMIMETYPE("audio/aac") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/aacp") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/x-aac")) {
+    return IsEnabled() && (aContainerType.ExtendedType().Codecs().IsEmpty() ||
+                           aContainerType.ExtendedType().Codecs() == "aac");
   }
 
   return false;
 }
 
 } // namespace mozilla
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -192,18 +192,18 @@ BenchmarkPlayback::DemuxNextSample()
   MOZ_ASSERT(OnThread());
 
   RefPtr<Benchmark> ref(mMainThreadState);
   RefPtr<MediaTrackDemuxer::SamplesPromise> promise = mTrackDemuxer->GetSamples();
   promise->Then(
     Thread(), __func__,
     [this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> aHolder) {
       mSamples.AppendElements(Move(aHolder->mSamples));
-      if (ref->mParameters.mStopAtFrame
-          && mSamples.Length() == (size_t)ref->mParameters.mStopAtFrame.ref()) {
+      if (ref->mParameters.mStopAtFrame &&
+          mSamples.Length() == (size_t)ref->mParameters.mStopAtFrame.ref()) {
         InitDecoder(Move(*mTrackDemuxer->GetInfo()));
       } else {
         Dispatch(NS_NewRunnableFunction("BenchmarkPlayback::DemuxNextSample",
                                         [this, ref]() { DemuxNextSample(); }));
       }
     },
     [this, ref](const MediaResult& aError) {
       switch (aError.Code()) {
@@ -286,20 +286,19 @@ BenchmarkPlayback::Output(const MediaDat
   RefPtr<Benchmark> ref(mMainThreadState);
   mFrameCount += aResults.Length();
   if (!mDecodeStartTime && mFrameCount >= ref->mParameters.mStartupFrame) {
     mDecodeStartTime = Some(TimeStamp::Now());
   }
   TimeStamp now = TimeStamp::Now();
   int32_t frames = mFrameCount - ref->mParameters.mStartupFrame;
   TimeDuration elapsedTime = now - mDecodeStartTime.refOr(now);
-  if (!mFinished
-      && (((frames == ref->mParameters.mFramesToMeasure) && frames > 0)
-          || elapsedTime >= ref->mParameters.mTimeout
-          || mDrained)) {
+  if (!mFinished &&
+      (((frames == ref->mParameters.mFramesToMeasure) && frames > 0) ||
+       elapsedTime >= ref->mParameters.mTimeout || mDrained)) {
     uint32_t decodeFps = frames / elapsedTime.ToSeconds();
     MainThreadShutdown();
     ref->Dispatch(
       NS_NewRunnableFunction("BenchmarkPlayback::Output", [ref, decodeFps]() {
         ref->ReturnResult(decodeFps);
       }));
   }
 }
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -338,18 +338,18 @@ bool InitPreferredChannelLayout()
   sPreferredChannelLayout = layout;
   return true;
 }
 
 uint32_t PreferredChannelMap(uint32_t aChannels)
 {
   // Use SMPTE default channel map if we can't get preferred layout
   // or the channel counts of preferred layout is different from input's one
-  if (!InitPreferredChannelLayout()
-      || kLayoutInfos[sPreferredChannelLayout].channels != aChannels) {
+  if (!InitPreferredChannelLayout() ||
+      kLayoutInfos[sPreferredChannelLayout].channels != aChannels) {
     AudioConfig::ChannelLayout smpteLayout(aChannels);
     return smpteLayout.Map();
   }
 
   return kLayoutInfos[sPreferredChannelLayout].mask;
 }
 
 void InitBrandName()
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -45,21 +45,21 @@ namespace mozilla
 {
 
 /* static */ bool
 DecoderTraits::IsHttpLiveStreamingType(const MediaContainerType& aType)
 {
   const auto& mimeType = aType.Type();
   return // For m3u8.
          // https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
-         mimeType == MEDIAMIMETYPE("application/vnd.apple.mpegurl")
-         // Some sites serve these as the informal m3u type.
-         || mimeType == MEDIAMIMETYPE("application/x-mpegurl")
-         || mimeType == MEDIAMIMETYPE("audio/mpegurl")
-         || mimeType == MEDIAMIMETYPE("audio/x-mpegurl");
+    mimeType == MEDIAMIMETYPE("application/vnd.apple.mpegurl") ||
+    // Some sites serve these as the informal m3u type.
+    mimeType == MEDIAMIMETYPE("application/x-mpegurl") ||
+    mimeType == MEDIAMIMETYPE("audio/mpegurl") ||
+    mimeType == MEDIAMIMETYPE("audio/x-mpegurl");
 }
 
 /* static */ bool
 DecoderTraits::IsMP4SupportedType(const MediaContainerType& aType,
                                   DecoderDoctorDiagnostics* aDiagnostics)
 {
 #ifdef MOZ_FMP4
   return MP4Decoder::IsSupportedType(aType, aDiagnostics);
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -667,17 +667,17 @@ AudioCallbackDriver::Init()
   input.channels = mInputChannels;
   input.layout = CUBEB_LAYOUT_UNDEFINED;
 
 #ifdef MOZ_WEBRTC
   if (mGraphImpl->mInputWanted) {
     StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
     uint32_t userChannels = 0;
     AudioInputCubeb::GetUserChannelCount(mGraphImpl->mInputDeviceID, userChannels);
-    input.channels = mInputChannels = userChannels;
+    input.channels = mInputChannels = std::min<uint32_t>(8, userChannels);
   }
 #endif
 
   cubeb_stream* stream = nullptr;
   CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
   // We have to translate the deviceID values to cubeb devid's since those can be
   // freed whenever enumerate is called.
   {
--- a/dom/media/Intervals.h
+++ b/dom/media/Intervals.h
@@ -141,47 +141,47 @@ public:
 
   bool ContainsWithStrictEnd(const T& aX) const
   {
     return mStart - mFuzz <= aX && aX < mEnd;
   }
 
   bool Contains(const SelfType& aOther) const
   {
-    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz)
-           && (aOther.mEnd - aOther.mFuzz <= mEnd + mFuzz);
+    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) &&
+           (aOther.mEnd - aOther.mFuzz <= mEnd + mFuzz);
   }
 
   bool ContainsStrict(const SelfType& aOther) const
   {
     return mStart <= aOther.mStart && aOther.mEnd <= mEnd;
   }
 
   bool ContainsWithStrictEnd(const SelfType& aOther) const
   {
-    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz)
-           && aOther.mEnd <= mEnd;
+    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) &&
+           aOther.mEnd <= mEnd;
   }
 
   bool Intersects(const SelfType& aOther) const
   {
-    return (mStart - mFuzz < aOther.mEnd + aOther.mFuzz)
-           && (aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
+    return (mStart - mFuzz < aOther.mEnd + aOther.mFuzz) &&
+           (aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
   }
 
   bool IntersectsStrict(const SelfType& aOther) const
   {
     return mStart < aOther.mEnd && aOther.mStart < mEnd;
   }
 
   // Same as Intersects, but including the boundaries.
   bool Touches(const SelfType& aOther) const
   {
-    return (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz)
-           && (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
+    return (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) &&
+           (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
   }
 
   // Returns true if aOther is strictly to the right of this and contiguous.
   // This operation isn't commutative.
   bool Contiguous(const SelfType& aOther) const
   {
     return mEnd <= aOther.mStart && aOther.mStart - mEnd <= mFuzz + aOther.mFuzz;
   }
@@ -240,19 +240,19 @@ public:
   {
     mFuzz = aFuzz;
   }
 
   // Returns true if the two intervals intersect with this being on the right
   // of aOther
   bool TouchesOnRight(const SelfType& aOther) const
   {
-    return aOther.mStart <= mStart
-           && (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz)
-           && (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
+    return aOther.mStart <= mStart &&
+           (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) &&
+           (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
   }
 
   T mStart;
   T mEnd;
   T mFuzz;
 
 private:
 };
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -99,55 +99,52 @@ AudioData::TransferAndUpdateTimestampAnd
                                       aOther->mChannels,
                                       aOther->mRate);
   return v.forget();
 }
 
 static bool
 ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
 {
-  return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION
-         && aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION
-         && aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT
-         && aPlane.mStride > 0;
+  return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
+         aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
+         aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
+         aPlane.mStride > 0;
 }
 
 static bool ValidateBufferAndPicture(const VideoData::YCbCrBuffer& aBuffer,
                                      const IntRect& aPicture)
 {
   // The following situation should never happen unless there is a bug
   // in the decoder
-  if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth
-      || aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
+  if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
+      aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
     NS_ERROR("C planes with different sizes");
     return false;
   }
 
   // The following situations could be triggered by invalid input
   if (aPicture.width <= 0 || aPicture.height <= 0) {
     // In debug mode, makes the error more noticeable
     MOZ_ASSERT(false, "Empty picture rect");
     return false;
   }
-  if (!ValidatePlane(aBuffer.mPlanes[0])
-      || !ValidatePlane(aBuffer.mPlanes[1])
-      || !ValidatePlane(aBuffer.mPlanes[2])) {
+  if (!ValidatePlane(aBuffer.mPlanes[0]) ||
+      !ValidatePlane(aBuffer.mPlanes[1]) ||
+      !ValidatePlane(aBuffer.mPlanes[2])) {
     NS_WARNING("Invalid plane size");
     return false;
   }
 
   // Ensure the picture size specified in the headers can be extracted out of
   // the frame we've been supplied without indexing out of bounds.
   CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
   CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
-  if (!xLimit.isValid()
-      || xLimit.value() > aBuffer.mPlanes[0].mStride
-      || !yLimit.isValid()
-      || yLimit.value() > aBuffer.mPlanes[0].mHeight)
-  {
+  if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
+      !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight) {
     // The specified picture dimensions can't be contained inside the video
     // frame, we'll stomp memory if we try to copy it. Fail.
     NS_WARNING("Overflowing picture rect");
     return false;
   }
   return true;
 }
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -752,22 +752,22 @@ MediaDecoder::EnsureTelemetryReported()
   if (mTelemetryReported || !mInfo) {
     // Note: sometimes we get multiple MetadataLoaded calls (for example
     // for chained ogg). So we ensure we don't report duplicate results for
     // these resources.
     return;
   }
 
   nsTArray<nsCString> codecs;
-  if (mInfo->HasAudio()
-      && !mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
+  if (mInfo->HasAudio() &&
+      !mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
     codecs.AppendElement(mInfo->mAudio.GetAsAudioInfo()->mMimeType);
   }
-  if (mInfo->HasVideo()
-      && !mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) {
+  if (mInfo->HasVideo() &&
+      !mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) {
     codecs.AppendElement(mInfo->mVideo.GetAsVideoInfo()->mMimeType);
   }
   if (codecs.IsEmpty()) {
     codecs.AppendElement(
       nsPrintfCString("resource; %s", ContainerType().OriginalString().Data()));
   }
   for (const nsCString& codec : codecs) {
     LOG("Telemetry MEDIA_CODEC_USED= '%s'", codec.get());
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -286,18 +286,18 @@ protected:
     auto copiedArgs = MakeTuple(Forward<Ts>(aArgs)...);
 
     // keep mMaster in a local object because mMaster will become invalid after
     // the current state object is deleted.
     auto master = mMaster;
 
     auto* s = new S(master);
 
-    MOZ_ASSERT(GetState() != s->GetState()
-               || GetState() == DECODER_STATE_SEEKING);
+    MOZ_ASSERT(GetState() != s->GetState() ||
+               GetState() == DECODER_STATE_SEEKING);
 
     SLOG("change state to: %s", ToStateStr(s->GetState()));
 
     Exit();
 
     master->mStateObj.reset(s);
     return CallEnterMemberFunction(s, copiedArgs,
                                    typename IndexSequenceFor<Ts...>::Type());
@@ -606,32 +606,31 @@ public:
     }
     mDormantTimer.Reset();
     mOnAudioPopped.DisconnectIfExists();
     mOnVideoPopped.DisconnectIfExists();
   }
 
   void Step() override
   {
-    if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING
-        && mMaster->IsPlaying()) {
+    if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING &&
+        mMaster->IsPlaying()) {
       // We're playing, but the element/decoder is in paused state. Stop
       // playing!
       mMaster->StopPlayback();
     }
 
     // Start playback if necessary so that the clock can be properly queried.
     if (!mIsPrerolling) {
       mMaster->MaybeStartPlayback();
     }
 
     mMaster->UpdatePlaybackPositionPeriodically();
 
-    MOZ_ASSERT(!mMaster->IsPlaying()
-               || mMaster->IsStateMachineScheduled(),
+    MOZ_ASSERT(!mMaster->IsPlaying() || mMaster->IsStateMachineScheduled(),
                "Must have timer scheduled");
 
     MaybeStartBuffering();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_DECODING;
@@ -745,33 +744,33 @@ private:
 
   uint32_t VideoPrerollFrames() const
   {
     return mMaster->GetAmpleVideoFrames() / 2;
   }
 
   bool DonePrerollingAudio()
   {
-    return !mMaster->IsAudioDecoding()
-           || mMaster->GetDecodedAudioDuration()
-              >= AudioPrerollThreshold().MultDouble(mMaster->mPlaybackRate);
+    return !mMaster->IsAudioDecoding() ||
+           mMaster->GetDecodedAudioDuration()
+           >= AudioPrerollThreshold().MultDouble(mMaster->mPlaybackRate);
   }
 
   bool DonePrerollingVideo()
   {
-    return !mMaster->IsVideoDecoding()
-           || static_cast<uint32_t>(mMaster->VideoQueue().GetSize())
-              >= VideoPrerollFrames() * mMaster->mPlaybackRate + 1;
+    return !mMaster->IsVideoDecoding() ||
+           static_cast<uint32_t>(mMaster->VideoQueue().GetSize()) >=
+             VideoPrerollFrames() * mMaster->mPlaybackRate + 1;
   }
 
   void MaybeStopPrerolling()
   {
-    if (mIsPrerolling
-        && (DonePrerollingAudio() || mMaster->IsWaitingAudioData())
-        && (DonePrerollingVideo() || mMaster->IsWaitingVideoData())) {
+    if (mIsPrerolling &&
+        (DonePrerollingAudio() || mMaster->IsWaitingAudioData()) &&
+        (DonePrerollingVideo() || mMaster->IsWaitingVideoData())) {
       mIsPrerolling = false;
       // Check if we can start playback.
       mMaster->ScheduleStateMachine();
     }
   }
 
   void StartDormantTimer()
   {
@@ -1183,19 +1182,19 @@ protected:
   virtual void RequestVideoData()
   {
     MOZ_ASSERT(!mDoneVideoSeeking);
     mMaster->RequestVideoData(media::TimeUnit());
   }
 
   void AdjustFastSeekIfNeeded(MediaData* aSample)
   {
-    if (mSeekJob.mTarget->IsFast()
-        && mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek
-        && aSample->mTime < mCurrentTimeBeforeSeek) {
+    if (mSeekJob.mTarget->IsFast() &&
+        mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek &&
+        aSample->mTime < mCurrentTimeBeforeSeek) {
       // We are doing a fastSeek, but we ended up *before* the previous
       // playback position. This is surprising UX, so switch to an accurate
       // seek and decode to the seek target. This is not conformant to the
       // spec, fastSeek should always be fast, but until we get the time to
       // change all Readers to seek to the keyframe after the currentTime
       // in this case, we'll just decode forward. Bug 1026330.
       mSeekJob.mTarget->SetType(SeekTarget::Accurate);
     }
@@ -1508,18 +1507,18 @@ private:
   void DoSeekInternal()
   {
     // We don't need to discard frames to the mCurrentTime here because we have
     // done it at DoSeek() and any video data received in between either
     // finishes the seek operation or be discarded, see HandleVideoDecoded().
 
     if (!NeedMoreVideo()) {
       FinishSeek();
-    } else if (!mMaster->IsRequestingVideoData()
-               && !mMaster->IsWaitingVideoData()) {
+    } else if (!mMaster->IsRequestingVideoData() &&
+               !mMaster->IsWaitingVideoData()) {
       RequestVideoData();
     }
   }
 
   class AysncNextFrameSeekTask : public Runnable
   {
   public:
     explicit AysncNextFrameSeekTask(NextFrameSeekingState* aStateObject)
@@ -1546,18 +1545,17 @@ private:
   void RequestVideoData()
   {
     mMaster->RequestVideoData(media::TimeUnit());
   }
 
   bool NeedMoreVideo() const
   {
     // Need to request video when we have none and video queue is not finished.
-    return VideoQueue().GetSize() == 0
-           && !VideoQueue().IsFinished();
+    return VideoQueue().GetSize() == 0 && !VideoQueue().IsFinished();
   }
 
   // Update the seek target's time before resolving this seek task, the updated
   // time will be used in the MDSM::SeekCompleted() to update the MDSM's
   // position.
   void UpdateSeekTargetTime()
   {
     RefPtr<VideoData> data = VideoQueue().PeekFront();
@@ -1889,48 +1887,47 @@ public:
     // we couldn't release it if we still need to render the frame.
 #ifndef MOZ_WIDGET_ANDROID
     if (!mMaster->mLooping) {
       // We've decoded all samples.
       // We don't need decoders anymore if not looping.
       Reader()->ReleaseResources();
     }
 #endif
-    bool hasNextFrame = (!mMaster->HasAudio() || !mMaster->mAudioCompleted)
-                        && (!mMaster->HasVideo() || !mMaster->mVideoCompleted);
+    bool hasNextFrame = (!mMaster->HasAudio() || !mMaster->mAudioCompleted) &&
+                        (!mMaster->HasVideo() || !mMaster->mVideoCompleted);
 
     mMaster->UpdateNextFrameStatus(
       hasNextFrame ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
                    : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
 
     Step();
   }
 
   void Exit() override
   {
     mSentPlaybackEndedEvent = false;
   }
 
   void Step() override
   {
-    if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING
-        && mMaster->IsPlaying()) {
+    if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING &&
+        mMaster->IsPlaying()) {
       mMaster->StopPlayback();
     }
 
     // Play the remaining media. We want to run AdvanceFrame() at least
     // once to ensure the current playback position is advanced to the
     // end of the media, and so that we update the readyState.
-    if ((mMaster->HasVideo() && !mMaster->mVideoCompleted)
-        || (mMaster->HasAudio() && !mMaster->mAudioCompleted)) {
+    if ((mMaster->HasVideo() && !mMaster->mVideoCompleted) ||
+        (mMaster->HasAudio() && !mMaster->mAudioCompleted)) {
       // Start playback if necessary to play the remaining media.
       mMaster->MaybeStartPlayback();
       mMaster->UpdatePlaybackPositionPeriodically();
-      MOZ_ASSERT(!mMaster->IsPlaying()
-                 || mMaster->IsStateMachineScheduled(),
+      MOZ_ASSERT(!mMaster->IsPlaying() || mMaster->IsStateMachineScheduled(),
                  "Must have timer scheduled");
       return;
     }
 
     // StopPlayback in order to reset the IsPlaying() state so audio
     // is restarted correctly.
     mMaster->StopPlayback();
 
@@ -2227,18 +2224,18 @@ DecodingFirstFrameState::Enter()
 }
 
 void
 MediaDecoderStateMachine::
 DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
 {
   MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
 
-  if ((mMaster->IsAudioDecoding() && AudioQueue().GetSize() == 0)
-      || (mMaster->IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
+  if ((mMaster->IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
+      (mMaster->IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
     return;
   }
 
   mMaster->FinishDecodeFirstFrame();
   if (mPendingSeek.Exists()) {
     SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
   } else {
     SetState<DecodingState>();
@@ -2246,19 +2243,19 @@ DecodingFirstFrameState::MaybeFinishDeco
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::Enter()
 {
   MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
 
-  if (mMaster->mVideoDecodeMode == VideoDecodeMode::Suspend
-      && !mMaster->mVideoDecodeSuspendTimer.IsScheduled()
-      && !mMaster->mVideoDecodeSuspended) {
+  if (mMaster->mVideoDecodeMode == VideoDecodeMode::Suspend &&
+      !mMaster->mVideoDecodeSuspendTimer.IsScheduled() &&
+      !mMaster->mVideoDecodeSuspended) {
     // If the VideoDecodeMode is Suspend and the timer is not schedule, it means
     // the timer has timed out and we should suspend video decoding now if
     // necessary.
     HandleVideoSuspendTimeout();
   }
 
   if (!mMaster->IsVideoDecoding() && !mMaster->IsAudioDecoding()) {
     SetState<CompletedState>();
@@ -2318,48 +2315,48 @@ DecodingState::HandleEndOfVideo()
     MaybeStopPrerolling();
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::DispatchDecodeTasksIfNeeded()
 {
-  if (mMaster->IsAudioDecoding()
-      && !mMaster->mMinimizePreroll
-      && !mMaster->HaveEnoughDecodedAudio()) {
+  if (mMaster->IsAudioDecoding() &&
+      !mMaster->mMinimizePreroll &&
+      !mMaster->HaveEnoughDecodedAudio()) {
     EnsureAudioDecodeTaskQueued();
   }
 
-  if (mMaster->IsVideoDecoding()
-      && !mMaster->mMinimizePreroll
-      && !mMaster->HaveEnoughDecodedVideo()) {
+  if (mMaster->IsVideoDecoding() &&
+      !mMaster->mMinimizePreroll &&
+      !mMaster->HaveEnoughDecodedVideo()) {
     EnsureVideoDecodeTaskQueued();
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::EnsureAudioDecodeTaskQueued()
 {
-  if (!mMaster->IsAudioDecoding()
-      || mMaster->IsRequestingAudioData()
-      || mMaster->IsWaitingAudioData()) {
+  if (!mMaster->IsAudioDecoding() ||
+      mMaster->IsRequestingAudioData() ||
+      mMaster->IsWaitingAudioData()) {
     return;
   }
   mMaster->RequestAudioData();
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::EnsureVideoDecodeTaskQueued()
 {
-  if (!mMaster->IsVideoDecoding()
-      || mMaster->IsRequestingVideoData()
-      || mMaster->IsWaitingVideoData()) {
+  if (!mMaster->IsVideoDecoding() ||
+      mMaster->IsRequestingVideoData() ||
+      mMaster->IsWaitingVideoData()) {
     return;
   }
   mMaster->RequestVideoData(mMaster->GetMediaTime());
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::MaybeStartBuffering()
@@ -2479,26 +2476,28 @@ BufferingState::Step()
       !mMaster->HasLowBufferedData(TimeUnit::FromSeconds(mBufferingWait));
     if (!stopBuffering) {
       SLOG("Buffering: wait %ds, timeout in %.3lfs",
            mBufferingWait, mBufferingWait - elapsed.ToSeconds());
       mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
       return;
     }
   } else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
-    MOZ_ASSERT(!mMaster->OutOfDecodedAudio()
-               || mMaster->IsRequestingAudioData()
-               || mMaster->IsWaitingAudioData());
-    MOZ_ASSERT(!mMaster->OutOfDecodedVideo()
-               || mMaster->IsRequestingVideoData()
-               || mMaster->IsWaitingVideoData());
+    MOZ_ASSERT(!mMaster->OutOfDecodedAudio() ||
+               mMaster->IsRequestingAudioData() ||
+               mMaster->IsWaitingAudioData());
+    MOZ_ASSERT(!mMaster->OutOfDecodedVideo() ||
+               mMaster->IsRequestingVideoData() ||
+               mMaster->IsWaitingVideoData());
     SLOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
          "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
-         mMaster->OutOfDecodedAudio(), mMaster->AudioRequestStatus(),
-         mMaster->OutOfDecodedVideo(), mMaster->VideoRequestStatus());
+         mMaster->OutOfDecodedAudio(),
+         mMaster->AudioRequestStatus(),
+         mMaster->OutOfDecodedVideo(),
+         mMaster->VideoRequestStatus());
     return;
   }
 
   SLOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
   SetState<DecodingState>();
 }
 
 void
@@ -2733,18 +2732,17 @@ MediaDecoderStateMachine::GetDecodedAudi
   return TimeUnit::FromMicroseconds(AudioQueue().Duration());
 }
 
 bool
 MediaDecoderStateMachine::HaveEnoughDecodedAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
   auto ampleAudio = mAmpleAudioThreshold.MultDouble(mPlaybackRate);
-  return AudioQueue().GetSize() > 0
-         && GetDecodedAudioDuration() >= ampleAudio;
+  return AudioQueue().GetSize() > 0 && GetDecodedAudioDuration() >= ampleAudio;
 }
 
 bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
   return VideoQueue().GetSize() >= GetAmpleVideoFrames() * mPlaybackRate + 1;
 }
 
@@ -2909,18 +2907,18 @@ MediaDecoderStateMachine::UpdatePlayback
 }
 
 void
 MediaDecoderStateMachine::UpdatePlaybackPosition(const TimeUnit& aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   UpdatePlaybackPositionInternal(aTime);
 
-  bool fragmentEnded = mFragmentEndTime.IsValid()
-    && GetMediaTime() >= mFragmentEndTime;
+  bool fragmentEnded =
+    mFragmentEndTime.IsValid() && GetMediaTime() >= mFragmentEndTime;
   mMetadataManager.DispatchMetadataIfNeeded(aTime);
 
   if (fragmentEnded) {
     StopPlayback();
   }
 }
 
 /* static */ const char*
@@ -3254,43 +3252,42 @@ MediaDecoderStateMachine::StartMediaSink
     }
   }
 }
 
 bool
 MediaDecoderStateMachine::HasLowDecodedAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
-  return IsAudioDecoding()
-         && GetDecodedAudioDuration()
-            < EXHAUSTED_DATA_MARGIN.MultDouble(mPlaybackRate);
+  return IsAudioDecoding() && GetDecodedAudioDuration()
+                              < EXHAUSTED_DATA_MARGIN.MultDouble(mPlaybackRate);
 }
 
 bool
 MediaDecoderStateMachine::HasLowDecodedVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
-  return IsVideoDecoding()
-         && VideoQueue().GetSize() < LOW_VIDEO_FRAMES * mPlaybackRate;
+  return IsVideoDecoding() &&
+         VideoQueue().GetSize() < LOW_VIDEO_FRAMES * mPlaybackRate;
 }
 
 bool
 MediaDecoderStateMachine::HasLowDecodedData()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mReader->UseBufferingHeuristics());
   return HasLowDecodedAudio() || HasLowDecodedVideo();
 }
 
 bool MediaDecoderStateMachine::OutOfDecodedAudio()
 {
     MOZ_ASSERT(OnTaskQueue());
-    return IsAudioDecoding() && !AudioQueue().IsFinished()
-           && AudioQueue().GetSize() == 0
-           && !mMediaSink->HasUnplayedFrames(TrackInfo::kAudioTrack);
+    return IsAudioDecoding() && !AudioQueue().IsFinished() &&
+           AudioQueue().GetSize() == 0 &&
+           !mMediaSink->HasUnplayedFrames(TrackInfo::kAudioTrack);
 }
 
 bool
 MediaDecoderStateMachine::HasLowBufferedData()
 {
   MOZ_ASSERT(OnTaskQueue());
   return HasLowBufferedData(detail::LOW_BUFFER_THRESHOLD);
 }
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -549,18 +549,18 @@ public:
     , mOwner(WrapNotNull(aOwner)) { }
 
   void CreateDecoder(TrackType aTrack);
 
   // Shutdown any decoder pending initialization and reset mAudio/mVideo to its
   // pristine state so CreateDecoder() is ready to be called again immediately.
   void ShutdownDecoder(TrackType aTrack)
   {
-    MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
-               || aTrack == TrackInfo::kVideoTrack);
+    MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
+               aTrack == TrackInfo::kVideoTrack);
     auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
     data.mPolicy->Cancel();
     data.mTokenRequest.DisconnectIfExists();
     data.mInitRequest.DisconnectIfExists();
     if (data.mDecoder) {
       mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
     }
     data.mStage = Stage::None;
@@ -600,18 +600,18 @@ private:
 
   // guaranteed to be valid by the owner.
   const NotNull<MediaFormatReader*> mOwner;
 };
 
 void
 MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack)
 {
-  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
-             || aTrack == TrackInfo::kVideoTrack);
+  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
+             aTrack == TrackInfo::kVideoTrack);
   RunStage(aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo);
 }
 
 class MediaFormatReader::DecoderFactory::Wrapper : public MediaDataDecoder
 {
   using Token = GlobalAllocPolicy::Token;
 
 public:
@@ -1391,18 +1391,18 @@ MediaFormatReader::OnDemuxerInitDone(con
     if (!mVideo.mTrackDemuxer) {
       mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
       return;
     }
 
     UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
     videoActive = videoInfo && videoInfo->IsValid();
     if (videoActive) {
-      if (platform
-          && !platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
+      if (platform &&
+          !platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
         // We have no decoder for this track. Error.
         mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
         return;
       }
       {
         MutexAutoLock lock(mVideo.mMutex);
         mInfo.mVideo = *videoInfo->GetAsVideoInfo();
       }
@@ -1423,20 +1423,18 @@ MediaFormatReader::OnDemuxerInitDone(con
     if (!mAudio.mTrackDemuxer) {
       mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
       return;
     }
 
     UniquePtr<TrackInfo> audioInfo = mAudio.mTrackDemuxer->GetInfo();
     // We actively ignore audio tracks that we know we can't play.
     audioActive =
-      audioInfo
-      && audioInfo->IsValid()
-      && (!platform || platform->SupportsMimeType(audioInfo->mMimeType,
-                                                  nullptr));
+      audioInfo && audioInfo->IsValid() &&
+      (!platform || platform->SupportsMimeType(audioInfo->mMimeType, nullptr));
 
     if (audioActive) {
       {
         MutexAutoLock lock(mAudio.mMutex);
         mInfo.mAudio = *audioInfo->GetAsAudioInfo();
       }
       for (const MetadataTag& tag : audioInfo->mTags) {
         tags->Put(tag.mKey, tag.mValue);
@@ -1503,18 +1501,18 @@ MediaFormatReader::OnDemuxerInitDone(con
   MaybeResolveMetadataPromise();
 }
 
 void
 MediaFormatReader::MaybeResolveMetadataPromise()
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing())
-      || (HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
+  if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing()) ||
+      (HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
     return;
   }
 
   TimeUnit startTime =
     std::min(mAudio.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()),
              mVideo.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()));
 
   if (!startTime.IsInfinite()) {
@@ -1531,18 +1529,18 @@ MediaFormatReader::MaybeResolveMetadataP
   UpdateBuffered();
 
   mMetadataPromise.Resolve(Move(metadata), __func__);
 }
 
 bool
 MediaFormatReader::IsEncrypted() const
 {
-  return (HasAudio() && mInfo.mAudio.mCrypto.mValid)
-         || (HasVideo() && mInfo.mVideo.mCrypto.mValid);
+  return (HasAudio() && mInfo.mAudio.mCrypto.mValid) ||
+         (HasVideo() && mInfo.mVideo.mCrypto.mValid);
 }
 
 void
 MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
 {
   mDemuxerInitRequest.Complete();
   mMetadataPromise.Reject(aError, __func__);
 }
@@ -1551,18 +1549,18 @@ void
 MediaFormatReader::ReadUpdatedMetadata(MediaInfo* aInfo)
 {
   *aInfo = mInfo;
 }
 
 MediaFormatReader::DecoderData&
 MediaFormatReader::GetDecoderData(TrackType aTrack)
 {
-  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
-             || aTrack == TrackInfo::kVideoTrack);
+  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
+             aTrack == TrackInfo::kVideoTrack);
   if (aTrack == TrackInfo::kAudioTrack) {
     return mAudio;
   }
   return mVideo;
 }
 
 bool
 MediaFormatReader::ShouldSkip(TimeUnit aTimeThreshold)
@@ -1575,32 +1573,31 @@ MediaFormatReader::ShouldSkip(TimeUnit a
 
   TimeUnit nextKeyframe;
   nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
   if (NS_FAILED(rv)) {
     // Only OggTrackDemuxer with video type gets into here.
     // We don't support skip-to-next-frame for this case.
     return false;
   }
-  return (nextKeyframe <= aTimeThreshold
-          || (mVideo.mTimeThreshold
-              && mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold))
-         && nextKeyframe.ToMicroseconds() >= 0
-         && !nextKeyframe.IsInfinite();
+  return (nextKeyframe <= aTimeThreshold ||
+          (mVideo.mTimeThreshold &&
+           mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold)) &&
+         nextKeyframe.ToMicroseconds() >= 0 && !nextKeyframe.IsInfinite();
 }
 
 RefPtr<MediaFormatReader::VideoDataPromise>
 MediaFormatReader::RequestVideoData(const TimeUnit& aTimeThreshold)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
                         "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
-  MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists()
-                        || mVideo.mTimeThreshold.isSome());
+  MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
+                        mVideo.mTimeThreshold.isSome());
   MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
   LOGV("RequestVideoData(%" PRId64 ")", aTimeThreshold.ToMicroseconds());
 
   if (!HasVideo()) {
     LOG("called with no video track");
     return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                                              __func__);
   }
@@ -1706,19 +1703,18 @@ MediaFormatReader::OnVideoDemuxCompleted
 
 RefPtr<MediaFormatReader::AudioDataPromise>
 MediaFormatReader::RequestAudioData()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
                         "No sample requests allowed while seeking");
-  MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking()
-                        || !mAudio.mSeekRequest.Exists()
-                        || mAudio.mTimeThreshold.isSome());
+  MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !mAudio.mSeekRequest.Exists() ||
+                        mAudio.mTimeThreshold.isSome());
   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
   LOGV("");
 
   if (!HasAudio()) {
     LOG("called with no audio track");
     return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                                              __func__);
   }
@@ -1866,23 +1862,23 @@ MediaFormatReader::NotifyEndOfStream(Tra
 }
 
 bool
 MediaFormatReader::NeedInput(DecoderData& aDecoder)
 {
   // The decoder will not be fed a new raw sample until the current decoding
   // requests has completed.
   return
-    (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome())
-    && !aDecoder.HasPendingDrain()
-    && !aDecoder.HasFatalError()
-    && !aDecoder.mDemuxRequest.Exists()
-    && !aDecoder.mOutput.Length()
-    && !aDecoder.HasInternalSeekPending()
-    && !aDecoder.mDecodeRequest.Exists();
+    (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome()) &&
+    !aDecoder.HasPendingDrain() &&
+    !aDecoder.HasFatalError() &&
+    !aDecoder.mDemuxRequest.Exists() &&
+    !aDecoder.mOutput.Length() &&
+    !aDecoder.HasInternalSeekPending() &&
+    !aDecoder.mDecodeRequest.Exists();
 }
 
 void
 MediaFormatReader::ScheduleUpdate(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mShutdown) {
     return;
@@ -1940,28 +1936,28 @@ MediaFormatReader::UpdateReceivedNewData
     decoder.mTimeThreshold.ref().mWaiting = false;
   }
   decoder.mWaitingForData = false;
 
   if (decoder.HasFatalError()) {
     return false;
   }
 
-  if (!mSeekPromise.IsEmpty()
-      && (!IsVideoSeeking() || aTrack == TrackInfo::kVideoTrack)) {
+  if (!mSeekPromise.IsEmpty() &&
+      (!IsVideoSeeking() || aTrack == TrackInfo::kVideoTrack)) {
     MOZ_ASSERT(!decoder.HasPromise());
     MOZ_DIAGNOSTIC_ASSERT(
       (IsVideoSeeking() || !mAudio.mTimeThreshold) && !mVideo.mTimeThreshold,
       "InternalSeek must have been aborted when Seek was first called");
     MOZ_DIAGNOSTIC_ASSERT(
-      (IsVideoSeeking() || !mAudio.HasWaitingPromise())
-      && !mVideo.HasWaitingPromise(),
+      (IsVideoSeeking() || !mAudio.HasWaitingPromise()) &&
+      !mVideo.HasWaitingPromise(),
       "Waiting promises must have been rejected when Seek was first called");
-    if (mVideo.mSeekRequest.Exists()
-        || (!IsVideoSeeking() && mAudio.mSeekRequest.Exists())) {
+    if (mVideo.mSeekRequest.Exists() ||
+        (!IsVideoSeeking() && mAudio.mSeekRequest.Exists())) {
       // Already waiting for a seek to complete. Nothing more to do.
       return true;
     }
     LOG("Attempting Seek");
     ScheduleSeek();
     return true;
   }
   if (decoder.HasInternalSeekPending() || decoder.HasWaitingPromise()) {
@@ -2060,25 +2056,25 @@ MediaFormatReader::HandleDemuxedSamples(
   LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
 
   // Decode all our demuxed frames.
   while (decoder.mQueuedSamples.Length()) {
     RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
     RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
 
     if (info && decoder.mLastStreamSourceID != info->GetID()) {
-      bool recyclable = MediaPrefs::MediaDecoderCheckRecycling()
-                        && decoder.mDecoder->SupportDecoderRecycling();
-      if (!recyclable
-          && decoder.mTimeThreshold.isNothing()
-          && (decoder.mNextStreamSourceID.isNothing()
-              || decoder.mNextStreamSourceID.ref() != info->GetID())) {
+      bool recyclable = MediaPrefs::MediaDecoderCheckRecycling() &&
+                        decoder.mDecoder->SupportDecoderRecycling();
+      if (!recyclable && decoder.mTimeThreshold.isNothing() &&
+          (decoder.mNextStreamSourceID.isNothing() ||
+           decoder.mNextStreamSourceID.ref() != info->GetID())) {
         LOG("%s stream id has changed from:%d to:%d, draining decoder.",
-          TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
-          info->GetID());
+            TrackTypeToStr(aTrack),
+            decoder.mLastStreamSourceID,
+            info->GetID());
         decoder.RequestDrain();
         decoder.mNextStreamSourceID = Some(info->GetID());
         ScheduleUpdate(aTrack);
         return;
       }
 
       LOG("%s stream id has changed from:%d to:%d.",
           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
@@ -2182,19 +2178,19 @@ void
 MediaFormatReader::DrainDecoder(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   auto& decoder = GetDecoderData(aTrack);
   if (decoder.mDrainState == DrainState::Draining) {
     return;
   }
-  if (!decoder.mDecoder
-      || (decoder.mDrainState != DrainState::PartialDrainPending
-          && decoder.mNumSamplesInput == decoder.mNumSamplesOutput)) {
+  if (!decoder.mDecoder ||
+      (decoder.mDrainState != DrainState::PartialDrainPending &&
+       decoder.mNumSamplesInput == decoder.mNumSamplesOutput)) {
     // No frames to drain.
     LOGV("Draining %s with nothing to drain", TrackTypeToStr(aTrack));
     decoder.mDrainState = DrainState::DrainAborted;
     ScheduleUpdate(aTrack);
     return;
   }
 
   decoder.mDrainState = DrainState::Draining;
@@ -2252,18 +2248,18 @@ MediaFormatReader::Update(TrackType aTra
   }
 
   if (decoder.mSeekRequest.Exists()) {
     LOGV("Seeking hasn't completed, nothing more to do");
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(
-    !decoder.HasInternalSeekPending()
-    || (!decoder.mOutput.Length() && !decoder.mQueuedSamples.Length()),
+    !decoder.HasInternalSeekPending() ||
+      (!decoder.mOutput.Length() && !decoder.mQueuedSamples.Length()),
     "No frames can be demuxed or decoded while an internal seek is pending");
 
   // Record number of frames decoded and parsed. Automatically update the
   // stats counters using the AutoNotifyDecoded stack-based class.
   FrameStatistics::AutoNotifyDecoded a(mFrameStats);
 
   // Drop any frames found prior our internal seek target.
   while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
@@ -2282,18 +2278,18 @@ MediaFormatReader::Update(TrackType aTra
            output->mTime.ToSeconds(),
            target.Time().ToSeconds(),
            output->mKeyframe);
       decoder.mOutput.RemoveElementAt(0);
       decoder.mSizeOfQueue -= 1;
     }
   }
 
-  while (decoder.mOutput.Length()
-         && decoder.mOutput[0]->mType == MediaData::NULL_DATA) {
+  while (decoder.mOutput.Length() &&
+         decoder.mOutput[0]->mType == MediaData::NULL_DATA) {
     LOGV("Dropping null data. Time: %" PRId64,
          decoder.mOutput[0]->mTime.ToMicroseconds());
     decoder.mOutput.RemoveElementAt(0);
     decoder.mSizeOfQueue -= 1;
   }
 
   if (decoder.HasPromise()) {
     needOutput = true;
@@ -2341,19 +2337,19 @@ MediaFormatReader::Update(TrackType aTra
       LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
       decoder.RejectPromise(decoder.mError.ref(), __func__);
       return;
     } else if (decoder.HasCompletedDrain()) {
       if (decoder.mDemuxEOS) {
         LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
         decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
       } else if (decoder.mWaitingForData) {
-        if (decoder.mDrainState == DrainState::DrainCompleted
-            && decoder.mLastDecodedSampleTime
-            && !decoder.mNextStreamSourceID) {
+        if (decoder.mDrainState == DrainState::DrainCompleted &&
+            decoder.mLastDecodedSampleTime &&
+            !decoder.mNextStreamSourceID) {
           // We have completed draining the decoder following WaitingForData.
           // Set up the internal seek machinery to be able to resume from the
           // last sample decoded.
           LOG("Seeking to last sample time: %" PRId64,
               decoder.mLastDecodedSampleTime.ref().mStart.ToMicroseconds());
           InternalSeek(aTrack,
                        InternalSeekTarget(decoder.mLastDecodedSampleTime.ref(), true));
         }
@@ -2367,47 +2363,47 @@ MediaFormatReader::Update(TrackType aTra
 
       // Now that draining has completed, we check if we have received
       // new data again as the result may now be different from the earlier
       // run.
       if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) {
         LOGV("Nothing more to do");
         return;
       }
-    } else if (decoder.mDemuxEOS
-               && !decoder.HasPendingDrain()
-               && decoder.mQueuedSamples.IsEmpty()) {
+    } else if (decoder.mDemuxEOS &&
+               !decoder.HasPendingDrain() &&
+               decoder.mQueuedSamples.IsEmpty()) {
       // It is possible to transition from WAITING_FOR_DATA directly to EOS
       // state during the internal seek; in which case no draining would occur.
       // There is no more samples left to be decoded and we are already in
       // EOS state. We can immediately reject the data promise.
       LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     } else if (decoder.mWaitingForKey) {
       LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
           TrackTypeToStr(aTrack));
       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
     }
   }
 
-  if (decoder.mDrainState == DrainState::DrainRequested
-      || decoder.mDrainState == DrainState::PartialDrainPending) {
+  if (decoder.mDrainState == DrainState::DrainRequested ||
+      decoder.mDrainState == DrainState::PartialDrainPending) {
     if (decoder.mOutput.IsEmpty()) {
       DrainDecoder(aTrack);
     }
     return;
   }
 
   if (decoder.mError && !decoder.HasFatalError()) {
     MOZ_RELEASE_ASSERT(!decoder.HasInternalSeekPending(),
                        "No error can occur while an internal seek is pending");
     bool needsNewDecoder =
       decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
-    if (!needsNewDecoder
-        && ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
+    if (!needsNewDecoder &&
+        ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
       NotifyError(aTrack, decoder.mError.ref());
       return;
     }
     decoder.mError.reset();
 
     LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
         decoder.mNumOfConsecutiveError);
 
@@ -2459,19 +2455,19 @@ MediaFormatReader::Update(TrackType aTra
        decoder.mLastStreamSourceID);
 
   if (IsWaitingOnCDMResource()) {
     // If the content is encrypted, MFR won't start to create decoder until
     // CDMProxy is set.
     return;
   }
 
-  if ((decoder.mWaitingForData
-       && (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
-      || (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
+  if ((decoder.mWaitingForData &&
+       (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) ||
+      (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
     // Nothing more we can do at present.
     LOGV("Still waiting for data or key.");
     return;
   }
 
   if (decoder.CancelWaitingForKey()) {
     LOGV("No longer waiting for key. Resolving waiting promise");
     return;
@@ -2489,44 +2485,48 @@ MediaFormatReader::Update(TrackType aTra
   HandleDemuxedSamples(aTrack, a);
 }
 
 void
 MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
 {
   MOZ_ASSERT(GetDecoderData(aTrack).HasPromise());
   MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::NULL_DATA);
-  LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]", TrackTypeToStr(aTrack),
-      aData->mTime.ToMicroseconds(), aData->GetEndTime().ToMicroseconds());
+  LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]",
+      TrackTypeToStr(aTrack),
+      aData->mTime.ToMicroseconds(),
+      aData->GetEndTime().ToMicroseconds());
 
   if (aTrack == TrackInfo::kAudioTrack) {
     AudioData* audioData = static_cast<AudioData*>(aData);
 
-    if (audioData->mChannels != mInfo.mAudio.mChannels
-        || audioData->mRate != mInfo.mAudio.mRate) {
+    if (audioData->mChannels != mInfo.mAudio.mChannels ||
+        audioData->mRate != mInfo.mAudio.mRate) {
       LOG("change of audio format (rate:%d->%d). "
           "This is an unsupported configuration",
-          mInfo.mAudio.mRate, audioData->mRate);
+          mInfo.mAudio.mRate,
+          audioData->mRate);
       mInfo.mAudio.mRate = audioData->mRate;
       mInfo.mAudio.mChannels = audioData->mChannels;
     }
     mAudio.ResolvePromise(audioData, __func__);
   } else if (aTrack == TrackInfo::kVideoTrack) {
     VideoData* videoData = static_cast<VideoData*>(aData);
 
     if (videoData->mDisplay != mInfo.mVideo.mDisplay) {
       LOG("change of video display size (%dx%d->%dx%d)",
           mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height,
           videoData->mDisplay.width, videoData->mDisplay.height);
       mInfo.mVideo.mDisplay = videoData->mDisplay;
     }
 
     TimeUnit nextKeyframe;
     if (!mVideo.HasInternalSeekPending() &&
-        NS_SUCCEEDED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) {
+        NS_SUCCEEDED(
+          mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) {
       videoData->SetNextKeyFrameTime(nextKeyframe);
     }
 
     mVideo.ResolvePromise(videoData, __func__);
   }
 }
 
 size_t
@@ -2734,18 +2734,18 @@ MediaFormatReader::Seek(const SeekTarget
 
   LOG("aTarget=(%" PRId64 ")", aTarget.GetTime().ToMicroseconds());
 
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
   MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() || !mAudio.HasPromise());
   MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing());
   MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
-  MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly()
-                        || mAudio.mTimeThreshold.isNothing());
+  MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() ||
+                        mAudio.mTimeThreshold.isNothing());
 
   if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
     LOG("Seek() END (Unseekable)");
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   if (mShutdown) {
     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
@@ -2820,36 +2820,36 @@ MediaFormatReader::OnSeekFailed(TrackTyp
   LOGV("%s failure:%" PRIu32, TrackTypeToStr(aTrack), static_cast<uint32_t>(aError.Code()));
   if (aTrack == TrackType::kVideoTrack) {
     mVideo.mSeekRequest.Complete();
   } else {
     mAudio.mSeekRequest.Complete();
   }
 
   if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
-    if (HasVideo()
-        && aTrack == TrackType::kAudioTrack
-        && mFallbackSeekTime.isSome()
-        && mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
+    if (HasVideo() &&
+        aTrack == TrackType::kAudioTrack &&
+        mFallbackSeekTime.isSome() &&
+        mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
       // We have failed to seek audio where video seeked to earlier.
       // Attempt to seek instead to the closest point that we know we have in
       // order to limit A/V sync discrepency.
 
       // Ensure we have the most up to date buffered ranges.
       UpdateReceivedNewData(TrackType::kAudioTrack);
       Maybe<TimeUnit> nextSeekTime;
       // Find closest buffered time found after video seeked time.
       for (const auto& timeRange : mAudio.mTimeRanges) {
         if (timeRange.mStart >= mPendingSeekTime.ref()) {
           nextSeekTime.emplace(timeRange.mStart);
           break;
         }
       }
-      if (nextSeekTime.isNothing()
-          || nextSeekTime.ref() > mFallbackSeekTime.ref()) {
+      if (nextSeekTime.isNothing() ||
+          nextSeekTime.ref() > mFallbackSeekTime.ref()) {
         nextSeekTime = Some(mFallbackSeekTime.ref());
         LOG("Unable to seek audio to video seek time. A/V sync may be broken");
       } else {
         mFallbackSeekTime.reset();
       }
       mPendingSeekTime = nextSeekTime;
       DoAudioSeek();
       return;
@@ -3060,32 +3060,32 @@ MediaFormatReader::UpdateBuffered()
     return;
   }
 
   if (HasVideo()) {
     mVideo.mTimeRanges = mVideo.mTrackDemuxer->GetBuffered();
     bool hasLastEnd;
     auto lastEnd = mVideo.mTimeRanges.GetEnd(&hasLastEnd);
     if (hasLastEnd) {
-      if (mVideo.mLastTimeRangesEnd
-          && mVideo.mLastTimeRangesEnd.ref() < lastEnd) {
+      if (mVideo.mLastTimeRangesEnd &&
+          mVideo.mLastTimeRangesEnd.ref() < lastEnd) {
         // New data was added after our previous end, we can clear the EOS flag.
         mVideo.mDemuxEOS = false;
         ScheduleUpdate(TrackInfo::kVideoTrack);
       }
       mVideo.mLastTimeRangesEnd = Some(lastEnd);
     }
   }
   if (HasAudio()) {
     mAudio.mTimeRanges = mAudio.mTrackDemuxer->GetBuffered();
     bool hasLastEnd;
     auto lastEnd = mAudio.mTimeRanges.GetEnd(&hasLastEnd);
     if (hasLastEnd) {
-      if (mAudio.mLastTimeRangesEnd
-          && mAudio.mLastTimeRangesEnd.ref() < lastEnd) {
+      if (mAudio.mLastTimeRangesEnd &&
+          mAudio.mLastTimeRangesEnd.ref() < lastEnd) {
         // New data was added after our previous end, we can clear the EOS flag.
         mAudio.mDemuxEOS = false;
         ScheduleUpdate(TrackInfo::kAudioTrack);
       }
       mAudio.mLastTimeRangesEnd = Some(lastEnd);
     }
   }
 
@@ -3093,18 +3093,17 @@ MediaFormatReader::UpdateBuffered()
   if (HasAudio() && HasVideo()) {
     intervals = media::Intersection(mVideo.mTimeRanges, mAudio.mTimeRanges);
   } else if (HasAudio()) {
     intervals = mAudio.mTimeRanges;
   } else if (HasVideo()) {
     intervals = mVideo.mTimeRanges;
   }
 
-  if (!intervals.Length()
-      || intervals.GetStart() == TimeUnit::Zero()) {
+  if (!intervals.Length() || intervals.GetStart() == TimeUnit::Zero()) {
     // IntervalSet already starts at 0 or is empty, nothing to shift.
     mBuffered = intervals;
   } else {
     mBuffered =
       intervals.Shift(TimeUnit::Zero() - mInfo.mStartTime);
   }
 }
 
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -463,18 +463,18 @@ private:
     bool HasFatalError() const
     {
       if (!mError.isSome()) {
         return false;
       }
       if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) {
         // Allow decode errors to be non-fatal, but give up
         // if we have too many, or if warnings should be treated as errors.
-        return mNumOfConsecutiveError > mMaxConsecutiveError
-               || MediaPrefs::MediaWarningsAsErrors();
+        return mNumOfConsecutiveError > mMaxConsecutiveError ||
+               MediaPrefs::MediaWarningsAsErrors();
       } else if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {
         // If the caller asked for a new decoder we shouldn't treat
         // it as fatal.
         return false;
       } else {
         // All other error types are fatal
         return true;
       }
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -279,19 +279,19 @@ public:
   // If aWidth and aHeight are identical to the original mImage.width/mImage.height
   // then the scaling ratio will be 1.
   // This is used for when the frame size is different from what the container
   // reports. This is legal in WebM, and we will preserve the ratio of the crop
   // rectangle as it was reported relative to the picture size reported by the
   // container.
   gfx::IntRect ScaledImageRect(int64_t aWidth, int64_t aHeight) const
   {
-    if ((aWidth == mImage.width && aHeight == mImage.height)
-        || !mImage.width
-        || !mImage.height) {
+    if ((aWidth == mImage.width && aHeight == mImage.height) ||
+        !mImage.width ||
+        !mImage.height) {
       return ImageRect();
     }
     gfx::IntRect imageRect = ImageRect();
     imageRect.x = (imageRect.x * aWidth) / mImage.width;
     imageRect.y = (imageRect.y * aHeight) / mImage.height;
     imageRect.SetWidth((aWidth * imageRect.Width()) / mImage.width);
     imageRect.SetHeight((aHeight * imageRect.Height()) / mImage.height);
     return imageRect;
@@ -365,18 +365,18 @@ public:
     , mExtraData(aOther.mExtraData)
   {
   }
 
   static const uint32_t MAX_RATE = 640000;
 
   bool IsValid() const override
   {
-    return mChannels > 0 && mChannels <= MAX_AUDIO_CHANNELS
-           && mRate > 0 && mRate <= MAX_RATE;
+    return mChannels > 0 && mChannels <= MAX_AUDIO_CHANNELS &&
+           mRate > 0 && mRate <= MAX_RATE;
   }
 
   AudioInfo* GetAsAudioInfo() override
   {
     return this;
   }
 
   const AudioInfo* GetAsAudioInfo() const override
@@ -495,34 +495,33 @@ public:
     // Set dummy values so that HasAudio() will return true;
     // See AudioInfo::IsValid()
     mAudio.mChannels = 2;
     mAudio.mRate = 44100;
   }
 
   bool IsEncrypted() const
   {
-    return (HasAudio() && mAudio.mCrypto.mValid)
-           || (HasVideo() && mVideo.mCrypto.mValid);
+    return (HasAudio() && mAudio.mCrypto.mValid) ||
+           (HasVideo() && mVideo.mCrypto.mValid);
   }
 
   bool HasValidMedia() const
   {
     return HasVideo() || HasAudio();
   }
 
   void AssertValid() const
   {
     NS_ASSERTION(!HasAudio() || mAudio.mTrackId != TRACK_INVALID,
                  "Audio track ID must be valid");
     NS_ASSERTION(!HasVideo() || mVideo.mTrackId != TRACK_INVALID,
                  "Audio track ID must be valid");
-    NS_ASSERTION(!HasAudio()
-                 || !HasVideo()
-                 || mAudio.mTrackId != mVideo.mTrackId,
+    NS_ASSERTION(!HasAudio() || !HasVideo() ||
+                 mAudio.mTrackId != mVideo.mTrackId,
                  "Duplicate track IDs");
   }
 
   // TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
   VideoInfo mVideo;
   AudioInfo mAudio;
 
   // If the metadata includes a duration, we store it here.
@@ -728,20 +727,18 @@ public:
     return mFormat;
   }
   bool Interleaved() const
   {
     return mInterleaved;
   }
   bool operator==(const AudioConfig& aOther) const
   {
-    return mChannelLayout == aOther.mChannelLayout
-      && mRate == aOther.mRate
-      && mFormat == aOther.mFormat
-      && mInterleaved == aOther.mInterleaved;
+    return mChannelLayout == aOther.mChannelLayout && mRate == aOther.mRate &&
+           mFormat == aOther.mFormat && mInterleaved == aOther.mInterleaved;
   }
   bool operator!=(const AudioConfig& aOther) const
   {
     return !(*this == aOther);
   }
 
   bool IsValid() const
   {
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -347,58 +347,58 @@ CreateTrackInfoWithMIMETypeAndContainerT
 
 namespace detail {
 
 // aString should start with aMajor + '/'.
 constexpr bool
 StartsWithMIMETypeMajor(const char* aString,
                         const char* aMajor, size_t aMajorRemaining)
 {
-  return (aMajorRemaining == 0 && *aString == '/')
-         || (*aString == *aMajor
-             && StartsWithMIMETypeMajor(aString + 1,
-                                        aMajor + 1, aMajorRemaining - 1));
+  return (aMajorRemaining == 0 && *aString == '/') ||
+         (*aString == *aMajor && StartsWithMIMETypeMajor(aString + 1,
+                                                         aMajor + 1,
+                                                         aMajorRemaining - 1));
 }
 
 // aString should only contain [a-z0-9\-\.] and a final '\0'.
 constexpr bool
 EndsWithMIMESubtype(const char* aString, size_t aRemaining)
 {
-  return aRemaining == 0
-         || (((*aString >= 'a' && *aString <= 'z')
-              || (*aString >= '0' && *aString <= '9')
-              || *aString == '-'
-              || *aString == '.')
-             && EndsWithMIMESubtype(aString + 1, aRemaining - 1));
+  return aRemaining == 0 ||
+         (((*aString >= 'a' && *aString <= 'z') ||
+           (*aString >= '0' && *aString <= '9') ||
+           *aString == '-' ||
+           *aString == '.') &&
+          EndsWithMIMESubtype(aString + 1, aRemaining - 1));
 }
 
 // Simple MIME-type literal string checker with a given (major) type.
 // Only accepts "{aMajor}/[a-z0-9\-\.]+".
 template <size_t MajorLengthPlus1>
 constexpr bool
 IsMIMETypeWithMajor(const char* aString, size_t aLength,
                     const char (&aMajor)[MajorLengthPlus1])
 {
-  return aLength > MajorLengthPlus1 // Major + '/' + at least 1 char
-         && StartsWithMIMETypeMajor(aString, aMajor, MajorLengthPlus1 - 1)
-         && EndsWithMIMESubtype(aString + MajorLengthPlus1,
-                                aLength - MajorLengthPlus1);
+  return aLength > MajorLengthPlus1 && // Major + '/' + at least 1 char
+         StartsWithMIMETypeMajor(aString, aMajor, MajorLengthPlus1 - 1) &&
+         EndsWithMIMESubtype(aString + MajorLengthPlus1,
+                             aLength - MajorLengthPlus1);
 }
 
 } // namespace detail
 
 // Simple MIME-type string checker.
 // Only accepts lowercase "{application,audio,video}/[a-z0-9\-\.]+".
 // Add more if necessary.
 constexpr bool
 IsMediaMIMEType(const char* aString, size_t aLength)
 {
-  return detail::IsMIMETypeWithMajor(aString, aLength, "application")
-         || detail::IsMIMETypeWithMajor(aString, aLength, "audio")
-         || detail::IsMIMETypeWithMajor(aString, aLength, "video");
+  return detail::IsMIMETypeWithMajor(aString, aLength, "application") ||
+         detail::IsMIMETypeWithMajor(aString, aLength, "audio") ||
+         detail::IsMIMETypeWithMajor(aString, aLength, "video");
 }
 
 // Simple MIME-type string literal checker.
 // Only accepts lowercase "{application,audio,video}/[a-z0-9\-\.]+".
 // Add more if necessary.
 template <size_t LengthPlus1>
 constexpr bool
 IsMediaMIMEType(const char (&aString)[LengthPlus1])
@@ -519,20 +519,23 @@ public:
     Pointer mStart;
     Pointer mEnd;
     Pointer mComma;
   };
 
   explicit StringListRange(const String& aList) : mList(aList) {}
   Iterator begin() const
   {
-    return Iterator(mList.Data()
-                    + ((empties == StringListRangeEmptyItems::ProcessEmptyItems
-                        && mList.Length() == 0) ? 1 : 0),
-                    mList.Length());
+    return Iterator(
+      mList.Data()
+      + ((empties == StringListRangeEmptyItems::ProcessEmptyItems &&
+          mList.Length() == 0)
+          ? 1
+          : 0),
+      mList.Length());
   }
   Iterator end() const
   {
     return Iterator(mList.Data() + mList.Length()
                     + (empties != StringListRangeEmptyItems::Skip ? 1 : 0),
                     0);
   }
 private:
--- a/dom/media/encoder/MediaEncoder.cpp
+++ b/dom/media/encoder/MediaEncoder.cpp
@@ -165,18 +165,18 @@ MediaEncoder::CreateEncoder(const nsAStr
   if (!aTrackTypes) {
     LOG(LogLevel::Error, ("NO TrackTypes!!!"));
     return nullptr;
   }
 #ifdef MOZ_WEBM_ENCODER
   else if (MediaEncoder::IsWebMEncoderEnabled() &&
           (aMIMEType.EqualsLiteral(VIDEO_WEBM) ||
           (aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
-    if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK
-        && MediaDecoder::IsOpusEnabled()) {
+    if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK &&
+        MediaDecoder::IsOpusEnabled()) {
       audioEncoder = new OpusTrackEncoder();
       NS_ENSURE_TRUE(audioEncoder, nullptr);
     }
     videoEncoder = new VP8TrackEncoder(aTrackRate);
     writer = new WebMWriter(aTrackTypes);
     NS_ENSURE_TRUE(writer, nullptr);
     NS_ENSURE_TRUE(videoEncoder, nullptr);
     mimeType = NS_LITERAL_STRING(VIDEO_WEBM);
--- a/dom/media/flac/FlacDecoder.cpp
+++ b/dom/media/flac/FlacDecoder.cpp
@@ -19,15 +19,15 @@ FlacDecoder::IsEnabled()
   // Until bug 1295886 is fixed.
   return false;
 #endif
 }
 
 /* static */ bool
 FlacDecoder::IsSupportedType(const MediaContainerType& aContainerType)
 {
-  return IsEnabled()
-         && (aContainerType.Type() == MEDIAMIMETYPE("audio/flac")
-             || aContainerType.Type() == MEDIAMIMETYPE("audio/x-flac")
-             || aContainerType.Type() == MEDIAMIMETYPE("application/x-flac"));
+  return IsEnabled() &&
+         (aContainerType.Type() == MEDIAMIMETYPE("audio/flac") ||
+          aContainerType.Type() == MEDIAMIMETYPE("audio/x-flac") ||
+          aContainerType.Type() == MEDIAMIMETYPE("application/x-flac"));
 }
 
 } // namespace mozilla
--- a/dom/media/flac/FlacDemuxer.cpp
+++ b/dom/media/flac/FlacDemuxer.cpp
@@ -444,34 +444,33 @@ public:
 
 private:
   bool GetNextFrame(MediaResourceIndex& aResource)
   {
     while (mNextFrame.FindNext(aResource)) {
       // Move our offset slightly, so that we don't find the same frame at the
       // next FindNext call.
       aResource.Seek(SEEK_CUR, mNextFrame.Header().Size());
-      if (mFrame.IsValid()
-          && mNextFrame.Offset() - mFrame.Offset() < FLAC_MAX_FRAME_SIZE
-          && !CheckCRC16AtOffset(mFrame.Offset(),
-                                 mNextFrame.Offset(),
-                                 aResource)) {
+      if (mFrame.IsValid() &&
+          mNextFrame.Offset() - mFrame.Offset() < FLAC_MAX_FRAME_SIZE &&
+          !CheckCRC16AtOffset(
+            mFrame.Offset(), mNextFrame.Offset(), aResource)) {
         // The frame doesn't match its CRC or would be too far, skip it..
         continue;
       }
       CheckFrameData();
       break;
     }
     return mNextFrame.IsValid();
   }
 
   bool CheckFrameData()
   {
-    if (mNextFrame.Header().Info().mRate == 0
-        || mNextFrame.Header().Info().mBitDepth == 0) {
+    if (mNextFrame.Header().Info().mRate == 0 ||
+        mNextFrame.Header().Info().mBitDepth == 0) {
       if (!Info().IsValid()) {
         // We can only use the STREAMINFO data if we have one.
         mNextFrame.SetInvalid();
       } else {
         if (mNextFrame.Header().Info().mRate == 0) {
           mNextFrame.SetRate(Info().mRate);
         }
         if (mNextFrame.Header().Info().mBitDepth == 0) {
@@ -486,19 +485,18 @@ private:
                           MediaResourceIndex& aResource) const
   {
     int64_t size = aEnd - aStart;
     if (size <= 0) {
       return false;
     }
     UniquePtr<char[]> buffer(new char[size]);
     uint32_t read = 0;
-    if (NS_FAILED(aResource.ReadAt(aStart, buffer.get(),
-                                   size, &read))
-        || read != size) {
+    if (NS_FAILED(aResource.ReadAt(aStart, buffer.get(), size, &read)) ||
+        read != size) {
       NS_WARNING("Couldn't read frame content");
       return false;
     }
 
     uint16_t crc = 0;
     uint8_t* buf = reinterpret_cast<uint8_t*>(buffer.get());
     const uint8_t *end = buf + size;
     while (buf < end) {
@@ -779,18 +777,18 @@ FlacTrackDemuxer::FastSeek(const TimeUni
       // Same frame found twice. We're done.
       break;
     }
     lastFoundOffset = Some(frame.Offset());
 
     if (frame.Time() == aTime) {
       break;
     }
-    if (aTime > frame.Time()
-        && aTime - frame.Time() <= TimeUnit::FromSeconds(GAP_THRESHOLD)) {
+    if (aTime > frame.Time() &&
+        aTime - frame.Time() <= TimeUnit::FromSeconds(GAP_THRESHOLD)) {
       // We're close enough to the target, experimentation shows that bisection
       // search doesn't help much after that.
       break;
     }
     if (frame.Time() > aTime) {
       last = pivot;
       pivot -= (pivot - first) / 2;
     } else {
@@ -808,20 +806,20 @@ FlacTrackDemuxer::FastSeek(const TimeUni
 
 TimeUnit
 FlacTrackDemuxer::ScanUntil(const TimeUnit& aTime)
 {
   LOG("ScanUntil(%f avgFrameLen=%f mParsedFramesDuration=%f offset=%" PRId64,
       aTime.ToSeconds(), AverageFrameLength(),
       mParsedFramesDuration.ToSeconds(), mParser->CurrentFrame().Offset());
 
-   if (!mParser->FirstFrame().IsValid()
-       || aTime <= mParser->FirstFrame().Time()) {
-     return FastSeek(aTime);
-   }
+  if (!mParser->FirstFrame().IsValid() ||
+      aTime <= mParser->FirstFrame().Time()) {
+    return FastSeek(aTime);
+  }
 
   int64_t previousOffset = 0;
   TimeUnit previousTime;
   while (FindNextFrame().IsValid() && mParser->CurrentFrame().Time() < aTime) {
     previousOffset = mParser->CurrentFrame().Offset();
     previousTime = mParser->CurrentFrame().Time();
   }
 
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -53,21 +53,21 @@ MP4Decoder::IsSupportedType(const MediaC
 {
   if (!IsEnabled()) {
     return false;
   }
 
   // Whitelist MP4 types, so they explicitly match what we encounter on
   // the web, as opposed to what we use internally (i.e. what our demuxers
   // etc output).
-  const bool isAudio = aType.Type() == MEDIAMIMETYPE("audio/mp4")
-                       || aType.Type() == MEDIAMIMETYPE("audio/x-m4a");
-  const bool isVideo = aType.Type() == MEDIAMIMETYPE("video/mp4")
-                       || aType.Type() == MEDIAMIMETYPE("video/quicktime")
-                       || aType.Type() == MEDIAMIMETYPE("video/x-m4v");
+  const bool isAudio = aType.Type() == MEDIAMIMETYPE("audio/mp4") ||
+                       aType.Type() == MEDIAMIMETYPE("audio/x-m4a");
+  const bool isVideo = aType.Type() == MEDIAMIMETYPE("video/mp4") ||
+                       aType.Type() == MEDIAMIMETYPE("video/quicktime") ||
+                       aType.Type() == MEDIAMIMETYPE("video/x-m4v");
 
   if (!isAudio && !isVideo) {
     return false;
   }
 
   nsTArray<UniquePtr<TrackInfo>> trackInfos;
   if (aType.ExtendedType().Codecs().IsEmpty()) {
     // No codecs specified. Assume H.264
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -360,26 +360,25 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demu
                                   mInfo->IsAudio()))
   , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex))
   , mNeedReIndex(true)
 {
   EnsureUpToDateIndex(); // Force update of index
 
   VideoInfo* videoInfo = mInfo->GetAsVideoInfo();
   // Collect telemetry from h264 AVCC SPS.
-  if (videoInfo
-      && (mInfo->mMimeType.EqualsLiteral("video/mp4")
-          || mInfo->mMimeType.EqualsLiteral("video/avc"))) {
+  if (videoInfo && (mInfo->mMimeType.EqualsLiteral("video/mp4") ||
+                    mInfo->mMimeType.EqualsLiteral("video/avc"))) {
     mIsH264 = true;
     RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData;
     mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData);
     mp4_demuxer::SPSData spsdata;
-    if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata)
-        && spsdata.pic_width > 0 && spsdata.pic_height > 0
-        && mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
+    if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) &&
+        spsdata.pic_width > 0 && spsdata.pic_height > 0 &&
+        mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
       videoInfo->mImage.width = spsdata.pic_width;
       videoInfo->mImage.height = spsdata.pic_height;
       videoInfo->mDisplay.width = spsdata.display_width;
       videoInfo->mDisplay.height = spsdata.display_height;
     }
   } else {
     // No SPS to be found.
     mNeedSPSForTelemetry = false;
@@ -527,19 +526,18 @@ MP4TrackDemuxer::GetSamples(int32_t aNum
       if (mp4_demuxer::H264::HasSPS(extradata)) {
         RefPtr<MediaByteBuffer> extradata =
           mp4_demuxer::H264::ExtractExtraData(sample);
         mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata);
       }
     }
   }
 
-  if (mNextKeyframeTime.isNothing()
-      || samples->mSamples.LastElement()->mTime
-      >= mNextKeyframeTime.value()) {
+  if (mNextKeyframeTime.isNothing() ||
+      samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value()) {
     SetNextKeyFrameTime();
   }
   return SamplesPromise::CreateAndResolve(samples, __func__);
 }
 
 void
 MP4TrackDemuxer::SetNextKeyFrameTime()
 {
--- a/dom/media/gtest/TestVPXDecoding.cpp
+++ b/dom/media/gtest/TestVPXDecoding.cpp
@@ -45,19 +45,18 @@ ParseIVFConfig(nsTArray<uint8_t>& data, 
   if (data[0] != 'D' || data[1] != 'K' || data[2] != 'I' || data[3] != 'F') {
     // Expect 'DKIP'
     return nullptr;
   }
   if (data[4] != 0 || data[5] != 0) {
     // Expect version==0.
     return nullptr;
   }
-  if (data[8] != 'V' || data[9] != 'P'
-      || (data[10] != '8' && data[10] != '9')
-      || data[11] != '0') {
+  if (data[8] != 'V' || data[9] != 'P' ||
+      (data[10] != '8' && data[10] != '9') || data[11] != '0') {
     // Expect 'VP80' or 'VP90'.
     return nullptr;
   }
   config.w = uint32_t(data[12]) || (uint32_t(data[13]) << 8);
   config.h = uint32_t(data[14]) || (uint32_t(data[15]) << 8);
   vpx_codec_iface_t* codec = (data[10] == '8')
                              ? vpx_codec_vp8_dx()
                              : vpx_codec_vp9_dx();
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -270,18 +270,18 @@ MediaSourceDecoder::GetDuration()
 }
 
 MediaDecoderOwner::NextFrameStatus
 MediaSourceDecoder::NextFrameBufferedStatus()
 {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
 
-  if (!mMediaSource
-      || mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
+  if (!mMediaSource ||
+      mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
   }
 
   // Next frame hasn't been decoded yet.
   // Use the buffered range to consider if we have the next frame available.
   auto currentPosition = CurrentPosition();
   TimeIntervals buffered = GetBuffered();
   buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -827,18 +827,18 @@ TrackBuffersManager::CreateDemuxerforMIM
 
   if (mType.Type() == MEDIAMIMETYPE("video/webm") ||
       mType.Type() == MEDIAMIMETYPE("audio/webm")) {
     mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ );
     return;
   }
 
 #ifdef MOZ_FMP4
-  if (mType.Type() == MEDIAMIMETYPE("video/mp4")
-      || mType.Type() == MEDIAMIMETYPE("audio/mp4")) {
+  if (mType.Type() == MEDIAMIMETYPE("video/mp4") ||
+      mType.Type() == MEDIAMIMETYPE("audio/mp4")) {
     mInputDemuxer = new MP4Demuxer(mCurrentInputBuffer);
     return;
   }
 #endif
   NS_WARNING("Not supported (yet)");
 }
 
 // We reset the demuxer by creating a new one and initializing it.
@@ -1770,18 +1770,18 @@ TrackBuffersManager::InsertFrames(TrackB
   // 15. Remove decoding dependencies of the coded frames removed in the previous step:
   // Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
 
   TimeIntervals intersection = trackBuffer.mBufferedRanges;
   intersection.Intersection(aIntervals);
 
   if (intersection.Length()) {
     if (aSamples[0]->mKeyframe &&
-        (mType.Type() == MEDIAMIMETYPE("video/webm")
-         || mType.Type() == MEDIAMIMETYPE("audio/webm"))) {
+        (mType.Type() == MEDIAMIMETYPE("video/webm") ||
+         mType.Type() == MEDIAMIMETYPE("audio/webm"))) {
       // We are starting a new GOP, we do not have to worry about breaking an
       // existing current coded frame group. Reset the next insertion index
       // so the search for when to start our frames removal can be exhaustive.
       // This is a workaround for bug 1276184 and only until either bug 1277733
       // or bug 1209386 is fixed.
       // With the webm container, we can't always properly determine the
       // duration of the last frame, which may cause the last frame of a cluster
       // to overlap the following frame.
--- a/dom/media/mp3/MP3Decoder.cpp
+++ b/dom/media/mp3/MP3Decoder.cpp
@@ -16,19 +16,17 @@ MP3Decoder::IsEnabled() {
   RefPtr<PDMFactory> platform = new PDMFactory();
   return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg"),
                                     /* DecoderDoctorDiagnostics* */ nullptr);
 }
 
 /* static */
 bool MP3Decoder::IsSupportedType(const MediaContainerType& aContainerType)
 {
-  if (aContainerType.Type() == MEDIAMIMETYPE("audio/mp3")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/mpeg")) {
-    return
-      IsEnabled()
-      && (aContainerType.ExtendedType().Codecs().IsEmpty()
-          || aContainerType.ExtendedType().Codecs() == "mp3");
+  if (aContainerType.Type() == MEDIAMIMETYPE("audio/mp3") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/mpeg")) {
+    return IsEnabled() && (aContainerType.ExtendedType().Codecs().IsEmpty() ||
+                           aContainerType.ExtendedType().Codecs() == "mp3");
   }
   return false;
 }
 
 } // namespace mozilla
--- a/dom/media/mp3/MP3Demuxer.cpp
+++ b/dom/media/mp3/MP3Demuxer.cpp
@@ -473,25 +473,25 @@ MP3TrackDemuxer::FindFirstFrame()
 
 static bool
 VerifyFrameConsistency(const FrameParser::Frame& aFrame1,
                        const FrameParser::Frame& aFrame2)
 {
   const auto& h1 = aFrame1.Header();
   const auto& h2 = aFrame2.Header();
 
-  return h1.IsValid()
-         && h2.IsValid()
-         && h1.Layer() == h2.Layer()
-         && h1.SlotSize() == h2.SlotSize()
-         && h1.SamplesPerFrame() == h2.SamplesPerFrame()
-         && h1.Channels() == h2.Channels()
-         && h1.SampleRate() == h2.SampleRate()
-         && h1.RawVersion() == h2.RawVersion()
-         && h1.RawProtection() == h2.RawProtection();
+  return h1.IsValid() &&
+         h2.IsValid() &&
+         h1.Layer() == h2.Layer() &&
+         h1.SlotSize() == h2.SlotSize() &&
+         h1.SamplesPerFrame() == h2.SamplesPerFrame() &&
+         h1.Channels() == h2.Channels() &&
+         h1.SampleRate() == h2.SampleRate() &&
+         h1.RawVersion() == h2.RawVersion() &&
+         h1.RawProtection() == h2.RawProtection();
 }
 
 MediaByteRange
 MP3TrackDemuxer::FindNextFrame()
 {
   static const int BUFFER_SIZE = 64;
   static const uint32_t MAX_SKIPPABLE_BYTES = 1024 * BUFFER_SIZE;
 
@@ -532,36 +532,35 @@ MP3TrackDemuxer::FindNextFrame()
         maxSkippableBytes += mParser.ID3Header().TotalTagSize();
       }
     } else if (mFrameLock) {
       // We've found a valid MPEG stream, so don't impose any limits
       // to allow skipping corrupted data until we hit EOS.
       maxSkippableBytes = std::numeric_limits<uint32_t>::max();
     }
 
-    if ((mOffset - startOffset > maxSkippableBytes)
-        || (read = Read(buffer, mOffset, BUFFER_SIZE)) == 0) {
+    if ((mOffset - startOffset > maxSkippableBytes) ||
+        (read = Read(buffer, mOffset, BUFFER_SIZE)) == 0) {
       MP3LOG("FindNext() EOS or exceeded maxSkippeableBytes without a frame");
       // This is not a valid MPEG audio stream or we've reached EOS, give up.
       break;
     }
 
     ByteReader reader(buffer, read);
     uint32_t bytesToSkip = 0;
     foundFrame = mParser.Parse(&reader, &bytesToSkip);
     frameHeaderOffset =
       mOffset + reader.Offset() - FrameParser::FrameHeader::SIZE;
 
     // If we've found neither an MPEG frame header nor an ID3v2 tag,
     // the reader shouldn't have any bytes remaining.
     MOZ_ASSERT(foundFrame || bytesToSkip || !reader.Remaining());
 
-    if (foundFrame && mParser.FirstFrame().Length()
-        && !VerifyFrameConsistency(mParser.FirstFrame(),
-                                   mParser.CurrentFrame())) {
+    if (foundFrame && mParser.FirstFrame().Length() &&
+        !VerifyFrameConsistency(mParser.FirstFrame(), mParser.CurrentFrame())) {
       // We've likely hit a false-positive, ignore it and proceed with the
       // search for the next valid frame.
       foundFrame = false;
       mOffset = frameHeaderOffset + 1;
       mParser.EndFrameSession();
     } else {
       // Advance mOffset by the amount of bytes read and if necessary,
       // skip an ID3v2 tag which stretches beyond the current buffer.
--- a/dom/media/mp3/MP3FrameParser.cpp
+++ b/dom/media/mp3/MP3FrameParser.cpp
@@ -396,22 +396,22 @@ bool
 FrameParser::VBRHeader::IsValid() const
 {
   return mType != NONE;
 }
 
 bool
 FrameParser::VBRHeader::IsComplete() const
 {
-  return IsValid()
-         && mNumAudioFrames.valueOr(0) > 0
-         && mNumBytes.valueOr(0) > 0
+  return IsValid() &&
+         mNumAudioFrames.valueOr(0) > 0 &&
+         mNumBytes.valueOr(0) > 0
          // We don't care about the scale for any computations here.
          // && mScale < 101
-         && true;
+         ;
 }
 
 int64_t
 FrameParser::VBRHeader::Offset(float aDurationFac) const
 {
   if (!IsTOCPresent()) {
     return -1;
   }
@@ -694,18 +694,18 @@ ID3Parser::ID3Header::IsValid(int aPos) 
     return true;
   }
   const uint8_t c = mRaw[aPos];
   switch (aPos) {
     case 0: case 1: case 2:
       // Expecting "ID3".
       return id3_header::ID[aPos] == c;
     case 3:
-      return MajorVersion() >= id3_header::MIN_MAJOR_VER
-             && MajorVersion() <= id3_header::MAX_MAJOR_VER;
+      return MajorVersion() >= id3_header::MIN_MAJOR_VER &&
+             MajorVersion() <= id3_header::MAX_MAJOR_VER;
     case 4:
       return MinorVersion() < 0xFF;
     case 5:
       // Validate flags for supported versions, see bug 949036.
       return ((0xFF >> MajorVersion()) & c) == 0;
     case 6: case 7: case 8: case 9:
       return c < 0x80;
   }
@@ -716,18 +716,18 @@ bool
 ID3Parser::ID3Header::IsValid() const
 {
   return mPos >= SIZE;
 }
 
 bool
 ID3Parser::ID3Header::Update(uint8_t c)
 {
-  if (mPos >= id3_header::SIZE_END - id3_header::SIZE_LEN
-      && mPos < id3_header::SIZE_END) {
+  if (mPos >= id3_header::SIZE_END - id3_header::SIZE_LEN &&
+      mPos < id3_header::SIZE_END) {
     mSize <<= 7;
     mSize |= c;
   }
   if (mPos < SIZE) {
     mRaw[mPos] = c;
   }
   return IsValid(mPos++);
 }
--- a/dom/media/ogg/OggCodecState.cpp
+++ b/dom/media/ogg/OggCodecState.cpp
@@ -430,20 +430,20 @@ TheoraState::Time(int64_t granulepos)
 }
 
 bool
 TheoraState::IsHeader(ogg_packet* aPacket)
 {
   return th_packet_isheader(aPacket);
 }
 
-# define TH_VERSION_CHECK(_info,_maj,_min,_sub) \
- (((_info)->version_major>(_maj)||(_info)->version_major==(_maj)) \
-  && (((_info)->version_minor>(_min)||(_info)->version_minor==(_min)) \
-  && (_info)->version_subminor>=(_sub)))
+#define TH_VERSION_CHECK(_info, _maj, _min, _sub)                              \
+  (((_info)->version_major > (_maj) || (_info)->version_major == (_maj)) &&    \
+   (((_info)->version_minor > (_min) || (_info)->version_minor == (_min)) &&   \
+    (_info)->version_subminor >= (_sub)))
 
 int64_t
 TheoraState::Time(th_info* aInfo, int64_t aGranulepos)
 {
   if (aGranulepos < 0 || aInfo->fps_numerator == 0) {
     return -1;
   }
   // Implementation of th_granule_frame inlined here to operate
@@ -596,19 +596,18 @@ TheoraState::ReconstructTheoraGranulepos
     ogg_int64_t frame = firstFrame + i;
     ogg_int64_t granulepos;
     auto& packet = mUnstamped[i];
     bool isKeyframe = th_packet_iskeyframe(packet.get()) == 1;
 
     if (isKeyframe) {
       granulepos = frame << shift;
       keyframe = frame;
-    } else if (frame >= keyframe
-               && frame - keyframe < ((ogg_int64_t)1 << shift))
-    {
+    } else if (frame >= keyframe &&
+               frame - keyframe < ((ogg_int64_t)1 << shift)) {
       // (frame - keyframe) won't overflow the "offset" segment of the
       // granulepos, so it's safe to calculate the granulepos.
       granulepos = (keyframe << shift) + (frame - keyframe);
     } else {
       // (frame - keyframeno) will overflow the "offset" segment of the
       // granulepos, so we take "keyframe" to be the max possible offset
       // frame instead.
       ogg_int64_t k =
@@ -619,33 +618,31 @@ TheoraState::ReconstructTheoraGranulepos
     // should be > 0.
     // Theora 3.2.0 granulepos store the frame index [0..(N-1)], so
     // granulepos should be >= 0.
     NS_ASSERTION(granulepos >= version_3_2_1,
                   "Invalid granulepos for Theora version");
 
     // Check that the frame's granule number is one more than the
     // previous frame's.
-    NS_ASSERTION(i == 0
-                 || th_granule_frame(mCtx, granulepos)
-                    == th_granule_frame(mCtx, mUnstamped[i-1]->granulepos)
-                       + 1,
+    NS_ASSERTION(i == 0 ||
+                 th_granule_frame(mCtx, granulepos) ==
+                 th_granule_frame(mCtx, mUnstamped[i - 1]->granulepos) + 1,
                  "Granulepos calculation is incorrect!");
 
     packet->granulepos = granulepos;
   }
 
   // Check that the second to last frame's granule number is one less than
   // the last frame's (the known granule number). If not our granulepos
   // recovery missed a beat.
   NS_ASSERTION(
-    mUnstamped.Length() < 2
-    || th_granule_frame(mCtx, mUnstamped[mUnstamped.Length() - 2]->granulepos)
-       + 1
-       == th_granule_frame(mCtx, lastGranulepos),
+    mUnstamped.Length() < 2 ||
+    (th_granule_frame(mCtx, mUnstamped[mUnstamped.Length() - 2]->granulepos)
+     + 1) == th_granule_frame(mCtx, lastGranulepos),
     "Granulepos recovery should catch up with packet->granulepos!");
 }
 
 nsresult
 VorbisState::Reset()
 {
   nsresult res = NS_OK;
   if (mActive && vorbis_synthesis_restart(&mDsp) != 0) {
@@ -1127,19 +1124,18 @@ OpusState::Time(int aPreSkip, int64_t aG
   // Ogg Opus always runs at a granule rate of 48 kHz.
   CheckedInt64 t = SaferMultDiv(aGranulepos - aPreSkip, USECS_PER_S, 48000);
   return t.isValid() ? t.value() : -1;
 }
 
 bool
 OpusState::IsHeader(ogg_packet* aPacket)
 {
-  return aPacket->bytes >= 16
-         && (!memcmp(aPacket->packet, "OpusHead", 8)
-             || !memcmp(aPacket->packet, "OpusTags", 8));
+  return aPacket->bytes >= 16 && (!memcmp(aPacket->packet, "OpusHead", 8) ||
+                                  !memcmp(aPacket->packet, "OpusTags", 8));
 }
 
 nsresult
 OpusState::PageIn(ogg_page* aPage)
 {
   if (!mActive) {
     return NS_OK;
   }
@@ -1189,19 +1185,19 @@ OpusState::PacketDuration(ogg_packet* aP
   CheckedInt64 t = SaferMultDiv(GetOpusDeltaGP(aPacket), USECS_PER_S, 48000);
   return t.isValid() ? t.value() : -1;
 }
 
 bool
 OpusState::ReconstructOpusGranulepos(void)
 {
   NS_ASSERTION(mUnstamped.Length() > 0, "Must have unstamped packets");
-  NS_ASSERTION(mUnstamped.LastElement()->e_o_s
-    || mUnstamped.LastElement()->granulepos > 0,
-    "Must know last granulepos!");
+  NS_ASSERTION(mUnstamped.LastElement()->e_o_s ||
+               mUnstamped.LastElement()->granulepos > 0,
+               "Must know last granulepos!");
   int64_t gp;
   // If this is the last page, and we've seen at least one previous page (or
   // this is the first page)...
   if (mUnstamped.LastElement()->e_o_s) {
     auto& last = mUnstamped.LastElement();
     if (mPrevPageGranulepos != -1) {
       // If this file only has one page and the final granule position is
       // smaller than the pre-skip amount, we MUST reject the stream.
@@ -1493,52 +1489,49 @@ static const size_t INDEX_KEYPOINT_OFFSE
 static const size_t FISBONE_MSG_FIELDS_OFFSET = 8;
 static const size_t FISBONE_SERIALNO_OFFSET = 12;
 
 static bool
 IsSkeletonBOS(ogg_packet* aPacket)
 {
   static_assert(SKELETON_MIN_HEADER_LEN >= 8,
                 "Minimum length of skeleton BOS header incorrect");
-  return aPacket->bytes >= SKELETON_MIN_HEADER_LEN
-         && memcmp(reinterpret_cast<char*>(aPacket->packet), "fishead", 8) == 0;
+  return aPacket->bytes >= SKELETON_MIN_HEADER_LEN &&
+         memcmp(reinterpret_cast<char*>(aPacket->packet), "fishead", 8) == 0;
 }
 
 static bool
 IsSkeletonIndex(ogg_packet* aPacket)
 {
   static_assert(SKELETON_4_0_MIN_INDEX_LEN >= 5,
                 "Minimum length of skeleton index header incorrect");
-  return aPacket->bytes >= SKELETON_4_0_MIN_INDEX_LEN
-         && memcmp(reinterpret_cast<char*>(aPacket->packet), "index", 5) == 0;
+  return aPacket->bytes >= SKELETON_4_0_MIN_INDEX_LEN &&
+         memcmp(reinterpret_cast<char*>(aPacket->packet), "index", 5) == 0;
 }
 
 static bool
 IsSkeletonFisbone(ogg_packet* aPacket)
 {
   static_assert(SKELETON_MIN_FISBONE_LEN >= 8,
                 "Minimum length of skeleton fisbone header incorrect");
-  return aPacket->bytes >= SKELETON_MIN_FISBONE_LEN
-         && memcmp(reinterpret_cast<char*>(aPacket->packet), "fisbone", 8) == 0;
+  return aPacket->bytes >= SKELETON_MIN_FISBONE_LEN &&
+         memcmp(reinterpret_cast<char*>(aPacket->packet), "fisbone", 8) == 0;
 }
 
 // Reads a variable length encoded integer at p. Will not read
 // past aLimit. Returns pointer to character after end of integer.
 static const unsigned char*
 ReadVariableLengthInt(const unsigned char* p,
                       const unsigned char* aLimit,
                       int64_t& n)
 {
   int shift = 0;
   int64_t byte = 0;
   n = 0;
-  while (p < aLimit
-         && (byte & 0x80) != 0x80
-         && shift < 57)
-  {
+  while (p < aLimit && (byte & 0x80) != 0x80 && shift < 57) {
     byte = static_cast<int64_t>(*p);
     n |= ((byte & 0x7f) << shift);
     shift += 7;
     p++;
   }
   return p;
 }
 
@@ -1591,19 +1584,19 @@ SkeletonState::DecodeIndex(ogg_packet* a
     (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET;
   if (!minPacketSize.isValid())
   {
     return (mActive = false);
   }
 
   int64_t sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET;
   int64_t maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE;
-  if (aPacket->bytes < minPacketSize.value()
-      || numKeyPoints > maxNumKeyPoints
-      || numKeyPoints < 0) {
+  if (aPacket->bytes < minPacketSize.value() ||
+      numKeyPoints > maxNumKeyPoints ||
+      numKeyPoints < 0) {
     // Packet size is less than the theoretical minimum size, or the packet is
     // claiming to store more keypoints than it's capable of storing. This means
     // that the numKeyPoints field is too large or small for the packet to
     // possibly contain as many packets as it claims to, so the numKeyPoints
     // field is possibly malicious. Don't try decoding this index, we may run
     // out of memory.
     LOG(LogLevel::Debug, ("Possibly malicious number of key points reported "
                        "(%" PRId64 ") in index packet for stream %u.",
@@ -1618,27 +1611,27 @@ SkeletonState::DecodeIndex(ogg_packet* a
   const unsigned char* limit = aPacket->packet + aPacket->bytes;
   int64_t numKeyPointsRead = 0;
   CheckedInt64 offset = 0;
   CheckedInt64 time = 0;
   while (p < limit && numKeyPointsRead < numKeyPoints) {
     int64_t delta = 0;
     p = ReadVariableLengthInt(p, limit, delta);
     offset += delta;
-    if (p == limit
-        || !offset.isValid()
-        || offset.value() > mLength
-        || offset.value() < 0) {
+    if (p == limit ||
+        !offset.isValid() ||
+        offset.value() > mLength ||
+        offset.value() < 0) {
       return (mActive = false);
     }
     p = ReadVariableLengthInt(p, limit, delta);
     time += delta;
-    if (!time.isValid()
-        || time.value() > endTime
-        || time.value() < startTime) {
+    if (!time.isValid() ||
+        time.value() > endTime ||
+        time.value() < startTime) {
       return (mActive = false);
     }
     CheckedInt64 timeUsecs = SaferMultDiv(time.value(), USECS_PER_S, timeDenom);
     if (!timeUsecs.isValid()) {
       return (mActive = false);
     }
     keyPoints->Add(offset.value(), timeUsecs.value());
     numKeyPointsRead++;
@@ -1657,20 +1650,20 @@ SkeletonState::DecodeIndex(ogg_packet* a
 nsresult
 SkeletonState::IndexedSeekTargetForTrack(uint32_t aSerialno,
                                          int64_t aTarget,
                                          nsKeyPoint& aResult)
 {
   nsKeyFrameIndex* index = nullptr;
   mIndex.Get(aSerialno, &index);
 
-  if (!index
-      || index->Length() == 0
-      || aTarget < index->mStartTime
-      || aTarget > index->mEndTime) {
+  if (!index ||
+      index->Length() == 0 ||
+      aTarget < index->mStartTime ||
+      aTarget > index->mEndTime) {
     return NS_ERROR_FAILURE;
   }
 
   // Binary search to find the last key point with time less than target.
   int start = 0;
   int end = index->Length() - 1;
   while (end > start) {
     int mid = start + ((end - start + 1) >> 1);
@@ -1699,18 +1692,18 @@ SkeletonState::IndexedSeekTarget(int64_t
   }
   // Loop over all requested tracks' indexes, and get the keypoint for that
   // seek target. Record the keypoint with the lowest offset, this will be
   // our seek result. User must seek to the one with lowest offset to ensure we
   // pass "keyframes" on all tracks when we decode forwards to the seek target.
   nsSeekTarget r;
   for (uint32_t i=0; i<aTracks.Length(); i++) {
     nsKeyPoint k;
-    if (NS_SUCCEEDED(IndexedSeekTargetForTrack(aTracks[i], aTarget, k))
-        && k.mOffset < r.mKeyPoint.mOffset) {
+    if (NS_SUCCEEDED(IndexedSeekTargetForTrack(aTracks[i], aTarget, k)) &&
+        k.mOffset < r.mKeyPoint.mOffset) {
       r.mKeyPoint = k;
       r.mSerial = aTracks[i];
     }
   }
   if (r.IsNull()) {
     return NS_ERROR_FAILURE;
   }
   LOG(LogLevel::Debug, ("Indexed seek target for time %" PRId64 " is offset %" PRId64,
@@ -1718,20 +1711,20 @@ SkeletonState::IndexedSeekTarget(int64_t
   aResult = r;
   return NS_OK;
 }
 
 nsresult
 SkeletonState::GetDuration(const nsTArray<uint32_t>& aTracks,
                            int64_t& aDuration)
 {
-  if (!mActive
-      || mVersion < SKELETON_VERSION(4,0)
-      || !HasIndex()
-      || aTracks.Length() == 0) {
+  if (!mActive ||
+      mVersion < SKELETON_VERSION(4,0) ||
+      !HasIndex() ||
+      aTracks.Length() == 0) {
     return NS_ERROR_FAILURE;
   }
   int64_t endTime = INT64_MIN;
   int64_t startTime = INT64_MAX;
   for (uint32_t i=0; i<aTracks.Length(); i++) {
     nsKeyFrameIndex* index = nullptr;
     mIndex.Get(aTracks[i], &index);
     if (!index) {
@@ -1850,19 +1843,19 @@ SkeletonState::DecodeHeader(OggPacketPtr
     int64_t d = LittleEndian::readInt64(
       aPacket->packet + SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET);
     mPresentationTime =
       d == 0 ? 0
              : (static_cast<float>(n) / static_cast<float>(d)) * USECS_PER_S;
 
     mVersion = SKELETON_VERSION(verMajor, verMinor);
     // We can only care to parse Skeleton version 4.0+.
-    if (mVersion < SKELETON_VERSION(4,0)
-        || mVersion >= SKELETON_VERSION(5,0)
-        || aPacket->bytes < SKELETON_4_0_MIN_HEADER_LEN) {
+    if (mVersion < SKELETON_VERSION(4,0) ||
+        mVersion >= SKELETON_VERSION(5,0) ||
+        aPacket->bytes < SKELETON_4_0_MIN_HEADER_LEN) {
       return false;
     }
 
     // Extract the segment length.
     mLength =
       LittleEndian::readInt64(aPacket->packet + SKELETON_FILE_LENGTH_OFFSET);
 
     LOG(LogLevel::Debug, ("Skeleton segment length: %" PRId64, mLength));
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -119,19 +119,19 @@ public:
       RefPtr<MediaByteBuffer> extraData =
         aTrackConfig.GetAsVideoInfo()->mExtraData;
       AddToCheckList([mimeType, extraData]() {
         if (MP4Decoder::IsH264(mimeType)) {
           mp4_demuxer::SPSData spsdata;
           // WMF H.264 Video Decoder and Apple ATDecoder
           // do not support YUV444 format.
           // For consistency, all decoders should be checked.
-          if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata)
-              && (spsdata.profile_idc == 244 /* Hi444PP */
-                  || spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
+          if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) &&
+              (spsdata.profile_idc == 244 /* Hi444PP */ ||
+               spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
             return CheckResult(
               SupportChecker::Reason::kVideoFormatNotSupported,
               MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                           RESULT_DETAIL("Decoder may not have the capability "
                                         "to handle the requested video format "
                                         "with YUV444 chroma subsampling.")));
           }
         }
--- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
@@ -19,24 +19,24 @@
 namespace mozilla {
 
 bool
 AgnosticDecoderModule::SupportsMimeType(
   const nsACString& aMimeType,
   DecoderDoctorDiagnostics* aDiagnostics) const
 {
   bool supports =
-    VPXDecoder::IsVPX(aMimeType)
+    VPXDecoder::IsVPX(aMimeType) ||
 #ifdef MOZ_AV1
-    || AOMDecoder::IsAV1(aMimeType)
+    AOMDecoder::IsAV1(aMimeType) ||
 #endif
-    || OpusDataDecoder::IsOpus(aMimeType)
-    || VorbisDataDecoder::IsVorbis(aMimeType)
-    || WaveDataDecoder::IsWave(aMimeType)
-    || TheoraDecoder::IsTheora(aMimeType);
+    OpusDataDecoder::IsOpus(aMimeType) ||
+    VorbisDataDecoder::IsVorbis(aMimeType) ||
+    WaveDataDecoder::IsWave(aMimeType) ||
+    TheoraDecoder::IsTheora(aMimeType);
   MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type",
         supports ? "supports" : "rejects"));
   return supports;
 }
 
 already_AddRefed<MediaDataDecoder>
 AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
 {
--- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp
@@ -90,20 +90,20 @@ BlankAudioDataCreator::BlankAudioDataCre
 
 already_AddRefed<MediaData>
 BlankAudioDataCreator::Create(MediaRawData* aSample)
 {
   // Convert duration to frames. We add 1 to duration to account for
   // rounding errors, so we get a consistent tone.
   CheckedInt64 frames = UsecsToFrames(
     aSample->mDuration.ToMicroseconds()+1, mSampleRate);
-  if (!frames.isValid()
-      || !mChannelCount
-      || !mSampleRate
-      || frames.value() > (UINT32_MAX / mChannelCount)) {
+  if (!frames.isValid() ||
+      !mChannelCount ||
+      !mSampleRate ||
+      frames.value() > (UINT32_MAX / mChannelCount)) {
     return nullptr;
   }
   AlignedAudioBuffer samples(frames.value() * mChannelCount);
   if (!samples) {
     return nullptr;
   }
   // Fill the sound buffer with an A4 tone.
   static const float pi = 3.14159265f;
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -280,20 +280,20 @@ VPXDecoder::DecodeAlpha(vpx_image_t** aI
 
   return NS_OK;
 }
 
 /* static */
 bool
 VPXDecoder::IsVPX(const nsACString& aMimeType, uint8_t aCodecMask)
 {
-  return ((aCodecMask & VPXDecoder::VP8)
-          && aMimeType.EqualsLiteral("video/vp8"))
-         || ((aCodecMask & VPXDecoder::VP9)
-             && aMimeType.EqualsLiteral("video/vp9"));
+  return ((aCodecMask & VPXDecoder::VP8) &&
+          aMimeType.EqualsLiteral("video/vp8")) ||
+         ((aCodecMask & VPXDecoder::VP9) &&
+          aMimeType.EqualsLiteral("video/vp9"));
 }
 
 /* static */
 bool
 VPXDecoder::IsVP8(const nsACString& aMimeType)
 {
   return IsVPX(aMimeType, VPXDecoder::VP8);
 }
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -47,19 +47,19 @@ CreateDecoderWrapper()
   RefPtr<MediaDataDecoderProxy> decoder(
     new MediaDataDecoderProxy(thread.forget()));
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 GMPDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
 {
-  if (!MP4Decoder::IsH264(aParams.mConfig.mMimeType)
-      && !VPXDecoder::IsVP8(aParams.mConfig.mMimeType)
-      && !VPXDecoder::IsVP9(aParams.mConfig.mMimeType)) {
+  if (!MP4Decoder::IsH264(aParams.mConfig.mMimeType) &&
+      !VPXDecoder::IsVP8(aParams.mConfig.mMimeType) &&
+      !VPXDecoder::IsVP9(aParams.mConfig.mMimeType)) {
     return nullptr;
   }
 
   RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper();
   auto params = GMPVideoDecoderParams(aParams);
   wrapper->SetProxyTarget(new GMPVideoDecoder(params));
   return wrapper.forget();
 }
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -134,35 +134,35 @@ AndroidDecoderModule::SupportsMimeType(
   if (aMimeType.EqualsLiteral("video/mp4") ||
       aMimeType.EqualsLiteral("video/avc")) {
     return true;
   }
 
   // When checking "audio/x-wav", CreateDecoder can cause a JNI ERROR by
   // Accessing a stale local reference leading to a SIGSEGV crash.
   // To avoid this we check for wav types here.
-  if (aMimeType.EqualsLiteral("audio/x-wav")
-      || aMimeType.EqualsLiteral("audio/wave; codecs=1")
-      || aMimeType.EqualsLiteral("audio/wave; codecs=6")
-      || aMimeType.EqualsLiteral("audio/wave; codecs=7")
-      || aMimeType.EqualsLiteral("audio/wave; codecs=65534")) {
+  if (aMimeType.EqualsLiteral("audio/x-wav") ||
+      aMimeType.EqualsLiteral("audio/wave; codecs=1") ||
+      aMimeType.EqualsLiteral("audio/wave; codecs=6") ||
+      aMimeType.EqualsLiteral("audio/wave; codecs=7") ||
+      aMimeType.EqualsLiteral("audio/wave; codecs=65534")) {
     return false;
   }
 
-  if ((VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8)
-       && !GetFeatureStatus(nsIGfxInfo::FEATURE_VP8_HW_DECODE))
-      || (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP9)
-          && !GetFeatureStatus(nsIGfxInfo::FEATURE_VP9_HW_DECODE))) {
+  if ((VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8) &&
+       !GetFeatureStatus(nsIGfxInfo::FEATURE_VP8_HW_DECODE)) ||
+      (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP9) &&
+       !GetFeatureStatus(nsIGfxInfo::FEATURE_VP9_HW_DECODE))) {
     return false;
   }
 
   // Prefer the gecko decoder for opus and vorbis; stagefright crashes
   // on content demuxed from mp4.
-  if (OpusDataDecoder::IsOpus(aMimeType)
-      || VorbisDataDecoder::IsVorbis(aMimeType)) {
+  if (OpusDataDecoder::IsOpus(aMimeType) ||
+      VorbisDataDecoder::IsVorbis(aMimeType)) {
     LOG("Rejecting audio of type %s", aMimeType.Data());
     return false;
   }
 
   return java::HardwareCodecCapabilityUtils::FindDecoderCodecInfoForMimeType(
     nsCString(TranslateMimeType(aMimeType)));
 }
 
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -38,18 +38,18 @@ FFmpegLibWrapper::Link()
   if (!isFFMpeg) {
     if (macro == 57) {
       // Due to current AVCodecContext binary incompatibility we can only
       // support FFmpeg 57 at this stage.
       Unlink();
       return LinkResult::CannotUseLibAV57;
     }
 #ifdef MOZ_FFMPEG
-    if (version < (54u << 16 | 35u << 8 | 1u)
-        && !MediaPrefs::LibavcodecAllowObsolete()) {
+    if (version < (54u << 16 | 35u << 8 | 1u) &&
+        !MediaPrefs::LibavcodecAllowObsolete()) {
       // Refuse any libavcodec version prior to 54.35.1.
       // (Unless media.libavcodec.allow-obsolete==true)
       Unlink();
       return LinkResult::BlockedOldLibAVVersion;
     }
 #endif
   }
 
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -80,18 +80,18 @@ FFmpegVideoDecoder<LIBAV_VER>::PtsCorrec
   if (aDts != int64_t(AV_NOPTS_VALUE)) {
     mNumFaultyDts += aDts <= mLastDts;
     mLastDts = aDts;
   }
   if (aPts != int64_t(AV_NOPTS_VALUE)) {
     mNumFaultyPts += aPts <= mLastPts;
     mLastPts = aPts;
   }
-  if ((mNumFaultyPts <= mNumFaultyDts || aDts == int64_t(AV_NOPTS_VALUE))
-      && aPts != int64_t(AV_NOPTS_VALUE)) {
+  if ((mNumFaultyPts <= mNumFaultyDts || aDts == int64_t(AV_NOPTS_VALUE)) &&
+      aPts != int64_t(AV_NOPTS_VALUE)) {
     pts = aPts;
   } else {
     pts = aDts;
   }
   return pts;
 }
 
 void
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -182,20 +182,20 @@ HRESULT ConvertMFTypeToDXVAType(IMFMedia
   hr = MFGetAttributeRatio(
     pType, MF_MT_FRAME_RATE, &fpsNumerator, &fpsDenominator);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   pDesc->InputSampleFreq.Numerator = fpsNumerator;
   pDesc->InputSampleFreq.Denominator = fpsDenominator;
 
   GetDXVA2ExtendedFormatFromMFMediaType(pType, &pDesc->SampleFormat);
   pDesc->OutputFrameFreq = pDesc->InputSampleFreq;
-  if ((pDesc->SampleFormat.SampleFormat
-       == DXVA2_SampleFieldInterleavedEvenFirst)
-      || (pDesc->SampleFormat.SampleFormat
-          == DXVA2_SampleFieldInterleavedOddFirst)) {
+  if ((pDesc->SampleFormat.SampleFormat ==
+       DXVA2_SampleFieldInterleavedEvenFirst) ||
+      (pDesc->SampleFormat.SampleFormat ==
+       DXVA2_SampleFieldInterleavedOddFirst)) {
     pDesc->OutputFrameFreq.Numerator *= 2;
   }
 
   return S_OK;
 }
 
 static const GUID DXVA2_ModeH264_E = {
   0x1b81be68, 0xa0c7, 0x11d3, { 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5 }
@@ -368,18 +368,18 @@ D3D9DXVA2Manager::Init(layers::KnowsComp
     aFailureReason = nsPrintfCString(
       "IDirectXVideoDecoderServer::GetDecoderDeviceGuids failed with error %X",
       hr);
     return hr;
   }
 
   bool found = false;
   for (UINT i = 0; i < deviceCount; i++) {
-    if (decoderDevices[i] == DXVA2_ModeH264_E
-        || decoderDevices[i] == DXVA2_Intel_ModeH264_E) {
+    if (decoderDevices[i] == DXVA2_ModeH264_E ||
+        decoderDevices[i] == DXVA2_Intel_ModeH264_E) {
       mDecoderGUID = decoderDevices[i];
       found = true;
       break;
     }
   }
   CoTaskMemFree(decoderDevices);
 
   if (!found) {
@@ -819,18 +819,18 @@ D3D11DXVA2Manager::InitInternal(layers::
     return hr;
   }
 
   bool found = false;
   UINT profileCount = videoDevice->GetVideoDecoderProfileCount();
   for (UINT i = 0; i < profileCount; i++) {
     GUID id;
     hr = videoDevice->GetVideoDecoderProfile(i, &id);
-    if (SUCCEEDED(hr)
-        && (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E)) {
+    if (SUCCEEDED(hr) &&
+        (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E)) {
       mDecoderGUID = id;
       found = true;
       break;
     }
   }
   if (!found) {
     aFailureReason.AssignLiteral("Failed to find an appropriate decoder GUID");
     return E_FAIL;
@@ -1258,14 +1258,14 @@ DXVA2Manager::~DXVA2Manager()
 bool
 DXVA2Manager::IsUnsupportedResolution(const uint32_t& aWidth,
                                       const uint32_t& aHeight,
                                       const float& aFramerate) const
 {
   // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in
   // hardware, so use software instead. Pick 45 as an arbitrary upper bound for
   // the framerate we can handle.
-  return mIsAMDPreUVD4
-         && (aWidth >= 1920 || aHeight >= 1088)
-         && aFramerate > 45;
+  return mIsAMDPreUVD4 &&
+         (aWidth >= 1920 || aHeight >= 1088) &&
+         aFramerate > 45;
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -229,34 +229,31 @@ bool
 WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
                            DecoderDoctorDiagnostics* aDiagnostics) const
 {
   if ((aTrackInfo.mMimeType.EqualsLiteral("audio/mp4a-latm") ||
        aTrackInfo.mMimeType.EqualsLiteral("audio/mp4")) &&
        WMFDecoderModule::HasAAC()) {
     return true;
   }
-  if (MP4Decoder::IsH264(aTrackInfo.mMimeType)
-      && WMFDecoderModule::HasH264()) {
+  if (MP4Decoder::IsH264(aTrackInfo.mMimeType) && WMFDecoderModule::HasH264()) {
     if (!MediaPrefs::PDMWMFAllowUnsupportedResolutions()) {
       const VideoInfo* videoInfo = aTrackInfo.GetAsVideoInfo();
       MOZ_ASSERT(videoInfo);
       // Check Windows format constraints, based on:
       // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
       if (IsWin8OrLater() || IsWin7H264Decoder4KCapable()) {
         // Windows >7, and Win7 with recent-enough decoder, support at most
         // 4096x2304.
-        if (videoInfo->mImage.width > 4096
-            || videoInfo->mImage.height > 2304) {
+        if (videoInfo->mImage.width > 4096 || videoInfo->mImage.height > 2304) {
           return false;
         }
       } else {
         // Windows <=7 (with original decoder) supports at most 1920x1088.
-        if (videoInfo->mImage.width > 1920
-            || videoInfo->mImage.height > 1088) {
+        if (videoInfo->mImage.width > 1920 || videoInfo->mImage.height > 1088) {
           return false;
         }
       }
     }
     return true;
   }
   if (aTrackInfo.mMimeType.EqualsLiteral("audio/mpeg") &&
       CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>()) {
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -326,19 +326,19 @@ FindDXVABlacklistedDLL(
       if (infoSize == 0) {
         // Can't get file info -> Assume we don't have the blacklisted DLL.
         continue;
       }
       // vInfo is a pointer into infoData, that's why we keep it outside of the loop.
       auto infoData = MakeUnique<unsigned char[]>(infoSize);
       VS_FIXEDFILEINFO *vInfo;
       UINT vInfoLen;
-      if (!GetFileVersionInfoW(dllPath, 0, infoSize, infoData.get())
-          || !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)
-          || !vInfo) {
+      if (!GetFileVersionInfoW(dllPath, 0, infoSize, infoData.get()) ||
+          !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen) ||
+          !vInfo) {
         // Can't find version -> Assume it's not blacklisted.
         continue;
       }
 
       nsTArray<nsCString> versions;
       SplitAt(",", nameAndVersions[1], versions);
       for (const auto& version : versions) {
         nsTArray<nsCString> numberStrings;
@@ -367,18 +367,18 @@ FindDXVABlacklistedDLL(
         if (NS_FAILED(errorCode)) {
           NS_WARNING(
             nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
                             aDLLBlacklistPrefName)
             .get());
           continue;
         }
 
-        if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1])
-            && vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
+        if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1]) &&
+            vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
           // Blacklisted! Record bad DLL.
           aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
           aDLLBlacklistingCache->mBlacklistedDLL.AppendPrintf(
             "%s (%lu.%lu.%lu.%lu)",
             nameAndVersions[0].get(),
             numbers[0],
             numbers[1],
             numbers[2],
@@ -527,19 +527,19 @@ bool
 WMFVideoMFTManager::ValidateVideoInfo()
 {
   // The WMF H.264 decoder is documented to have a minimum resolution
   // 48x48 pixels. We've observed the decoder working for output smaller than
   // that, but on some output it hangs in IMFTransform::ProcessOutput(), so
   // we just reject streams which are less than the documented minimum.
   // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
   static const int32_t MIN_H264_FRAME_DIMENSION = 48;
-  if (mStreamType == H264
-      && (mVideoInfo.mImage.width < MIN_H264_FRAME_DIMENSION
-          || mVideoInfo.mImage.height < MIN_H264_FRAME_DIMENSION)) {
+  if (mStreamType == H264 &&
+      (mVideoInfo.mImage.width < MIN_H264_FRAME_DIMENSION ||
+       mVideoInfo.mImage.height < MIN_H264_FRAME_DIMENSION)) {
     LogToBrowserConsole(NS_LITERAL_STRING(
       "Can't decode H.264 stream with width or height less than 48 pixels."));
     mIsValid = false;
   }
 
   return mIsValid;
 }
 
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -57,18 +57,18 @@ H264Converter::Init()
            TrackType::kVideoTrack, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 H264Converter::Decode(MediaRawData* aSample)
 {
   MOZ_RELEASE_ASSERT(mFlushPromise.IsEmpty(), "Flush operatin didn't complete");
 
-  MOZ_RELEASE_ASSERT(!mDecodePromiseRequest.Exists()
-                     && !mInitPromiseRequest.Exists(),
+  MOZ_RELEASE_ASSERT(!mDecodePromiseRequest.Exists() &&
+                       !mInitPromiseRequest.Exists(),
                      "Can't request a new decode until previous one completed");
 
   if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
     // We need AVCC content to be able to later parse the SPS.
     // This is a no-op if the data is already AVCC.
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("ConvertSampleToAVCC")),
       __func__);
@@ -117,18 +117,18 @@ H264Converter::Decode(MediaRawData* aSam
                   RESULT_DETAIL("Unable to create H264 decoder")),
       __func__);
   }
 
   if (mNeedKeyframe && !aSample->mKeyframe) {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   }
 
-  if (!*mNeedAVCC
-      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+  if (!*mNeedAVCC &&
+      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("ConvertSampleToAnnexB")),
       __func__);
   }
 
   mNeedKeyframe = false;
 
@@ -252,18 +252,18 @@ H264Converter::CreateDecoder(const Video
     return NS_ERROR_NOT_INITIALIZED;
   }
   UpdateConfigFromExtraData(aConfig.mExtraData);
 
   mp4_demuxer::SPSData spsdata;
   if (mp4_demuxer::H264::DecodeSPSFromExtraData(aConfig.mExtraData, spsdata)) {
     // Do some format check here.
     // WMF H.264 Video Decoder and Apple ATDecoder do not support YUV444 format.
-    if (spsdata.profile_idc == 244 /* Hi444PP */
-        || spsdata.chroma_format_idc == PDMFactory::kYUV444) {
+    if (spsdata.profile_idc == 244 /* Hi444PP */ ||
+        spsdata.chroma_format_idc == PDMFactory::kYUV444) {
       mLastError = NS_ERROR_FAILURE;
       if (aDiagnostics) {
         aDiagnostics->SetVideoNotSupported();
       }
       return NS_ERROR_FAILURE;
     }
   } else {
     // SPS was invalid.
@@ -351,35 +351,34 @@ H264Converter::CreateDecoderAndInit(Medi
   }
   return rv;
 }
 
 bool
 H264Converter::CanRecycleDecoder() const
 {
   MOZ_ASSERT(mDecoder);
-  return MediaPrefs::MediaDecoderCheckRecycling()
-         && mDecoder->SupportDecoderRecycling();
+  return MediaPrefs::MediaDecoderCheckRecycling() &&
+         mDecoder->SupportDecoderRecycling();
 }
 
 void
 H264Converter::DecodeFirstSample(MediaRawData* aSample)
 {
   if (mNeedKeyframe && !aSample->mKeyframe) {
     mDecodePromise.Resolve(mPendingFrames, __func__);
     mPendingFrames.Clear();
     return;
   }
 
-  if (!*mNeedAVCC
-      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
-    mDecodePromise.Reject(
-      MediaResult(NS_ERROR_OUT_OF_MEMORY,
-                  RESULT_DETAIL("ConvertSampleToAnnexB")),
-      __func__);
+  if (!*mNeedAVCC &&
+      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+    mDecodePromise.Reject(MediaResult(NS_ERROR_OUT_OF_MEMORY,
+                                      RESULT_DETAIL("ConvertSampleToAnnexB")),
+                          __func__);
     return;
   }
 
   mNeedKeyframe = false;
 
   RefPtr<H264Converter> self = this;
   mDecoder->Decode(aSample)
     ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
@@ -531,19 +530,18 @@ void H264Converter::FlushThenShutdownDec
            })
     ->Track(mFlushRequest);
 }
 
 void
 H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
 {
   mp4_demuxer::SPSData spsdata;
-  if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)
-      && spsdata.pic_width > 0
-      && spsdata.pic_height > 0) {
+  if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
+      spsdata.pic_width > 0 && spsdata.pic_height > 0) {
     mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
     mCurrentConfig.mImage.width = spsdata.pic_width;
     mCurrentConfig.mImage.height = spsdata.pic_height;
     mCurrentConfig.mDisplay.width = spsdata.display_width;
     mCurrentConfig.mDisplay.height = spsdata.display_height;
   }
   mCurrentConfig.mExtraData = aExtraData;
 }
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -690,18 +690,19 @@ CamerasParent::RecvAllocateCaptureDevice
   RefPtr<CamerasParent> self(this);
   RefPtr<Runnable> mainthread_runnable =
     media::NewRunnableFrom([self, aCapEngine, unique_id, aPrincipalInfo]() -> nsresult {
       // Verify whether the claimed origin has received permission
       // to use the camera, either persistently or this session (one shot).
       bool allowed = HasCameraPermission(aPrincipalInfo);
       if (!allowed) {
         // Developer preference for turning off permission check.
-        if (Preferences::GetBool("media.navigator.permission.disabled", false)
-            || Preferences::GetBool("media.navigator.permission.fake")) {
+        if (Preferences::GetBool("media.navigator.permission.disabled",
+                                 false) ||
+            Preferences::GetBool("media.navigator.permission.fake")) {
           allowed = true;
           LOG(("No permission but checks are disabled or fake sources active"));
         } else {
           LOG(("No camera permission for this origin"));
         }
       }
       // After retrieving the permission (or not) on the main thread,
       // bounce to the WebRTC thread to allocate the device (or not),
@@ -855,20 +856,20 @@ CamerasParent::StopCapture(const Capture
     engine->WithEntry(capnum,[](VideoEngine::CaptureEntry& cap){
       if (cap.VideoCapture()) {
         cap.VideoCapture()->StopCapture();
         cap.VideoCapture()->DeRegisterCaptureDataCallback();
       }
     });
     // we're removing elements, iterate backwards
     for (size_t i = mCallbacks.Length(); i > 0; i--) {
-      if (mCallbacks[i-1]->mCapEngine == aCapEngine
-          && mCallbacks[i-1]->mStreamId == (uint32_t) capnum) {
-        delete mCallbacks[i-1];
-        mCallbacks.RemoveElementAt(i-1);
+      if (mCallbacks[i - 1]->mCapEngine == aCapEngine &&
+          mCallbacks[i - 1]->mStreamId == (uint32_t)capnum) {
+        delete mCallbacks[i - 1];
+        mCallbacks.RemoveElementAt(i - 1);
         break;
       }
     }
     engine->Shutdown();
   }
 }
 
 mozilla::ipc::IPCResult
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -99,19 +99,20 @@ public:
                                                    const VideoCaptureCapability&) override;
   virtual mozilla::ipc::IPCResult RecvStopCapture(const CaptureEngine&, const int&) override;
   virtual mozilla::ipc::IPCResult RecvReleaseFrame(mozilla::ipc::Shmem&&) override;
   virtual mozilla::ipc::IPCResult RecvAllDone() override;
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
   virtual mozilla::ipc::IPCResult RecvEnsureInitialized(const CaptureEngine&) override;
 
   nsIEventTarget* GetBackgroundEventTarget() { return mPBackgroundEventTarget; };
-  bool IsShuttingDown() { return !mChildIsAlive
-                              ||  mDestroyed
-                              || !mWebRTCAlive; };
+  bool IsShuttingDown()
+  {
+    return !mChildIsAlive || mDestroyed || !mWebRTCAlive;
+  };
   ShmemBuffer GetBuffer(size_t aSize);
 
   // helper to forward to the PBackground thread
   int DeliverFrameOverIPC(CaptureEngine capEng,
                           uint32_t aStreamId,
                           ShmemBuffer buffer,
                           unsigned char* altbuffer,
                           VideoFrameProperties& aProps);
--- a/dom/media/systemservices/VideoFrameUtils.cpp
+++ b/dom/media/systemservices/VideoFrameUtils.cpp
@@ -51,25 +51,27 @@ void VideoFrameUtils::CopyVideoFrameBuff
                        const size_t aDestBufferSize,
                        const webrtc::VideoFrame& aFrame)
 {
   size_t aggregateSize = TotalRequiredBufferSize(aFrame);
 
   MOZ_ASSERT(aDestBufferSize >= aggregateSize);
 
   // If planes are ordered YUV and contiguous then do a single copy
-  if ((aFrame.video_frame_buffer()->DataY() != nullptr)
+  if ((aFrame.video_frame_buffer()->DataY() != nullptr) &&
       // Check that the three planes are ordered
-      && (aFrame.video_frame_buffer()->DataY() < aFrame.video_frame_buffer()->DataU())
-      && (aFrame.video_frame_buffer()->DataU() < aFrame.video_frame_buffer()->DataV())
+      (aFrame.video_frame_buffer()->DataY()
+       < aFrame.video_frame_buffer()->DataU()) &&
+      (aFrame.video_frame_buffer()->DataU()
+       < aFrame.video_frame_buffer()->DataV()) &&
       //  Check that the last plane ends at firstPlane[totalsize]
-      && (&aFrame.video_frame_buffer()->DataY()[aggregateSize] ==
-          &aFrame.video_frame_buffer()->DataV()[((aFrame.video_frame_buffer()->height()+1)/2) *
-                                                aFrame.video_frame_buffer()->StrideV()]))
-  {
+      (&aFrame.video_frame_buffer()->DataY()[aggregateSize] ==
+       &aFrame.video_frame_buffer()
+          ->DataV()[((aFrame.video_frame_buffer()->height() + 1) / 2)
+                    * aFrame.video_frame_buffer()->StrideV()])) {
     memcpy(aDestBuffer, aFrame.video_frame_buffer()->DataY(), aggregateSize);
     return;
   }
 
   // Copy each plane
   size_t offset = 0;
   size_t size;
   auto height = aFrame.video_frame_buffer()->height();
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -282,8 +282,10 @@ skip-if = (android_version == '18') # an
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_selftest.html]
 # Bug 1227781: Crash with bogus TURN server.
 [test_peerConnection_bug1227781.html]
 [test_peerConnection_stats.html]
 skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator, Bug 1373858)
 [test_peerConnection_sender_and_receiver_stats.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
+[test_peerConnection_verifyDescriptions.html]
+skip-if = (android_version == '18')
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -841,45 +841,25 @@ PeerConnectionWrapper.prototype = {
    *
    * @returns {object} The local description
    */
   get localDescription() {
     return this._pc.localDescription;
   },
 
   /**
-   * Sets the local description.
-   *
-   * @param {object} desc
-   *        The new local description
-   */
-  set localDescription(desc) {
-    this._pc.localDescription = desc;
-  },
-
-  /**
    * Returns the remote description.
    *
    * @returns {object} The remote description
    */
   get remoteDescription() {
     return this._pc.remoteDescription;
   },
 
   /**
-   * Sets the remote description.
-   *
-   * @param {object} desc
-   *        The new remote description
-   */
-  set remoteDescription(desc) {
-    this._pc.remoteDescription = desc;
-  },
-
-  /**
    * Returns the signaling state.
    *
    * @returns {object} The local description
    */
   get signalingState() {
     return this._pc.signalingState;
   },
   /**
copy from dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
copy to dom/media/tests/mochitest/test_peerConnection_verifyDescriptions.html
--- a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
+++ b/dom/media/tests/mochitest/test_peerConnection_verifyDescriptions.html
@@ -2,62 +2,60 @@
 <html>
 <head>
   <script type="application/javascript" src="pc.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
-    bug: "1091898",
-    title: "PeerConnection with promises (sendonly)",
-    visible: true
+    bug: "1264479",
+    title: "PeerConnection verify current and pending descriptions"
   });
 
   var pc1 = new RTCPeerConnection();
   var pc2 = new RTCPeerConnection();
 
   var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
   pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
   pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
 
   var v1, v2;
-  var delivered = new Promise(resolve => pc2.ontrack = e => {
-    // Test RTCTrackEvent here.
-    ok(e.streams.length > 0, "has streams");
-    ok(e.streams[0].getTrackById(e.track.id), "has track");
-    ok(pc2.getReceivers().some(receiver => receiver == e.receiver), "has receiver");
-    if (e.streams[0].getTracks().length == 2) {
-      // Test RTCTrackEvent required args here.
-      mustThrowWith("RTCTrackEvent wo/required args",
-                    "TypeError", () => new RTCTrackEvent("track", {}));
-      v2.srcObject = e.streams[0];
-      resolve();
-    }
-  });
 
   runNetworkTest(function() {
     v1 = createMediaElement('video', 'v1');
     v2 = createMediaElement('video', 'v2');
-    var canPlayThrough = new Promise(resolve => v2.canplaythrough = e => resolve());
-
-    is(v2.currentTime, 0, "v2.currentTime is zero at outset");
 
     navigator.mediaDevices.getUserMedia({ video: true, audio: true })
     .then(stream => (v1.srcObject = stream).getTracks().forEach(t => pc1.addTrack(t, stream)))
     .then(() => pc1.createOffer({})) // check that createOffer accepts arg.
     .then(offer => pc1.setLocalDescription(offer))
+    .then(() => {
+      ok(!pc1.currentLocalDescription, "pc1 currentLocalDescription is empty");
+      ok(pc1.pendingLocalDescription, "pc1 pendingLocalDescription is set");
+      ok(pc1.localDescription, "pc1 localDescription is set");
+    })
     .then(() => pc2.setRemoteDescription(pc1.localDescription))
+    .then(() => {
+      ok(!pc2.currentRemoteDescription, "pc2 currentRemoteDescription is empty");
+      ok(pc2.pendingRemoteDescription, "pc2 pendingRemoteDescription is set");
+      ok(pc2.remoteDescription, "pc2 remoteDescription is set");
+    })
     .then(() => pc2.createAnswer({}))  // check that createAnswer accepts arg.
     .then(answer => pc2.setLocalDescription(answer))
+    .then(() => {
+      ok(pc2.currentLocalDescription, "pc2 currentLocalDescription is set");
+      ok(!pc2.pendingLocalDescription, "pc2 pendingLocalDescription is empty");
+      ok(pc2.localDescription, "pc2 localDescription is set");
+    })
     .then(() => pc1.setRemoteDescription(pc2.localDescription))
-    .then(() => delivered)
-//    .then(() => canPlayThrough)    // why doesn't this fire?
-    .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
-    .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
-    .then(() => ok(true, "Connected."))
+    .then(() => {
+      ok(pc1.currentRemoteDescription, "pc1 currentRemoteDescription is set");
+      ok(!pc1.pendingRemoteDescription, "pc1 pendingRemoteDescription is empty");
+      ok(pc1.remoteDescription, "pc1 remoteDescription is set");
+    })
     .catch(reason => ok(false, "unexpected failure: " + reason))
     .then(networkTestFinished);
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/wave/WaveDecoder.cpp
+++ b/dom/media/wave/WaveDecoder.cpp
@@ -11,22 +11,22 @@
 namespace mozilla {
 
 /* static */ bool
 WaveDecoder::IsSupportedType(const MediaContainerType& aContainerType)
 {
   if (!MediaDecoder::IsWaveEnabled()) {
     return false;
   }
-  if (aContainerType.Type() == MEDIAMIMETYPE("audio/wave")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/x-wav")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/wav")
-      || aContainerType.Type() == MEDIAMIMETYPE("audio/x-pn-wav")) {
-    return (aContainerType.ExtendedType().Codecs().IsEmpty()
-            || aContainerType.ExtendedType().Codecs() == "1"
-            || aContainerType.ExtendedType().Codecs() == "6"
-            || aContainerType.ExtendedType().Codecs() == "7");
+  if (aContainerType.Type() == MEDIAMIMETYPE("audio/wave") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/x-wav") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/wav") ||
+      aContainerType.Type() == MEDIAMIMETYPE("audio/x-pn-wav")) {
+    return (aContainerType.ExtendedType().Codecs().IsEmpty() ||
+            aContainerType.ExtendedType().Codecs() == "1" ||
+            aContainerType.ExtendedType().Codecs() == "6" ||
+            aContainerType.ExtendedType().Codecs() == "7");
   }
 
   return false;
 }
 
 } // namespace mozilla
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -859,18 +859,18 @@ FormatParser::FormatChunk::ParseNext(uin
 {
   Update(c);
   return IsValid();
 }
 
 bool
 FormatParser::FormatChunk::IsValid() const
 {
-  return (FrameSize() == SampleRate() * Channels() / 8)
-         && (mPos >= FMT_CHUNK_MIN_SIZE);
+  return (FrameSize() == SampleRate() * Channels() / 8) &&
+         (mPos >= FMT_CHUNK_MIN_SIZE);
 }
 
 void
 FormatParser::FormatChunk::Update(uint8_t c)
 {
   if (mPos < FMT_CHUNK_MIN_SIZE) {
     mRaw[mPos++] = c;
   }
--- a/dom/media/webaudio/ScriptProcessorNode.cpp
+++ b/dom/media/webaudio/ScriptProcessorNode.cpp
@@ -540,19 +540,19 @@ JSObject*
 ScriptProcessorNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ScriptProcessorNodeBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 ScriptProcessorNode::UpdateConnectedStatus()
 {
-  bool isConnected = mHasPhantomInput ||
-    !(OutputNodes().IsEmpty() && OutputParams().IsEmpty()
-      && InputNodes().IsEmpty());
+  bool isConnected =
+    mHasPhantomInput || !(OutputNodes().IsEmpty() && OutputParams().IsEmpty() &&
+                          InputNodes().IsEmpty());
 
   // Events are queued even when there is no listener because a listener
   // may be added while events are in the queue.
   SendInt32ParameterToStream(ScriptProcessorNodeEngine::IS_CONNECTED,
                              isConnected);
 
   if (isConnected && HasListenersFor(nsGkAtoms::onaudioprocess)) {
     MarkActive();
--- a/dom/media/webaudio/blink/Reverb.cpp
+++ b/dom/media/webaudio/blink/Reverb.cpp
@@ -146,18 +146,22 @@ void Reverb::initialize(const nsTArray<c
         WriteZeroesToAudioBlock(&m_tempBuffer, 0, WEBAUDIO_BLOCK_SIZE);
     }
 }
 
 void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus)
 {
     // Do a fairly comprehensive sanity check.
     // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases.
-    bool isSafeToProcess = sourceBus && destinationBus && sourceBus->ChannelCount() > 0 && destinationBus->mChannelData.Length() > 0
-        && WEBAUDIO_BLOCK_SIZE <= MaxFrameSize && WEBAUDIO_BLOCK_SIZE <= size_t(sourceBus->GetDuration()) && WEBAUDIO_BLOCK_SIZE <= size_t(destinationBus->GetDuration());
+    bool isSafeToProcess =
+      sourceBus && destinationBus && sourceBus->ChannelCount() > 0 &&
+      destinationBus->mChannelData.Length() > 0 &&
+      WEBAUDIO_BLOCK_SIZE <= MaxFrameSize &&
+      WEBAUDIO_BLOCK_SIZE <= size_t(sourceBus->GetDuration()) &&
+      WEBAUDIO_BLOCK_SIZE <= size_t(destinationBus->GetDuration());
 
     MOZ_ASSERT(isSafeToProcess);
     if (!isSafeToProcess)
         return;
 
     // For now only handle mono or stereo output
     MOZ_ASSERT(destinationBus->ChannelCount() <= 2);
 
--- a/dom/media/webaudio/blink/ReverbConvolver.cpp
+++ b/dom/media/webaudio/blink/ReverbConvolver.cpp
@@ -113,29 +113,30 @@ ReverbConvolver::ReverbConvolver(const f
         } else
             m_stages.AppendElement(stage.forget());
 
         // Figure out next FFT size
         fftSize *= 2;
 
         stageOffset += stageSize;
 
-        if (hasRealtimeConstraint && !isBackgroundStage
-            && fftSize > MaxRealtimeFFTSize) {
-            fftSize = MaxRealtimeFFTSize;
-            // Custom phase positions for all but the first of the realtime
-            // stages of largest size.  These spread out the work of the
-            // larger realtime stages.  None of the FFTs of size 1024, 2048 or
-            // 4096 are performed when processing the same block.  The first
-            // MaxRealtimeFFTSize = 4096 stage, at the end of the doubling,
-            // performs its FFT at block 7.  The FFTs of size 2048 are
-            // performed in blocks 3 + 8 * n and size 1024 at 1 + 4 * n.
-            const uint32_t phaseLookup[] = { 14, 0, 10, 4 };
-            stagePhase = WEBAUDIO_BLOCK_SIZE *
-                phaseLookup[m_stages.Length() % ArrayLength(phaseLookup)];
+        if (hasRealtimeConstraint && !isBackgroundStage &&
+            fftSize > MaxRealtimeFFTSize) {
+          fftSize = MaxRealtimeFFTSize;
+          // Custom phase positions for all but the first of the realtime
+          // stages of largest size.  These spread out the work of the
+          // larger realtime stages.  None of the FFTs of size 1024, 2048 or
+          // 4096 are performed when processing the same block.  The first
+          // MaxRealtimeFFTSize = 4096 stage, at the end of the doubling,
+          // performs its FFT at block 7.  The FFTs of size 2048 are
+          // performed in blocks 3 + 8 * n and size 1024 at 1 + 4 * n.
+          const uint32_t phaseLookup[] = { 14, 0, 10, 4 };
+          stagePhase =
+            WEBAUDIO_BLOCK_SIZE *
+            phaseLookup[m_stages.Length() % ArrayLength(phaseLookup)];
         } else if (fftSize > maxFFTSize) {
             fftSize = maxFFTSize;
             // A prime offset spreads out FFTs in a way that all
             // available phase positions will be used if there are sufficient
             // stages.
             stagePhase += 5 * WEBAUDIO_BLOCK_SIZE;
         } else if (stageSize > WEBAUDIO_BLOCK_SIZE) {
             // As the stages are doubling in size, the next FFT will occur
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -191,18 +191,18 @@ WebMDemuxer::Init()
 {
   InitBufferedState();
 
   if (NS_FAILED(ReadMetadata())) {
     return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR,
                                         __func__);
   }
 
-  if (!GetNumberTracks(TrackInfo::kAudioTrack)
-      && !GetNumberTracks(TrackInfo::kVideoTrack)) {
+  if (!GetNumberTracks(TrackInfo::kAudioTrack) &&
+      !GetNumberTracks(TrackInfo::kVideoTrack)) {
     return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR,
                                         __func__);
   }
 
   return InitPromise::CreateAndResolve(NS_OK, __func__);
 }
 
 void
@@ -292,18 +292,18 @@ WebMDemuxer::ReadMetadata()
     }
     mBufferedState->NotifyDataArrived(buffer->Elements(), buffer->Length(), 0);
     if (mBufferedState->GetInitEndOffset() < 0) {
       return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(mBufferedState->GetInitEndOffset() <= resource.Tell());
   }
   mInitData = resource.MediaReadAt(0, mBufferedState->GetInitEndOffset());
-  if (!mInitData
-      || mInitData->Length() != size_t(mBufferedState->GetInitEndOffset())) {
+  if (!mInitData ||
+      mInitData->Length() != size_t(mBufferedState->GetInitEndOffset())) {
     return NS_ERROR_FAILURE;
   }
 
   unsigned int ntracks = 0;
   r = nestegg_track_count(context, &ntracks);
   if (r == -1) {
     return NS_ERROR_FAILURE;
   }
@@ -340,20 +340,20 @@ WebMDemuxer::ReadMetadata()
       unsigned int cropH = params.crop_right + params.crop_left;
       unsigned int cropV = params.crop_bottom + params.crop_top;
       gfx::IntRect pictureRect(params.crop_left,
                                params.crop_top,
                                params.width - cropH,
                                params.height - cropV);
 
       // If the cropping data appears invalid then use the frame data
-      if (pictureRect.width <= 0
-          || pictureRect.height <= 0
-          || pictureRect.x < 0
-          || pictureRect.y < 0) {
+      if (pictureRect.width <= 0 ||
+          pictureRect.height <= 0 ||
+          pictureRect.x < 0 ||
+          pictureRect.y < 0) {
         pictureRect.x = 0;
         pictureRect.y = 0;
         pictureRect.width = params.width;
         pictureRect.height = params.height;
       }
 
       // Validate the container-reported frame and pictureRect sizes. This
       // ensures that our video frame creation code doesn't overflow.
@@ -468,25 +468,25 @@ WebMDemuxer::ReadMetadata()
     }
   }
   return NS_OK;
 }
 
 bool
 WebMDemuxer::IsSeekable() const
 {
-  return Context(TrackInfo::kVideoTrack)
-         && nestegg_has_cues(Context(TrackInfo::kVideoTrack));
+  return Context(TrackInfo::kVideoTrack) &&
+         nestegg_has_cues(Context(TrackInfo::kVideoTrack));
 }
 
 bool
 WebMDemuxer::IsSeekableOnlyInBufferedRanges() const
 {
-  return Context(TrackInfo::kVideoTrack)
-         && !nestegg_has_cues(Context(TrackInfo::kVideoTrack));
+  return Context(TrackInfo::kVideoTrack) &&
+         !nestegg_has_cues(Context(TrackInfo::kVideoTrack));
 }
 
 void
 WebMDemuxer::EnsureUpToDateIndex()
 {
   if (!mNeedReIndex || !mInitData) {
     return;
   }
@@ -601,18 +601,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
     if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
       return rv;
     }
     if (next_holder) {
       next_tstamp = next_holder->Timestamp();
       PushAudioPacket(next_holder);
     } else if (duration >= 0) {
       next_tstamp = tstamp + duration;
-    } else if (!mIsMediaSource
-               || (mIsMediaSource && mLastAudioFrameTime.isSome())) {
+    } else if (!mIsMediaSource ||
+               (mIsMediaSource && mLastAudioFrameTime.isSome())) {
       next_tstamp = tstamp;
       next_tstamp += tstamp - mLastAudioFrameTime.refOr(0);
     } else {
       PushAudioPacket(holder);
     }
     mLastAudioFrameTime = Some(tstamp);
   } else if (aType == TrackInfo::kVideoTrack) {
     RefPtr<NesteggPacketHolder> next_holder;
@@ -620,18 +620,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
     if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
       return rv;
     }
     if (next_holder) {
       next_tstamp = next_holder->Timestamp();
       PushVideoPacket(next_holder);
     } else if (duration >= 0) {
       next_tstamp = tstamp + duration;
-    } else if (!mIsMediaSource
-               || (mIsMediaSource && mLastVideoFrameTime.isSome())) {
+    } else if (!mIsMediaSource ||
+               (mIsMediaSource && mLastVideoFrameTime.isSome())) {
       next_tstamp = tstamp;
       next_tstamp += tstamp - mLastVideoFrameTime.refOr(0);
     } else {
       PushVideoPacket(holder);
     }
     mLastVideoFrameTime = Some(tstamp);
   }
 
@@ -707,18 +707,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
             dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP9);
             break;
 #ifdef MOZ_AV1
           case NESTEGG_CODEC_AV1:
             dimensions = AOMDecoder::GetFrameSize(sample);
             break;
 #endif
           }
-          if (mLastSeenFrameSize.isSome()
-              && (dimensions != mLastSeenFrameSize.value())) {
+          if (mLastSeenFrameSize.isSome() &&
+              (dimensions != mLastSeenFrameSize.value())) {
             mInfo.mVideo.mDisplay = dimensions;
             mSharedVideoTrackInfo =
               new TrackInfoSharedPtr(mInfo.mVideo, ++sStreamSourceID);
           }
           mLastSeenFrameSize = Some(dimensions);
         }
       }
     }
@@ -756,19 +756,19 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
         discardFrames = TimeUnitToFrames(
           TimeUnit::FromNanoseconds(discardPadding), mInfo.mAudio.mRate);
       }
       if (discardFrames.isValid()) {
         sample->mDiscardPadding = discardFrames.value();
       }
     }
 
-    if (packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED
-        || packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED
-        || packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED) {
+    if (packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED ||
+        packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED ||
+        packetEncryption == NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED) {
       nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
       unsigned char const* iv;
       size_t ivLength;
       nestegg_packet_iv(holder->Packet(), &iv, &ivLength);
       writer->mCrypto.mValid = true;
       writer->mCrypto.mIVSize = ivLength;
       if (ivLength == 0) {
         // Frame is not encrypted
@@ -1183,18 +1183,18 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
     if (sample->mKeyframe) {
       frameTime = sample->mTime;
       foundKeyframe = true;
     }
     int64_t sampleTimecode = sample->mTimecode.ToMicroseconds();
     skipSamplesQueue.Push(sample.forget());
     if (!startTime) {
       startTime.emplace(sampleTimecode);
-    } else if (!foundKeyframe
-               && sampleTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
+    } else if (!foundKeyframe &&
+               sampleTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
       WEBM_DEBUG("Couldn't find keyframe in a reasonable time, aborting");
       break;
     }
   }
   // We may have demuxed more than intended, so ensure that all frames are kept
   // in the right order.
   mSamples.PushFront(Move(skipSamplesQueue));
 
@@ -1231,18 +1231,18 @@ WebMTrackDemuxer::UpdateSamples(nsTArray
   for (const auto& sample : aSamples) {
     if (sample->mCrypto.mValid) {
       nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
       writer->mCrypto.mMode = mInfo->mCrypto.mMode;
       writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
       writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
     }
   }
-  if (mNextKeyframeTime.isNothing()
-      || aSamples.LastElement()->mTime >= mNextKeyframeTime.value()) {
+  if (mNextKeyframeTime.isNothing() ||
+      aSamples.LastElement()->mTime >= mNextKeyframeTime.value()) {
     SetNextKeyFrameTime();
   }
 }
 
 nsresult
 WebMTrackDemuxer::GetNextRandomAccessPoint(TimeUnit* aTime)
 {
   if (mNextKeyframeTime.isNothing()) {
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -640,16 +640,18 @@ private:
   nsTArray<int16_t> mInputBuffer;
   // mSkipProcessing is true if none of the processing passes are enabled,
   // because of prefs or constraints. This allows simply copying the audio into
   // the MSG, skipping resampling and the whole webrtc.org code.
   bool mSkipProcessing;
 
   // To only update microphone when needed, we keep track of previous settings.
   MediaEnginePrefs mLastPrefs;
+
+  AlignedShortBuffer mInputDownmixBuffer;
 };
 
 class MediaEngineWebRTC : public MediaEngine
 {
   typedef MediaEngine Super;
 public:
   explicit MediaEngineWebRTC(MediaEnginePrefs& aPrefs);
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -201,16 +201,17 @@ MediaEngineWebRTCMicrophoneSource::Media
   , mTrackID(TRACK_NONE)
   , mStarted(false)
   , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE)
   , mTotalFrames(0)
   , mLastLogFrames(0)
   , mPlayoutDelay(0)
   , mNullTransport(nullptr)
   , mSkipProcessing(false)
+  , mInputDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
 {
   MOZ_ASSERT(aVoiceEnginePtr);
   MOZ_ASSERT(aAudioInput);
   mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
   mDeviceUUID.Assign(uuid);
   mListener = new mozilla::WebRTCAudioDataListener(this);
   mSettings->mEchoCancellation.Construct(0);
   mSettings->mAutoGainControl.Construct(0);
@@ -355,18 +356,18 @@ MediaEngineWebRTCMicrophoneSource::Updat
         MOZ_ASSERT(mSources.Length() > 0);
         auto& source = mSources.LastElement();
         mAudioInput->SetUserChannelCount(prefs.mChannels);
         // Get validated number of channel
         uint32_t channelCount = 0;
         mAudioInput->GetChannelCount(channelCount);
         MOZ_ASSERT(channelCount > 0 && mLastPrefs.mChannels > 0);
         // Check if new validated channels is the same as previous
-        if (static_cast<uint32_t>(mLastPrefs.mChannels) != channelCount
-            && !source->OpenNewAudioCallbackDriver(mListener)) {
+        if (static_cast<uint32_t>(mLastPrefs.mChannels) != channelCount &&
+            !source->OpenNewAudioCallbackDriver(mListener)) {
           return NS_ERROR_FAILURE;
         }
         // Update settings
         prefs.mChannels = channelCount;
       }
 
       if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
         MonitorAutoLock lock(mMonitor);
@@ -618,17 +619,26 @@ MediaEngineWebRTCMicrophoneSource::Packe
     uint32_t samplesPerPacket = mPacketizer->PacketSize() *
       mPacketizer->Channels();
     if (mInputBuffer.Length() < samplesPerPacket) {
       mInputBuffer.SetLength(samplesPerPacket);
     }
     int16_t* packet = mInputBuffer.Elements();
     mPacketizer->Output(packet);
 
-    mVoERender->ExternalRecordingInsertData(packet, samplesPerPacket, aRate, 0);
+    if (aChannels > MAX_CHANNELS) {
+      AudioConverter converter(AudioConfig(aChannels, 0, AudioConfig::FORMAT_S16),
+                               AudioConfig(MAX_CHANNELS, 0, AudioConfig::FORMAT_S16));
+      converter.Process(mInputDownmixBuffer, packet, mPacketizer->PacketSize());
+      mVoERender->ExternalRecordingInsertData(mInputDownmixBuffer.Data(),
+                                              mPacketizer->PacketSize() * MAX_CHANNELS,
+                                              aRate, 0);
+    } else {
+      mVoERender->ExternalRecordingInsertData(packet, samplesPerPacket, aRate, 0);
+    }
   }
 }
 
 template<typename T>
 void
 MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
                                                  size_t aFrames,
                                                  uint32_t aChannels)
@@ -656,18 +666,18 @@ MediaEngineWebRTCMicrophoneSource::Inser
     TimeStamp insertTime;
     // Make sure we include the stream and the track.
     // The 0:1 is a flag to note when we've done the final insert for a given input block.
     LogTime(AsyncLatencyLogger::AudioTrackInsertion,
             LATENCY_STREAM_ID(mSources[i].get(), mTrackID),
             (i+1 < len) ? 0 : 1, insertTime);
 
     // Bug 971528 - Support stereo capture in gUM
-    MOZ_ASSERT(aChannels == 1 || aChannels == 2,
-        "GraphDriver only supports mono and stereo audio for now");
+    MOZ_ASSERT(aChannels >= 1 && aChannels <= 8,
+               "Support up to 8 channels");
 
     nsAutoPtr<AudioSegment> segment(new AudioSegment());
     RefPtr<SharedBuffer> buffer =
       SharedBuffer::Create(aFrames * aChannels * sizeof(T));
     AutoTArray<const T*, 8> channels;
     if (aChannels == 1) {
       PodCopy(static_cast<T*>(buffer->Data()), aBuffer, aFrames);
       channels.AppendElement(static_cast<T*>(buffer->Data()));
@@ -843,17 +853,18 @@ MediaEngineWebRTCMicrophoneSource::Alloc
         // Set "codec" to PCM, 32kHz on device's channels
         ScopedCustomReleasePtr<webrtc::VoECodec> ptrVoECodec(webrtc::VoECodec::GetInterface(mVoiceEngine));
         if (ptrVoECodec) {
           webrtc::CodecInst codec;
           strcpy(codec.plname, ENCODING);
           codec.channels = CHANNELS;
           uint32_t maxChannels = 0;
           if (mAudioInput->GetMaxAvailableChannels(maxChannels) == 0) {
-            codec.channels = maxChannels;
+            MOZ_ASSERT(maxChannels);
+            codec.channels = std::min<uint32_t>(maxChannels, MAX_CHANNELS);
           }
           MOZ_ASSERT(mSampleFrequency == 16000 || mSampleFrequency == 32000);
           codec.rate = SAMPLE_RATE(mSampleFrequency);
           codec.plfreq = mSampleFrequency;
           codec.pacsize = SAMPLE_LENGTH(mSampleFrequency);
           codec.pltype = 0; // Default payload type
 
           if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {
--- a/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -96,17 +96,20 @@ GetSpeechRecognitionService(const nsAStr
   }
 
   nsresult rv;
   nsCOMPtr<nsISpeechRecognitionService> recognitionService;
   recognitionService = do_GetService(speechRecognitionServiceCID.get(), &rv);
   return recognitionService.forget();
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(SpeechRecognition, DOMEventTargetHelper, mDOMStream, mSpeechGrammarList)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(SpeechRecognition,
+                                   DOMEventTargetHelper,
+                                   mDOMStream,
+                                   mSpeechGrammarList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognition)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(SpeechRecognition, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SpeechRecognition, DOMEventTargetHelper)
 
@@ -156,32 +159,35 @@ SpeechRecognition::WrapObject(JSContext*
 }
 
 bool
 SpeechRecognition::IsAuthorized(JSContext* aCx, JSObject* aGlobal)
 {
   nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(aGlobal);
 
   nsresult rv;
-  nsCOMPtr<nsIPermissionManager> mgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
+  nsCOMPtr<nsIPermissionManager> mgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   uint32_t speechRecognition = nsIPermissionManager::UNKNOWN_ACTION;
-  rv = mgr->TestExactPermissionFromPrincipal(principal, "speech-recognition", &speechRecognition);
+  rv = mgr->TestExactPermissionFromPrincipal(
+    principal, "speech-recognition", &speechRecognition);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
-  bool hasPermission = (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
+  bool hasPermission =
+    (speechRecognition == nsIPermissionManager::ALLOW_ACTION);
 
-  return (hasPermission || MediaPrefs::WebSpeechRecognitionForceEnabled()
-          || MediaPrefs::WebSpeechTestEnabled())
-         && MediaPrefs::WebSpeechRecognitionEnabled();
+  return (hasPermission || MediaPrefs::WebSpeechRecognitionForceEnabled() ||
+          MediaPrefs::WebSpeechTestEnabled()) &&
+         MediaPrefs::WebSpeechRecognitionEnabled();
 }
 
 already_AddRefed<SpeechRecognition>
 SpeechRecognition::Constructor(const GlobalObject& aGlobal,
                                ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
   if (!win) {
@@ -360,33 +366,35 @@ SpeechRecognition::Transition(SpeechEven
         case EVENT_AUDIO_DATA:
           DoNothing(aEvent);
           break;
         case EVENT_ABORT:
           AbortSilently(aEvent);
           break;
         case EVENT_START:
         case EVENT_RECOGNITIONSERVICE_INTERMEDIATE_RESULT:
-          SR_LOG("STATE_WAITING_FOR_RESULT: Unhandled aEvent %s", GetName(aEvent));
+          SR_LOG("STATE_WAITING_FOR_RESULT: Unhandled aEvent %s",
+                 GetName(aEvent));
           MOZ_CRASH();
         case EVENT_COUNT:
           MOZ_CRASH("Invalid event EVENT_COUNT");
       }
       break;
     case STATE_COUNT:
       MOZ_CRASH("Invalid state STATE_COUNT");
   }
 }
 
 /*
  * Handle a segment of recorded audio data.
  * Returns the number of samples that were processed.
  */
 uint32_t
-SpeechRecognition::ProcessAudioSegment(AudioSegment* aSegment, TrackRate aTrackRate)
+SpeechRecognition::ProcessAudioSegment(AudioSegment* aSegment,
+                                       TrackRate aTrackRate)
 {
   AudioSegment::ChunkIterator iterator(*aSegment);
   uint32_t samples = 0;
   while (!iterator.IsEnded()) {
     float out;
     mEndpointer.ProcessAudio(*iterator, &out);
     samples += iterator->GetDuration();
     iterator.Next();
@@ -436,17 +444,18 @@ SpeechRecognition::WaitForAudioData(Spee
 }
 
 void
 SpeechRecognition::StartedAudioCapture(SpeechEvent* aEvent)
 {
   SetState(STATE_ESTIMATING);
 
   mEndpointer.SetEnvironmentEstimationMode();
-  mEstimationSamples += ProcessAudioSegment(aEvent->mAudioSegment, aEvent->mTrackRate);
+  mEstimationSamples +=
+    ProcessAudioSegment(aEvent->mAudioSegment, aEvent->mTrackRate);
 
   DispatchTrustedEvent(NS_LITERAL_STRING("audiostart"));
   if (mCurrentState == STATE_ESTIMATING) {
     DispatchTrustedEvent(NS_LITERAL_STRING("start"));
   }
 }
 
 void
@@ -460,17 +469,18 @@ SpeechRecognition::StopRecordingAndRecog
   StopRecording();
 }
 
 void
 SpeechRecognition::WaitForEstimation(SpeechEvent* aEvent)
 {
   SetState(STATE_ESTIMATING);
 
-  mEstimationSamples += ProcessAudioSegment(aEvent->mAudioSegment, aEvent->mTrackRate);
+  mEstimationSamples +=
+    ProcessAudioSegment(aEvent->mAudioSegment, aEvent->mTrackRate);
   if (mEstimationSamples > kESTIMATION_SAMPLES) {
     mEndpointer.SetUserInputMode();
     SetState(STATE_WAITING_FOR_SPEECH);
   }
 }
 
 void
 SpeechRecognition::DetectSpeech(SpeechEvent* aEvent)
@@ -510,18 +520,18 @@ SpeechRecognition::NotifyFinalResult(Spe
   RootedDictionary<SpeechRecognitionEventInit> init(RootingCx());
   init.mBubbles = true;
   init.mCancelable = false;
   // init.mResultIndex = 0;
   init.mResults = aEvent->mRecognitionResultList;
   init.mInterpretation = JS::NullValue();
   // init.mEmma = nullptr;
 
-  RefPtr<SpeechRecognitionEvent> event =
-    SpeechRecognitionEvent::Constructor(this, NS_LITERAL_STRING("result"), init);
+  RefPtr<SpeechRecognitionEvent> event = SpeechRecognitionEvent::Constructor(
+    this, NS_LITERAL_STRING("result"), init);
   event->SetTrusted(true);
 
   bool defaultActionEnabled;
   this->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
 SpeechRecognition::DoNothing(SpeechEvent* aEvent)
@@ -616,24 +626,26 @@ SpeechRecognition::Observe(nsISupports* 
              !strcmp(aTopic, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC)) {
     ProcessTestEventRequest(aSubject, nsDependentString(aData));
   }
 
   return NS_OK;
 }
 
 void
-SpeechRecognition::ProcessTestEventRequest(nsISupports* aSubject, const nsAString& aEventName)
+SpeechRecognition::ProcessTestEventRequest(nsISupports* aSubject,
+                                           const nsAString& aEventName)
 {
   if (aEventName.EqualsLiteral("EVENT_ABORT")) {
     Abort();
   } else if (aEventName.EqualsLiteral("EVENT_AUDIO_ERROR")) {
-    DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR,
-                  SpeechRecognitionErrorCode::Audio_capture, // TODO different codes?
-                  NS_LITERAL_STRING("AUDIO_ERROR test event"));
+    DispatchError(
+      SpeechRecognition::EVENT_AUDIO_ERROR,
+      SpeechRecognitionErrorCode::Audio_capture, // TODO different codes?
+      NS_LITERAL_STRING("AUDIO_ERROR test event"));
   } else {
     NS_ASSERTION(MediaPrefs::WebSpeechFakeRecognitionService(),
                  "Got request for fake recognition service event, but "
                  TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is unset");
 
     // let the fake recognition service handle the request
   }
 }
@@ -812,17 +824,18 @@ SpeechRecognition::ValidateAndSetGrammar
     return false;
   }
 
   for (uint32_t count = 0; count < grammarListLength; ++count) {
     RefPtr<SpeechGrammar> speechGrammar = mSpeechGrammarList->Item(count, aRv);
     if (aRv.Failed()) {
       return false;
     }
-    if (NS_FAILED(mRecognitionService->ValidateAndSetGrammarList(speechGrammar.get(), nullptr))) {
+    if (NS_FAILED(mRecognitionService->ValidateAndSetGrammarList(
+          speechGrammar.get(), nullptr))) {
       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return false;
     }
   }
 
   return true;
 }
 
@@ -930,17 +943,18 @@ SpeechRecognition::CreateAudioSegment(ns
   }
 
   return segment;
 }
 
 void
 SpeechRecognition::FeedAudioData(already_AddRefed<SharedBuffer> aSamples,
                                  uint32_t aDuration,
-                                 MediaStreamListener* aProvider, TrackRate aTrackRate)
+                                 MediaStreamListener* aProvider,
+                                 TrackRate aTrackRate)
 {
   NS_ASSERTION(!NS_IsMainThread(),
                "FeedAudioData should not be called in the main thread");
 
   // Endpointer expects to receive samples in chunks whose size is a
   // multiple of its frame size.
   // Since we can't assume we will receive the frames in appropriate-sized
   // chunks, we must buffer and split them in chunks of mAudioSamplesPerChunk
@@ -1030,30 +1044,32 @@ SpeechEvent::~SpeechEvent()
 
 NS_IMETHODIMP
 SpeechEvent::Run()
 {
   mRecognition->ProcessEvent(this);
   return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaSuccessCallback, nsIDOMGetUserMediaSuccessCallback)
+NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaSuccessCallback,
+                  nsIDOMGetUserMediaSuccessCallback)
 
 NS_IMETHODIMP
 SpeechRecognition::GetUserMediaSuccessCallback::OnSuccess(nsISupports* aStream)
 {
   RefPtr<DOMMediaStream> stream = do_QueryObject(aStream);
   if (!stream) {
     return NS_ERROR_NO_INTERFACE;
   }
   mRecognition->StartRecording(stream);
   return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaErrorCallback, nsIDOMGetUserMediaErrorCallback)
+NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaErrorCallback,
+                  nsIDOMGetUserMediaErrorCallback)
 
 NS_IMETHODIMP
 SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
 {
   RefPtr<MediaStreamError> error = do_QueryObject(aError);
   if (!error) {
     return NS_OK;
   }
--- a/dom/webidl/RTCPeerConnection.webidl
+++ b/dom/webidl/RTCPeerConnection.webidl
@@ -77,17 +77,21 @@ interface RTCPeerConnection : EventTarge
                             optional DOMString username);
   [Pref="media.peerconnection.identity.enabled"]
   Promise<DOMString> getIdentityAssertion();
   Promise<RTCSessionDescriptionInit> createOffer (optional RTCOfferOptions options);
   Promise<RTCSessionDescriptionInit> createAnswer (optional RTCAnswerOptions options);
   Promise<void> setLocalDescription (RTCSessionDescriptionInit description);
   Promise<void> setRemoteDescription (RTCSessionDescriptionInit description);
   readonly attribute RTCSessionDescription? localDescription;
+  readonly attribute RTCSessionDescription? currentLocalDescription;
+  readonly attribute RTCSessionDescription? pendingLocalDescription;
   readonly attribute RTCSessionDescription? remoteDescription;
+  readonly attribute RTCSessionDescription? currentRemoteDescription;
+  readonly attribute RTCSessionDescription? pendingRemoteDescription;
   readonly attribute RTCSignalingState signalingState;
   Promise<void> addIceCandidate ((RTCIceCandidateInit or RTCIceCandidate)? candidate);
   readonly attribute boolean? canTrickleIceCandidates;
   readonly attribute RTCIceGatheringState iceGatheringState;
   readonly attribute RTCIceConnectionState iceConnectionState;
   [Pref="media.peerconnection.identity.enabled"]
   readonly attribute Promise<RTCIdentityAssertion> peerIdentity;
   [Pref="media.peerconnection.identity.enabled"]
--- a/dom/webidl/StyleSheet.webidl
+++ b/dom/webidl/StyleSheet.webidl
@@ -19,16 +19,24 @@ interface StyleSheet {
   [Pure]
   readonly attribute StyleSheet? parentStyleSheet;
   [Pure]
   readonly attribute DOMString? title;
   [Constant]
   readonly attribute MediaList media;
   [Pure]
   attribute boolean disabled;
+  // The source map URL for this style sheet.  The source map URL can
+  // be found in one of two ways.
+  //
   // If a SourceMap or X-SourceMap response header is seen, this is
-  // the value.  If both are seen, SourceMap is preferred.  If neither
-  // is seen, this will be an empty string.  Because this relies on
-  // the HTTP response, it can change if checked before the response
-  // is available -- which is why it is not [Constant].
+  // the value.  If both are seen, SourceMap is preferred.  Because
+  // this relies on the HTTP response, it can change if checked before
+  // the response is available -- which is why it is not [Constant].
+  //
+  // If the style sheet has the special "# sourceMappingURL=" comment,
+  // then this is the URL specified there.
+  //
+  // If the source map URL is not found by either of these methods,
+  // then this is an empty string.
   [ChromeOnly, Pure]
   readonly attribute DOMString sourceMapURL;
 };
--- a/dom/xbl/XBLChildrenElement.cpp
+++ b/dom/xbl/XBLChildrenElement.cpp
@@ -11,24 +11,20 @@
 
 namespace mozilla {
 namespace dom {
 
 XBLChildrenElement::~XBLChildrenElement()
 {
 }
 
-NS_IMPL_ADDREF_INHERITED(XBLChildrenElement, Element)
-NS_IMPL_RELEASE_INHERITED(XBLChildrenElement, Element)
-
-NS_INTERFACE_TABLE_HEAD(XBLChildrenElement)
-  NS_INTERFACE_TABLE_INHERITED(XBLChildrenElement, nsIDOMNode,
-                               nsIDOMElement)
-  NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
-NS_INTERFACE_MAP_END_INHERITING(Element)
+NS_IMPL_ISUPPORTS_INHERITED(XBLChildrenElement,
+                            Element,
+                            nsIDOMNode,
+                            nsIDOMElement)
 
 NS_IMPL_ELEMENT_CLONE(XBLChildrenElement)
 
 nsresult
 XBLChildrenElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                   const nsAttrValueOrString* aValue,
                                   bool aNotify)
 {
@@ -55,21 +51,18 @@ using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
 
 NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList)
   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
-  NS_INTERFACE_TABLE_INHERITED(nsAnonymousContentList, nsINodeList,
-                               nsIDOMNodeList)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE
-  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsAnonymousContentList)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_TABLE(nsAnonymousContentList, nsINodeList, nsIDOMNodeList)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsAnonymousContentList)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
 nsAnonymousContentList::GetLength(uint32_t* aLength)
 {
   if (!mParent) {
     *aLength = 0;
     return NS_OK;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -91,34 +91,31 @@ BasicLayerManager::PushGroupForLayer(gfx
   bool canPushGroup = aGroupResult.mOperator == CompositionOp::OP_OVER ||
     (aGroupResult.mOperator == CompositionOp::OP_SOURCE && (aLayer->CanUseOpaqueSurface() || aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA));
 
   if (!canPushGroup) {
     aContext->Save();
     gfxUtils::ClipToRegion(aGroupResult.mFinalTarget, aGroupResult.mVisibleRegion);
 
     // PushGroup/PopGroup do not support non operator over.
-    gfxMatrix oldMat = aContext->CurrentMatrix();
-    aContext->SetMatrix(gfxMatrix());
-    gfxRect rect = aContext->GetClipExtents();
-    aContext->SetMatrix(oldMat);
+    gfxRect rect = aContext->GetClipExtents(gfxContext::eDeviceSpace);
     rect.RoundOut();
     IntRect surfRect;
     ToRect(rect).ToIntRect(&surfRect);
 
     if (!surfRect.IsEmpty()) {
       RefPtr<DrawTarget> dt = aContext->GetDrawTarget()->CreateSimilarDrawTarget(surfRect.Size(), SurfaceFormat::B8G8R8A8);
 
       RefPtr<gfxContext> ctx =
         gfxContext::CreateOrNull(dt, ToRect(rect).TopLeft());
       if (!ctx) {
         gfxCriticalNote << "BasicLayerManager context problem in PushGroupForLayer " << gfx::hexa(dt);
         return false;
       }
-      ctx->SetMatrix(oldMat);
+      ctx->SetMatrix(aContext->CurrentMatrix());
 
       aGroupResult.mGroupOffset = surfRect.TopLeft();
       aGroupResult.mGroupTarget = ctx;
 
       aGroupResult.mMaskSurface = GetMaskForLayer(aLayer, &aGroupResult.mMaskTransform);
       return true;
     }
     aContext->Restore();
@@ -599,23 +596,18 @@ BasicLayerManager::EndTransactionInterna
     if (mRoot->GetMaskLayer()) {
       ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData, nullptr);
     }
   }
 
   if (mTarget && mRoot &&
       !(aFlags & END_NO_IMMEDIATE_REDRAW) &&
       !(aFlags & END_NO_COMPOSITE)) {
-    IntRect clipRect;
-
-    {
-      gfxContextMatrixAutoSaveRestore save(mTarget);
-      mTarget->SetMatrix(gfxMatrix());
-      clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
-    }
+    IntRect clipRect =
+      ToOutsideIntRect(mTarget->GetClipExtents(gfxContext::eDeviceSpace));
 
     if (IsRetained()) {
       nsIntRegion region;
       MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
       if (mUsingDefaultTarget && mDoubleBuffering != BufferMode::BUFFER_NONE) {
         ApplyDoubleBuffering(mRoot, clipRect);
       }
     }
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -590,27 +590,29 @@ gfxContext::PopClip()
 {
   MOZ_ASSERT(CurrentState().pushedClips.Length() > 0);
 
   CurrentState().pushedClips.RemoveElementAt(CurrentState().pushedClips.Length() - 1);
   mDT->PopClip();
 }
 
 gfxRect
-gfxContext::GetClipExtents()
+gfxContext::GetClipExtents(ClipExtentsSpace aSpace) const
 {
   Rect rect = GetAzureDeviceSpaceClipBounds();
 
   if (rect.width == 0 || rect.height == 0) {
     return gfxRect(0, 0, 0, 0);
   }
 
-  Matrix mat = mTransform;
-  mat.Invert();
-  rect = mat.TransformBounds(rect);
+  if (aSpace == eUserSpace) {
+    Matrix mat = mTransform;
+    mat.Invert();
+    rect = mat.TransformBounds(rect);
+  }
 
   return ThebesRect(rect);
 }
 
 bool
 gfxContext::ExportClip(ClipExporter& aExporter)
 {
   for (unsigned int i = 0; i < mStateStack.Length(); i++) {
@@ -811,32 +813,23 @@ gfxContext::Paint(gfxFloat alpha)
 }
 
 void
 gfxContext::PushGroupForBlendBack(gfxContentType content, Float aOpacity, SourceSurface* aMask, const Matrix& aMaskTransform)
 {
   mDT->PushLayer(content == gfxContentType::COLOR, aOpacity, aMask, aMaskTransform);
 }
 
-static gfxRect
-GetRoundOutDeviceClipExtents(gfxContext* aCtx)
-{
-  gfxContextMatrixAutoSaveRestore save(aCtx);
-  aCtx->SetMatrix(gfxMatrix());
-  gfxRect r = aCtx->GetClipExtents();
-  r.RoundOut();
-  return r;
-}
-
 void
 gfxContext::PushGroupAndCopyBackground(gfxContentType content, Float aOpacity, SourceSurface* aMask, const Matrix& aMaskTransform)
 {
   IntRect clipExtents;
   if (mDT->GetFormat() != SurfaceFormat::B8G8R8X8) {
-    gfxRect clipRect = GetRoundOutDeviceClipExtents(this);
+    gfxRect clipRect = GetClipExtents(gfxContext::eDeviceSpace);
+    clipRect.RoundOut();
     clipExtents = IntRect::Truncate(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
   }
   bool pushOpaqueWithCopiedBG = (mDT->GetFormat() == SurfaceFormat::B8G8R8X8 ||
                                  mDT->GetOpaqueRect().Contains(clipExtents)) &&
                                 !mDT->GetUserData(&sDontUseAsSourceKey);
 
   if (pushOpaqueWithCopiedBG) {
     mDT->PushLayer(true, aOpacity, aMask, aMaskTransform, IntRect(), true);
@@ -1057,23 +1050,23 @@ gfxContext::ChangeTransform(const Matrix
   }
 
   mTransform = aNewMatrix;
 
   mDT->SetTransform(GetDTTransform());
 }
 
 Rect
-gfxContext::GetAzureDeviceSpaceClipBounds()
+gfxContext::GetAzureDeviceSpaceClipBounds() const
 {
   Rect rect(CurrentState().deviceOffset.x, CurrentState().deviceOffset.y,
             Float(mDT->GetSize().width), Float(mDT->GetSize().height));
   for (unsigned int i = 0; i < mStateStack.Length(); i++) {
     for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
-      AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
+      const AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
       if (clip.path) {
         Rect bounds = clip.path->GetBounds(clip.transform);
         rect.IntersectRect(rect, bounds);
       } else {
         rect.IntersectRect(rect, clip.transform.TransformBounds(clip.rect));
       }
     }
   }
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -372,21 +372,26 @@ public:
      * Any current path will be destroyed by these functions!
      */
     void Clip(const Rect& rect);
     void Clip(const gfxRect& rect); // will clip to a rect
     void Clip(Path* aPath);
 
     void PopClip();
 
+    enum ClipExtentsSpace {
+        eUserSpace = 0,
+        eDeviceSpace = 1,
+    };
+
     /**
-     * This will return the current bounds of the clip region in user
-     * space.
+     * According to aSpace, this function will return the current bounds of
+     * the clip region in user space or device space.
      */
-    gfxRect GetClipExtents();
+    gfxRect GetClipExtents(ClipExtentsSpace aSpace = eUserSpace) const;
 
     /**
      * Returns true if the given rectangle is fully contained in the current clip.
      * This is conservative; it may return false even when the given rectangle is
      * fully contained by the current clip.
      */
     bool ClipContainsRect(const gfxRect& aRect);
 
@@ -514,17 +519,17 @@ private:
 
   // This ensures mPath contains a valid path (in user space!)
   void EnsurePath();
   // This ensures mPathBuilder contains a valid PathBuilder (in user space!)
   void EnsurePathBuilder();
   void FillAzure(const Pattern& aPattern, mozilla::gfx::Float aOpacity);
   CompositionOp GetOp();
   void ChangeTransform(const mozilla::gfx::Matrix &aNewMatrix, bool aUpdatePatternTransform = true);
-  Rect GetAzureDeviceSpaceClipBounds();
+  Rect GetAzureDeviceSpaceClipBounds() const;
   Matrix GetDeviceTransform() const;
   Matrix GetDTTransform() const;
 
   bool mPathIsRect;
   bool mTransformChanged;
   Matrix mPathTransform;
   Rect mRect;
   RefPtr<PathBuilder> mPathBuilder;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3831,29 +3831,24 @@ nsCSSFrameConstructor::FindInputData(Ele
     // display (in practice, none).
   };
 
   nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
   NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
 
   auto controlType = control->ControlType();
 
-  // Note that Android widgets don't have theming support and thus
-  // appearance:none is the same as any other appearance value.
-  // So this chunk doesn't apply there:
-#if !defined(MOZ_WIDGET_ANDROID)
   // radio and checkbox inputs with appearance:none should be constructed
   // by display type.  (Note that we're not checking that appearance is
   // not (respectively) NS_THEME_RADIO and NS_THEME_CHECKBOX.)
   if ((controlType == NS_FORM_INPUT_CHECKBOX ||
        controlType == NS_FORM_INPUT_RADIO) &&
       aStyleContext->StyleDisplay()->mAppearance == NS_THEME_NONE) {
     return nullptr;
   }
-#endif
 
   return FindDataByInt(controlType, aElement, aStyleContext,
                        sInputData, ArrayLength(sInputData));
 }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindObjectData(Element* aElement,
--- a/layout/forms/nsFormControlFrame.cpp
+++ b/layout/forms/nsFormControlFrame.cpp
@@ -39,78 +39,64 @@ NS_QUERYFRAME_HEAD(nsFormControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 
 /* virtual */ nscoord
 nsFormControlFrame::GetMinISize(gfxContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
-#if !defined(MOZ_WIDGET_ANDROID)
   result = StyleDisplay()->mAppearance == NS_THEME_NONE ? 0 : DefaultSize();
-#else
-  result = DefaultSize();
-#endif
   return result;
 }
 
 /* virtual */ nscoord
 nsFormControlFrame::GetPrefISize(gfxContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_PREF_WIDTH(this, result);
-#if !defined(MOZ_WIDGET_ANDROID)
   result = StyleDisplay()->mAppearance == NS_THEME_NONE ? 0 : DefaultSize();
-#else
-  result = DefaultSize();
-#endif
   return result;
 }
 
 /* virtual */
 LogicalSize
 nsFormControlFrame::ComputeAutoSize(gfxContext*         aRC,
                                     WritingMode         aWM,
                                     const LogicalSize&  aCBSize,
                                     nscoord             aAvailableISize,
                                     const LogicalSize&  aMargin,
                                     const LogicalSize&  aBorder,
                                     const LogicalSize&  aPadding,
                                     ComputeSizeFlags    aFlags)
 {
   LogicalSize size(aWM, 0, 0);
-#if !defined(MOZ_WIDGET_ANDROID)
   if (StyleDisplay()->mAppearance == NS_THEME_NONE) {
     return size;
   }
-#endif
+
   // Note: this call always set the BSize to NS_UNCONSTRAINEDSIZE.
   size = nsAtomicContainerFrame::ComputeAutoSize(aRC, aWM, aCBSize,
                                                  aAvailableISize, aMargin,
                                                  aBorder, aPadding, aFlags);
   size.BSize(aWM) = DefaultSize();
   return size;
 }
 
 nscoord
 nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const
 {
   NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
                "frame must not be dirty");
 
-// NOTE: on Android we use appearance:none by default for checkbox/radio,
-// so the different layout for appearance:none we have on other platforms
-// doesn't work there. *shrug*
-#if !defined(MOZ_WIDGET_ANDROID)
   // For appearance:none we use a standard CSS baseline, i.e. synthesized from
   // our margin-box.
   if (StyleDisplay()->mAppearance == NS_THEME_NONE) {
     return nsAtomicContainerFrame::GetLogicalBaseline(aWritingMode);
   }
-#endif
 
   // This is for compatibility with Chrome, Safari and Edge (Dec 2016).
   // Treat radio buttons and checkboxes as having an intrinsic baseline
   // at the block-end of the control (use the block-end content edge rather
   // than the margin edge).
   // For "inverted" lines (typically in writing-mode:vertical-lr), use the
   // block-start end instead.
   return aWritingMode.IsLineInverted()
--- a/layout/forms/nsGfxCheckboxControlFrame.cpp
+++ b/layout/forms/nsGfxCheckboxControlFrame.cpp
@@ -13,88 +13,25 @@
 #include "nsLayoutUtils.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsDisplayList.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
-#ifdef MOZ_WIDGET_ANDROID
-
-static void
-PaintCheckMark(nsIFrame* aFrame,
-               DrawTarget* aDrawTarget,
-               const nsRect& aDirtyRect,
-               nsPoint aPt)
-{
-  nsRect rect(aPt, aFrame->GetSize());
-  rect.Deflate(aFrame->GetUsedBorderAndPadding());
-
-  // Points come from the coordinates on a 7X7 unit box centered at 0,0
-  const int32_t checkPolygonX[] = { -3, -1,  3,  3, -1, -3 };
-  const int32_t checkPolygonY[] = { -1,  1, -3, -1,  3,  1 };
-  const int32_t checkNumPoints = sizeof(checkPolygonX) / sizeof(int32_t);
-  const int32_t checkSize      = 9; // 2 units of padding on either side
-                                    // of the 7x7 unit checkmark
-
-  // Scale the checkmark based on the smallest dimension
-  nscoord paintScale = std::min(rect.width, rect.height) / checkSize;
-  nsPoint paintCenter(rect.x + rect.width  / 2,
-                      rect.y + rect.height / 2);
-
-  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
-  nsPoint p = paintCenter + nsPoint(checkPolygonX[0] * paintScale,
-                                    checkPolygonY[0] * paintScale);
-
-  int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
-  builder->MoveTo(NSPointToPoint(p, appUnitsPerDevPixel));
-  for (int32_t polyIndex = 1; polyIndex < checkNumPoints; polyIndex++) {
-    p = paintCenter + nsPoint(checkPolygonX[polyIndex] * paintScale,
-                              checkPolygonY[polyIndex] * paintScale);
-    builder->LineTo(NSPointToPoint(p, appUnitsPerDevPixel));
-  }
-  RefPtr<Path> path = builder->Finish();
-  aDrawTarget->Fill(path,
-                    ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
-}
-
-static void
-PaintIndeterminateMark(nsIFrame* aFrame,
-                       DrawTarget* aDrawTarget,
-                       const nsRect& aDirtyRect,
-                       nsPoint aPt)
-{
-  int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
-
-  nsRect rect(aPt, aFrame->GetSize());
-  rect.Deflate(aFrame->GetUsedBorderAndPadding());
-  rect.y += (rect.height - rect.height/4) / 2;
-  rect.height /= 4;
-
-  Rect devPxRect = NSRectToSnappedRect(rect, appUnitsPerDevPixel, *aDrawTarget);
-
-  aDrawTarget->FillRect(
-    devPxRect, ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
-}
-
-#endif
-
-//------------------------------------------------------------
 nsIFrame*
 NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell,
                               nsStyleContext* aContext)
 {
   return new (aPresShell) nsGfxCheckboxControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGfxCheckboxControlFrame)
 
-
-//------------------------------------------------------------
 // Initialize GFX-rendered state
 nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame(nsStyleContext* aContext)
 : nsFormControlFrame(aContext, kClassID)
 {
 }
 
 nsGfxCheckboxControlFrame::~nsGfxCheckboxControlFrame()
 {
@@ -102,52 +39,8 @@ nsGfxCheckboxControlFrame::~nsGfxCheckbo
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsGfxCheckboxControlFrame::AccessibleType()
 {
   return a11y::eHTMLCheckboxType;
 }
 #endif
-
-//------------------------------------------------------------
-#ifdef MOZ_WIDGET_ANDROID
-
-void
-nsGfxCheckboxControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                            const nsDisplayListSet& aLists)
-{
-  nsFormControlFrame::BuildDisplayList(aBuilder, aLists);
-
-  // Get current checked state through content model.
-  if ((!IsChecked() && !IsIndeterminate()) || !IsVisibleForPainting(aBuilder))
-    return;   // we're not checked or not visible, nothing to paint.
-
-  if (IsThemed())
-    return; // No need to paint the checkmark. The theme will do it.
-
-  aLists.Content()->AppendNewToTop(new (aBuilder)
-    nsDisplayGeneric(aBuilder, this,
-                     IsIndeterminate()
-                     ? PaintIndeterminateMark : PaintCheckMark,
-                     "CheckedCheckbox",
-                     DisplayItemType::TYPE_CHECKED_CHECKBOX));
-}
-
-#endif
-//------------------------------------------------------------
-bool
-nsGfxCheckboxControlFrame::IsChecked()
-{
-  nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent));
-  bool retval = false;
-  elem->GetChecked(&retval);
-  return retval;
-}
-
-bool
-nsGfxCheckboxControlFrame::IsIndeterminate()
-{
-  nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent));
-  bool retval = false;
-  elem->GetIndeterminate(&retval);
-  return retval;
-}
--- a/layout/forms/nsGfxCheckboxControlFrame.h
+++ b/layout/forms/nsGfxCheckboxControlFrame.h
@@ -17,25 +17,15 @@ public:
   virtual ~nsGfxCheckboxControlFrame();
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("CheckboxControl"), aResult);
   }
 #endif
 
-#ifdef MOZ_WIDGET_ANDROID
-  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                const nsDisplayListSet& aLists) override;
-#endif
-
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
-
-protected:
-
-  bool IsChecked();
-  bool IsIndeterminate();
 };
 
 #endif
 
--- a/layout/forms/nsGfxRadioControlFrame.cpp
+++ b/layout/forms/nsGfxRadioControlFrame.cpp
@@ -35,62 +35,8 @@ nsGfxRadioControlFrame::~nsGfxRadioContr
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsGfxRadioControlFrame::AccessibleType()
 {
   return a11y::eHTMLRadioButtonType;
 }
 #endif
-
-#ifdef MOZ_WIDGET_ANDROID
-
-//--------------------------------------------------------------
-// Draw the dot for a non-native radio button in the checked state.
-static void
-PaintCheckedRadioButton(nsIFrame* aFrame,
-                        DrawTarget* aDrawTarget,
-                        const nsRect& aDirtyRect,
-                        nsPoint aPt)
-{
-  // The dot is an ellipse 2px on all sides smaller than the content-box,
-  // drawn in the foreground color.
-  nsRect rect(aPt, aFrame->GetSize());
-  rect.Deflate(aFrame->GetUsedBorderAndPadding());
-  rect.Deflate(nsPresContext::CSSPixelsToAppUnits(2),
-               nsPresContext::CSSPixelsToAppUnits(2));
-
-  Rect devPxRect =
-    ToRect(nsLayoutUtils::RectToGfxRect(rect,
-                                        aFrame->PresContext()->AppUnitsPerDevPixel()));
-
-  ColorPattern color(ToDeviceColor(aFrame->StyleColor()->mColor));
-
-  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
-  AppendEllipseToPath(builder, devPxRect.Center(), devPxRect.Size());
-  RefPtr<Path> ellipse = builder->Finish();
-  aDrawTarget->Fill(ellipse, color);
-}
-
-void
-nsGfxRadioControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                         const nsDisplayListSet& aLists)
-{
-  nsFormControlFrame::BuildDisplayList(aBuilder, aLists);
-
-  if (!IsVisibleForPainting(aBuilder))
-    return;
-
-  if (IsThemed())
-    return; // The theme will paint the check, if any.
-
-  bool checked = true;
-  GetCurrentCheckState(&checked); // Get check state from the content model
-  if (!checked)
-    return;
-
-  aLists.Content()->AppendNewToTop(new (aBuilder)
-    nsDisplayGeneric(aBuilder, this, PaintCheckedRadioButton,
-                     "CheckedRadioButton",
-                     DisplayItemType::TYPE_CHECKED_RADIOBUTTON));
-}
-
-#endif
--- a/layout/forms/nsGfxRadioControlFrame.h
+++ b/layout/forms/nsGfxRadioControlFrame.h
@@ -18,16 +18,11 @@ public:
   explicit nsGfxRadioControlFrame(nsStyleContext* aContext);
   ~nsGfxRadioControlFrame();
 
   NS_DECL_FRAMEARENA_HELPERS(nsGfxRadioControlFrame)
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
-
-#ifdef MOZ_WIDGET_ANDROID
-  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                const nsDisplayListSet& aLists) override;
-#endif
 };
 
 #endif
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -780,24 +780,18 @@ GenerateAndPushTextMask(nsIFrame* aFrame
 
     nsLayoutUtils::PaintFrame(aContext, aFrame,
                               nsRect(nsPoint(0, 0), aFrame->GetSize()),
                               NS_RGB(255, 255, 255),
                               nsDisplayListBuilderMode::PAINTING_SELECTION_BACKGROUND);
   }
 
   // Evaluate required surface size.
-  IntRect drawRect;
-  {
-    gfxContextMatrixAutoSaveRestore matRestore(sourceCtx);
-
-    sourceCtx->SetMatrix(gfxMatrix());
-    gfxRect clipRect = sourceCtx->GetClipExtents();
-    drawRect = RoundedOut(ToRect(clipRect));
-  }
+  IntRect drawRect =
+    RoundedOut(ToRect(sourceCtx->GetClipExtents(gfxContext::eDeviceSpace)));
 
   // Create a mask surface.
   RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
   RefPtr<DrawTarget> maskDT =
     sourceTarget->CreateSimilarDrawTarget(drawRect.Size(),
                                           SurfaceFormat::A8);
   if (!maskDT || !maskDT->IsValid()) {
     return false;
@@ -8597,21 +8591,19 @@ bool nsDisplaySVGEffects::ValidateSVGFra
   }
 
   return true;
 }
 
 static IntRect
 ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
 {
-  gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
-
   // Get the clip extents in device space.
-  aCtx.SetMatrix(gfxMatrix());
-  gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
+  gfxRect clippedFrameSurfaceRect =
+    aCtx.GetClipExtents(gfxContext::eDeviceSpace);
   clippedFrameSurfaceRect.RoundOut();
 
   IntRect result;
   ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
   return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
                                                                 : IntRect();
 }
 
@@ -8703,25 +8695,24 @@ ComputeMaskGeometry(PaintFramesParams& a
                                        appUnitsPerDevPixel,
                                        &clipState);
       currentMaskSurfaceRect = clipState.mDirtyRectInDevPx;
     }
 
     maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
   }
 
-  ctx.Save();
+  gfxContextAutoSaveRestore autoSR;
 
   if (!maskInUserSpace.IsEmpty()) {
+    autoSR.SetContext(&ctx);
     ctx.Clip(maskInUserSpace);
   }
 
   IntRect result = ComputeClipExtsInDeviceSpace(ctx);
-  ctx.Restore();
-
   aParams.maskRect = result;
 }
 
 nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayList* aList,
                              bool aHandleOpacity,
                              const ActiveScrolledRoot* aActiveScrolledRoot)
   : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity, aActiveScrolledRoot)
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -378,17 +378,17 @@ fuzzy-if(Android&&isDebugBuild,229,45) =
 fuzzy-if(Android&&isDebugBuild,229,45) == 315920-12a.html 315920-12-ref.html # bug 1342240
 fuzzy-if(Android&&isDebugBuild,229,45) == 315920-12b.html 315920-12-ref.html # bug 1342240
 fuzzy-if(Android&&isDebugBuild,229,45) == 315920-12c.html 315920-12-ref.html # bug 1342240
 fuzzy-if(Android&&isDebugBuild,229,45) == 315920-13a.html 315920-13-ref.html # bug 1342240
 fuzzy-if(Android&&isDebugBuild,229,45) == 315920-13b.html 315920-13-ref.html # bug 1342240
 == 315920-14.html 315920-14-ref.html
 == 315920-15.html 315920-15-ref.html
 == 315920-16.html 315920-16-ref.html
-== 315920-17.html 315920-17-ref.html
+fuzzy-if(Android,2,18) == 315920-17.html 315920-17-ref.html
 == 315920-18a.html 315920-18-ref.html
 == 315920-18b.html 315920-18-ref.html
 == 315920-18c.html 315920-18-ref.html
 == 315920-18d.html 315920-18-ref.html
 == 315920-18e.html 315920-18-ref.html
 == 315920-18f.html 315920-18-ref.html
 == 315920-18g.html 315920-18-ref.html
 == 315920-18h.html 315920-18-ref.html
@@ -651,20 +651,20 @@ fails-if(Android&&!asyncPan) == 371561-1
 == 372062-1.html 372062-1-ref.html
 == 372063-1.html 372063-1-ref.html
 == 372323-1.xhtml 372323-1-ref.xhtml
 == 372553-1.html 372553-1-ref.html
 == 372632-1.html 372632-1-ref.html
 == 372768-1.html 372768-1-ref.html
 == 373295-1.html 373295-1-ref.html
 == 373298-1.html 373298-1-ref.html
-fails-if(Android) == 373381-1.html 373381-1-ref.html
-fails-if(Android) fuzzy-if(skiaContent&&!Android,2,40) == 373381-2.html 373381-2-ref.html
-fails-if(Android) random-if(d2d) == 373381-3.html 373381-3-ref.html
-fails-if(Android) == 373381-4.html 373381-4-ref.html
+== 373381-1.html 373381-1-ref.html
+fuzzy-if(skiaContent&&!Android,2,40) == 373381-2.html 373381-2-ref.html
+random-if(d2d) == 373381-3.html 373381-3-ref.html
+== 373381-4.html 373381-4-ref.html
 == 373383-1.html 373383-1-ref.html
 == 373433-1.html 373433-1-ref.html
 == 373533-1.xhtml about:blank
 == 373533-2.xhtml about:blank
 == 373533-3.xhtml about:blank
 == 374038-1.xul 374038-1-ref.xul
 == 374038-2.xul 374038-2-ref.xul
 random-if(d2d) == 374719-1.xul 374719-1-ref.xul
@@ -1935,17 +1935,17 @@ skip-if(!Android) fails-if(Android) == 1
 == 1150021-1.xul 1150021-1-ref.xul
 == 1151145-1.html 1151145-1-ref.html
 == 1151306-1.html 1151306-1-ref.html
 == 1153845-1.html 1153845-1-ref.html
 == 1155828-1.html 1155828-1-ref.html
 fuzzy-if(skiaContent,7,84) fails-if(webrender) == 1156129-1.html 1156129-1-ref.html
 pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html
 fuzzy-if(Android,6,6) == 1169331-1.html 1169331-1-ref.html
-fuzzy(1,74) fails-if(gtkWidget&&!styloVsGecko) == 1174332-1.html 1174332-1-ref.html # bug 1312658
+fuzzy(1,74) fails-if(Android||(gtkWidget&&!styloVsGecko)) == 1174332-1.html 1174332-1-ref.html # bug 1312658
 == 1179078-1.html 1179078-1-ref.html
 == 1179288-1.html 1179288-1-ref.html
 == 1190635-1.html 1190635-1-ref.html
 == 1202512-1.html 1202512-1-ref.html
 fuzzy-if(skiaContent,1,1) == 1202512-2.html 1202512-2-ref.html
 != 1207326-1.html about:blank
 == 1209603-1.html 1209603-1-ref.html
 == 1209994-1.html 1209994-1-ref.html
--- a/layout/reftests/forms/input/checkbox/reftest.list
+++ b/layout/reftests/forms/input/checkbox/reftest.list
@@ -1,17 +1,17 @@
 == label-dynamic.html label-dynamic-ref.html
 == radio-stretched.html radio-stretched-ref.html # test for bug 464589
 != checked-native.html checked-native-notref.html
-fails-if(Android) == checked-appearance-none.html about:blank
-fails-if(Android) == unchecked-appearance-none.html about:blank
+== checked-appearance-none.html about:blank
+== unchecked-appearance-none.html about:blank
 != checked-native.html about:blank
 != checked-native-notref.html about:blank
-fails-if(Android) == indeterminate-checked.html about:blank
-fails-if(Android) == indeterminate-checked-notref.html about:blank
-fails-if(Android) == indeterminate-unchecked.html about:blank
+== indeterminate-checked.html about:blank
+== indeterminate-checked-notref.html about:blank
+== indeterminate-unchecked.html about:blank
 != indeterminate-native-checked.html indeterminate-native-checked-notref.html
 != indeterminate-native-unchecked.html indeterminate-native-unchecked-notref.html
 == indeterminate-selector.html indeterminate-selector-ref.html
 skip-if(!gtkWidget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html
-skip-if(Android) == checkbox-baseline.html checkbox-baseline-ref.html # skip-if(Android) because Android use appearance:none by default for checkbox/radio.
-skip-if(Android) == checkbox-radio-color.html checkbox-radio-color-ref.html # skip-if(Android) because Android use appearance:none by default for checkbox/radio.
-skip == checkbox-radio-auto-sized.html checkbox-radio-auto-sized-ref.html # Disabled until bug 1352238 is fixed.
+== checkbox-baseline.html checkbox-baseline-ref.html
+== checkbox-radio-color.html checkbox-radio-color-ref.html
+skip-if(OSX) == checkbox-radio-auto-sized.html checkbox-radio-auto-sized-ref.html
--- a/layout/reftests/forms/input/radio/reftest.list
+++ b/layout/reftests/forms/input/radio/reftest.list
@@ -1,7 +1,7 @@
 == label-dynamic.html label-dynamic-ref.html
 != checked-native.html checked-native-notref.html
-fails-if(Android) == checked-appearance-none.html about:blank
-fails-if(Android) == unchecked-appearance-none.html about:blank
+== checked-appearance-none.html about:blank
+== unchecked-appearance-none.html about:blank
 != checked-native.html about:blank
 != checked-native-notref.html about:blank
 skip-if(!gtkWidget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html
--- a/layout/reftests/webcomponents/reftest.list
+++ b/layout/reftests/webcomponents/reftest.list
@@ -8,12 +8,12 @@ pref(dom.webcomponents.enabled,true) fai
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == adjacent-insertion-points-1.html adjacent-insertion-points-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == adjacent-insertion-points-2.html adjacent-insertion-points-2-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == fallback-content-1.html fallback-content-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == remove-insertion-point-1.html remove-insertion-point-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == basic-shadow-element-1.html basic-shadow-element-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == nested-shadow-element-1.html nested-shadow-element-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == update-dist-node-descendants-1.html update-dist-node-descendants-1-ref.html
-pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == input-transition-1.html input-transition-1-ref.html
+pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) fuzzy-if(Android,2,7) == input-transition-1.html input-transition-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == dynamic-insertion-point-distribution-2.html dynamic-insertion-point-distribution-2-ref.html
 pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == remove-append-shadow-host-1.html remove-append-shadow-host-1-ref.html
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -56,16 +56,18 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_HasR
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
                    RawServoStyleSheetContentsBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_Clone, RawServoStyleSheetContentsStrong,
                    RawServoStyleSheetContentsBorrowed sheet,
                    const mozilla::ServoStyleSheet* reference_sheet);
 SERVO_BINDING_FUNC(Servo_StyleSheet_SizeOfIncludingThis, size_t,
                    mozilla::MallocSizeOf malloc_size_of,
                    RawServoStyleSheetContentsBorrowed sheet)
+SERVO_BINDING_FUNC(Servo_StyleSheet_GetSourceMapURL, void,
+                   RawServoStyleSheetContentsBorrowed sheet, nsAString* result)
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetOrigin, uint8_t,
                    RawServoStyleSheetContentsBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSet*, RawGeckoPresContextOwned pres_context)
 SERVO_BINDING_FUNC(Servo_StyleSet_RebuildCachedData, void,
                    RawServoStyleSetBorrowed set)
@@ -219,18 +221,19 @@ SERVO_BINDING_FUNC(Servo_Keyframe_SetSty
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_KeyframesRule_GetName, nsIAtom*,
                    RawServoKeyframesRuleBorrowed rule)
 // This method takes an addrefed nsIAtom.
 SERVO_BINDING_FUNC(Servo_KeyframesRule_SetName, void,
                    RawServoKeyframesRuleBorrowed rule, nsIAtom* name)
 SERVO_BINDING_FUNC(Servo_KeyframesRule_GetCount, uint32_t,
                    RawServoKeyframesRuleBorrowed rule)
-SERVO_BINDING_FUNC(Servo_KeyframesRule_GetKeyframe, RawServoKeyframeStrong,
-                   RawServoKeyframesRuleBorrowed rule, uint32_t index)
+SERVO_BINDING_FUNC(Servo_KeyframesRule_GetKeyframeAt, RawServoKeyframeStrong,
+                   RawServoKeyframesRuleBorrowed rule, uint32_t index,
+                   uint32_t* line, uint32_t* column)
 // Returns the index of the rule, max value of uint32_t if nothing found.
 SERVO_BINDING_FUNC(Servo_KeyframesRule_FindRule, uint32_t,
                    RawServoKeyframesRuleBorrowed rule, const nsACString* key)
 // Returns whether it successfully appends the rule.
 SERVO_BINDING_FUNC(Servo_KeyframesRule_AppendRule, bool,
                    RawServoKeyframesRuleBorrowed rule,
                    RawServoStyleSheetContentsBorrowed sheet,
                    const nsACString* css)
--- a/layout/style/ServoKeyframeRule.h
+++ b/layout/style/ServoKeyframeRule.h
@@ -13,18 +13,19 @@
 namespace mozilla {
 
 class ServoDeclarationBlock;
 class ServoKeyframeDeclaration;
 
 class ServoKeyframeRule final : public dom::CSSKeyframeRule
 {
 public:
-  explicit ServoKeyframeRule(already_AddRefed<RawServoKeyframe> aRaw)
-    : CSSKeyframeRule(0, 0)
+  ServoKeyframeRule(already_AddRefed<RawServoKeyframe> aRaw,
+                    uint32_t aLine, uint32_t aColumn)
+    : CSSKeyframeRule(aLine, aColumn)
     , mRaw(aRaw) {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoKeyframeRule,
                                            dom::CSSKeyframeRule)
 
   bool IsCCLeaf() const final;
 #ifdef DEBUG
--- a/layout/style/ServoKeyframesRule.cpp
+++ b/layout/style/ServoKeyframesRule.cpp
@@ -48,21 +48,25 @@ public:
       }
     }
   }
 
   ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
 
   ServoKeyframeRule* GetRule(uint32_t aIndex) {
     if (!mRules[aIndex]) {
-      ServoKeyframeRule* rule = new ServoKeyframeRule(
-        Servo_KeyframesRule_GetKeyframe(mRawRule, aIndex).Consume());
-      mRules.ReplaceObjectAt(rule, aIndex);
-      rule->SetStyleSheet(mStyleSheet);
-      rule->SetParentRule(mParentRule);
+      uint32_t line = 0, column = 0;
+      RefPtr<RawServoKeyframe> rule =
+        Servo_KeyframesRule_GetKeyframeAt(mRawRule, aIndex,
+                                          &line, &column).Consume();
+      ServoKeyframeRule* ruleObj =
+        new ServoKeyframeRule(rule.forget(), line, column);
+      mRules.ReplaceObjectAt(ruleObj, aIndex);
+      ruleObj->SetStyleSheet(mStyleSheet);
+      ruleObj->SetParentRule(mParentRule);
     }
     return static_cast<ServoKeyframeRule*>(mRules[aIndex]);
   }
 
   ServoKeyframeRule* IndexedGetter(uint32_t aIndex, bool& aFound) final
   {
     if (aIndex >= mRules.Length()) {
       aFound = false;
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -213,16 +213,20 @@ ServoStyleSheet::ParseSheet(css::Loader*
                                                       aInput.Length(),
                                                       mParsingMode,
                                                       extraData,
                                                       aLineNumber,
                                                       aCompatMode,
                                                       aReusableSheets)
                          .Consume();
 
+  nsString sourceMapURL;
+  Servo_StyleSheet_GetSourceMapURL(Inner()->mContents, &sourceMapURL);
+  SetSourceMapURLFromComment(sourceMapURL);
+
   Inner()->mURLData = extraData.forget();
   return NS_OK;
 }
 
 nsresult
 ServoStyleSheet::ReparseSheet(const nsAString& aInput)
 {
   if (!mInner->mComplete) {
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -255,16 +255,17 @@ StyleSheetInfo::StyleSheetInfo(StyleShee
   , mPrincipal(aCopy.mPrincipal)
   , mCORSMode(aCopy.mCORSMode)
   , mReferrerPolicy(aCopy.mReferrerPolicy)
   , mIntegrity(aCopy.mIntegrity)
   , mComplete(aCopy.mComplete)
   , mFirstChild()  // We don't rebuild the child because we're making a copy
                    // without children.
   , mSourceMapURL(aCopy.mSourceMapURL)
+  , mSourceMapURLFromComment(aCopy.mSourceMapURLFromComment)
 #ifdef DEBUG
   , mPrincipalSet(aCopy.mPrincipalSet)
 #endif
 {
   AddSheet(aPrimarySheet);
 }
 
 StyleSheetInfo::~StyleSheetInfo()
@@ -505,25 +506,35 @@ StyleSheet::GetCssRules(nsIPrincipal& aS
     return nullptr;
   }
   FORWARD_INTERNAL(GetCssRulesInternal, ())
 }
 
 void
 StyleSheet::GetSourceMapURL(nsAString& aSourceMapURL)
 {
-  aSourceMapURL = mInner->mSourceMapURL;
+  if (mInner->mSourceMapURL.IsEmpty()) {
+    aSourceMapURL = mInner->mSourceMapURLFromComment;
+  } else {
+    aSourceMapURL = mInner->mSourceMapURL;
+  }
 }
 
 void
 StyleSheet::SetSourceMapURL(const nsAString& aSourceMapURL)
 {
   mInner->mSourceMapURL = aSourceMapURL;
 }
 
+void
+StyleSheet::SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment)
+{
+  mInner->mSourceMapURLFromComment = aSourceMapURLFromComment;
+}
+
 css::Rule*
 StyleSheet::GetDOMOwnerRule() const
 {
   return mOwnerRule;
 }
 
 uint32_t
 StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -210,16 +210,17 @@ public:
   // GetOwnerNode is defined above.
   inline StyleSheet* GetParentStyleSheet() const;
   // The XPCOM GetTitle is fine for WebIDL.
   dom::MediaList* Media();
   bool Disabled() const { return mDisabled; }
   // The XPCOM SetDisabled is fine for WebIDL.
   void GetSourceMapURL(nsAString& aTitle);
   void SetSourceMapURL(const nsAString& aSourceMapURL);
+  void SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment);
 
   // WebIDL CSSStyleSheet API
   // Can't be inline because we can't include ImportRule here.  And can't be
   // called GetOwnerRule because that would be ambiguous with the ImportRule
   // version.
   css::Rule* GetDOMOwnerRule() const;
   dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal,
                                 ErrorResult& aRv);
--- a/layout/style/StyleSheetInfo.h
+++ b/layout/style/StyleSheetInfo.h
@@ -60,16 +60,21 @@ struct StyleSheetInfo
   // throughout its parent chain and things are good.
   RefPtr<StyleSheet>     mFirstChild;
   AutoTArray<StyleSheet*, 8> mSheets;
 
   // If a SourceMap or X-SourceMap response header is seen, this is
   // the value.  If both are seen, SourceMap is preferred.  If neither
   // is seen, this will be an empty string.
   nsString mSourceMapURL;
+  // This stores any source map URL that might have been seen in a
+  // comment in the style sheet.  This is separate from mSourceMapURL
+  // so that the value does not overwrite any value that might have
+  // come from a response header.
+  nsString mSourceMapURLFromComment;
 
 #ifdef DEBUG
   bool                   mPrincipalSet;
 #endif
 };
 
 } // namespace mozilla
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1641,16 +1641,18 @@ CSSParserImpl::ParseSheet(const nsAStrin
       ParseAtRule(AppendRuleToSheet, this, false);
       continue;
     }
     UngetToken();
     if (ParseRuleSet(AppendRuleToSheet, this)) {
       mSection = eCSSSection_General;
     }
   }
+
+  mSheet->SetSourceMapURLFromComment(scanner.GetSourceMapURL());
   ReleaseScanner();
 
   mParsingMode = css::eAuthorSheetFeatures;
   mIsChrome = false;
   mReusableSheets = nullptr;
 
   return NS_OK;
 }
--- a/layout/style/nsCSSPropertyIDSet.h
+++ b/layout/style/nsCSSPropertyIDSet.h
@@ -62,25 +62,54 @@ public:
             NS_ASSERTION(mProperties[i] == 0, aText);
         }
     }
 
     bool Equals(const nsCSSPropertyIDSet& aOther) const {
       return mozilla::PodEqual(mProperties, aOther.mProperties);
     }
 
+    bool IsEmpty() const {
+      for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
+          if (mProperties[i] != 0) {
+            return false;
+          }
+      }
+      return true;
+    }
+
     // Return a new nsCSSPropertyIDSet which is the inverse of this set.
     nsCSSPropertyIDSet Inverse() const {
       nsCSSPropertyIDSet result;
       for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
         result.mProperties[i] = ~mProperties[i];
       }
       return result;
     }
 
+    // Returns a new nsCSSPropertyIDSet with all properties that are both in
+    // this set and |aOther|.
+    nsCSSPropertyIDSet Intersect(const nsCSSPropertyIDSet& aOther) const {
+      nsCSSPropertyIDSet result;
+      for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
+        result.mProperties[i] = mProperties[i] & aOther.mProperties[i];
+      }
+      return result;
+    }
+
+    // Return a new nsCSSPropertyIDSet with all properties that are in either
+    // this set or |aOther| but not both.
+    nsCSSPropertyIDSet Xor(const nsCSSPropertyIDSet& aOther) const {
+      nsCSSPropertyIDSet result;
+      for (size_t i = 0; i < mozilla::ArrayLength(mProperties); ++i) {
+        result.mProperties[i] = mProperties[i] ^ aOther.mProperties[i];
+      }
+      return result;
+    }
+
 private:
     typedef unsigned long property_set_type;
 public:
     // number of bits in |property_set_type|.
     static const size_t kBitsInChunk = sizeof(property_set_type)*CHAR_BIT;
     // number of |property_set_type|s in the set
     static const size_t kChunkCount =
         (eCSSProperty_COUNT_no_shorthands + kBitsInChunk - 1) / kBitsInChunk;
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -543,42 +543,88 @@ nsCSSScanner::SkipWhitespace()
 }
 
 /**
  * Skip over one CSS comment starting at the current read position.
  */
 void
 nsCSSScanner::SkipComment()
 {
+  static const char sourceMappingURLDirective[] = "# sourceMappingURL=";
+
   MOZ_ASSERT(Peek() == '/' && Peek(1) == '*', "should not have been called");
   Advance(2);
+  // Look in each comment for a source map directive; using a simple
+  // state machine.  The states are:
+  // * sourceMapIndex >= 0 means that we're still looking for the
+  //   directive and expect the next character to be at that index of
+  //   sourceMappingURLDirective.
+  //   As a special case, when sourceMapIndex == 0, '@' is also recognized.
+  // * sourceMapIndex < 0 means that we don't need to look for the
+  //   directive any more -- whether it was found or not.
+  // * copying == true means that the directive was found and we're
+  //   copying characters into mSourceMapURL.  This stops at the first
+  //   whitespace, or at the end of the comment.
+  int sourceMapIndex = 0;
+  bool copying = false;
   for (;;) {
     int32_t ch = Peek();
     if (ch < 0) {
       if (mReporter)
         mReporter->ReportUnexpectedEOF("PECommentEOF");
       SetEOFCharacters(eEOFCharacters_Asterisk | eEOFCharacters_Slash);
       return;
     }
+    if (sourceMapIndex >= 0) {
+      if ((sourceMapIndex == 0 && ch == '@') || ch == sourceMappingURLDirective[sourceMapIndex]) {
+        ++sourceMapIndex;
+        if (sourceMappingURLDirective[sourceMapIndex] == '\0') {
+          sourceMapIndex = -1;
+          mSourceMapURL.Truncate();
+          copying = true;
+          Advance();
+          // Make sure we don't copy out the '=' by falling through.
+          continue;
+        }
+      } else {
+        // Did not see the directive.
+        sourceMapIndex = -1;
+      }
+    }
+
     if (ch == '*') {
       Advance();
       ch = Peek();
       if (ch < 0) {
+        // In this case, even if we saw a source map directive, leave
+        // the "*" out of it.
         if (mReporter)
           mReporter->ReportUnexpectedEOF("PECommentEOF");
         SetEOFCharacters(eEOFCharacters_Slash);
         return;
       }
       if (ch == '/') {
         Advance();
         return;
       }
+      if (copying) {
+        mSourceMapURL.Append('*');
+      }
     } else if (IsVertSpace(ch)) {
       AdvanceLine();
+      // Done with the directive, so stop copying.
+      copying = false;
+    } else if (IsWhitespace(ch)) {
+      Advance();
+      // Done with the directive, so stop copying.
+      copying = false;
     } else {
+      if (copying) {
+        mSourceMapURL.Append(ch);
+      }
       Advance();
     }
   }
 }
 
 /**
  * If there is a valid escape sequence starting at the current read
  * position, consume it, decode it, append the result to |aOutput|,
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -227,16 +227,19 @@ class nsCSSScanner {
   { return mTokenOffset - mTokenLineOffset; }
 
   uint32_t GetTokenOffset() const
   { return mTokenOffset; }
 
   uint32_t GetTokenEndOffset() const
   { return mOffset; }
 
+  const nsAString& GetSourceMapURL() const
+  { return mSourceMapURL; }
+
   // Get the text of the line containing the first character of
   // the most recently processed token.
   nsDependentSubstring GetCurrentLine() const;
 
   // Get the next token.  Return false on EOF.  aTokenResult is filled
   // in with the data for the token.  aSkip controls whether
   // whitespace and/or comment tokens are ever returned.
   bool Next(nsCSSToken& aTokenResult, nsCSSScannerExclude aSkip);
@@ -356,16 +359,18 @@ protected:
   uint32_t mRecordStartOffset;
   EOFCharacters mEOFCharacters;
 
   mozilla::css::ErrorReporter *mReporter;
 
   bool mRecording;
   bool mSeenBadToken;
   bool mSeenVariableReference;
+
+  nsString mSourceMapURL;
 };
 
 // Token for the grid-template-areas micro-syntax
 // http://dev.w3.org/csswg/css-grid/#propdef-grid-template-areas
 struct MOZ_STACK_CLASS nsCSSGridTemplateAreaToken {
   nsAutoString mName;  // Empty for a null cell, non-empty for a named cell
   bool isTrash;  // True for a trash token, mName is ignored in this case.
 };
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -28,22 +28,19 @@ nsDOMCSSDeclaration::~nsDOMCSSDeclaratio
 }
 
 /* virtual */ JSObject*
 nsDOMCSSDeclaration::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return dom::CSS2PropertiesBinding::Wrap(aCx, this, aGivenProto);
 }
 
-NS_INTERFACE_TABLE_HEAD(nsDOMCSSDeclaration)
-  NS_INTERFACE_TABLE(nsDOMCSSDeclaration,
-                     nsICSSDeclaration,
-                     nsIDOMCSSStyleDeclaration)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE
-NS_INTERFACE_MAP_END
+NS_IMPL_QUERY_INTERFACE(nsDOMCSSDeclaration,
+                        nsICSSDeclaration,
+                        nsIDOMCSSStyleDeclaration)
 
 NS_IMETHODIMP
 nsDOMCSSDeclaration::GetPropertyValue(const nsCSSPropertyID aPropID,
                                       nsAString& aValue)
 {
   NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
                   "Should never pass eCSSProperty_UNKNOWN around");
 
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -593,65 +593,16 @@ input[type="radio"]:disabled:hover,
 input[type="radio"]:disabled:hover:active,
 input[type="checkbox"]:disabled,
 input[type="checkbox"]:disabled:active,
 input[type="checkbox"]:disabled:hover,
 input[type="checkbox"]:disabled:hover:active {
   cursor: inherit;
 }
 
-%if defined(MOZ_WIDGET_ANDROID)
-/*
- * These platforms doesn't have any theming support and thus -moz-appearance:none
- * is the same as any other appearance value.
- * XXX This is not web-compatible and should be fixed.
- */
-input[type="radio"] {
-  border-radius: 100%;
-}
-
-input[type="checkbox"] {
-  border-radius: 0;
-}
-
-/* NOTE: The width, height, border-width, and padding here must all
-   add up the way nsFormControlFrame::GetIntrinsic(Width|Height)
-   expects them to, or they will not come out with total width equal
-   to total height on sites that set their 'width' or 'height' to 'auto'.
-   (Should we maybe set !important on width and height, then?)  */
-input[type="radio"],
-input[type="checkbox"] {
-  inline-size: 13px;
-  block-size: 13px;
-  color: -moz-FieldText;
-  border: 2px inset ThreeDLightShadow;
-  background-repeat: no-repeat;
-  background-position: center;
-}
-
-input[type="radio"]:disabled,
-input[type="radio"]:disabled:active,
-input[type="radio"]:disabled:hover,
-input[type="radio"]:disabled:hover:active,
-input[type="checkbox"]:disabled,
-input[type="checkbox"]:disabled:active,
-input[type="checkbox"]:disabled:hover,
-input[type="checkbox"]:disabled:hover:active {
-  padding: 1px;
-  border: 1px inset ThreeDShadow;
-}
-
-input[type="checkbox"]:hover:active,
-input[type="radio"]:hover:active {
-  background-color: ThreeDFace ! important;
-  border-style: inset !important;
-}
-
-%endif /* defined(MOZ_WIDGET_ANDROID) */
-
 % On Mac, the native theme takes care of this.
 % See nsNativeThemeCocoa::ThemeDrawsFocusForWidget.
 %ifndef XP_MACOSX
 input[type="checkbox"]:-moz-focusring,
 input[type="radio"]:-moz-focusring {
   /* Don't specify the outline-color, we should always use initial value. */
   outline: 1px dotted;
 }
--- a/layout/style/test/browser.ini
+++ b/layout/style/test/browser.ini
@@ -8,8 +8,9 @@ support-files =
   mapped2.css
   mapped2.css^headers^
   sourcemap_css.html
 
 [browser_bug453896.js]
 [browser_newtab_share_rule_processors.js]
 skip-if = stylo # Gecko-specific test
 [browser_sourcemap.js]
+[browser_sourcemap_comment.js]
new file mode 100644
--- /dev/null
+++ b/layout/style/test/browser_sourcemap_comment.js
@@ -0,0 +1,40 @@
+add_task(async function() {
+  // Test text and expected results.
+  let test_cases = [
+    ["/*# sourceMappingURL=here*/", "here"],
+    ["/*# sourceMappingURL=here  */", "here"],
+    ["/*@ sourceMappingURL=here*/", "here"],
+    ["/*@ sourceMappingURL=there*/ /*# sourceMappingURL=here*/", "here"],
+    ["/*# sourceMappingURL=here there  */", "here"],
+
+    ["/*# sourceMappingURL=  here  */", ""],
+    ["/*# sourceMappingURL=*/", ""],
+    ["/*# sourceMappingUR=here  */", ""],
+    ["/*! sourceMappingURL=here  */", ""],
+    ["/*# sourceMappingURL = here  */", ""],
+    ["/*   # sourceMappingURL=here   */", ""],
+  ];
+
+  let page = "<!DOCTYPE HTML>\n<html>\n<head>\n";
+  for (let i = 0; i < test_cases.length; ++i) {
+    page += `<style type="text/css"> #x${i} { color: red; }${test_cases[i][0]}</style>\n`;
+  }
+  page += "</head><body>some text</body></html>";
+
+  let uri = "data:text/html;base64," + btoa(page);
+  info(`URI is ${uri}`);
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: uri
+  }, async function(browser) {
+    await ContentTask.spawn(browser, test_cases, function* (tests) {
+      for (let i = 0; i < content.document.styleSheets.length; ++i) {
+        let sheet = content.document.styleSheets[i];
+
+        info(`Checking sheet #${i}`);
+        is(sheet.sourceMapURL, tests[i][1], `correct source map for sheet ${i}`);
+      }
+    });
+  });
+});
--- a/layout/style/test/mapped2.css
+++ b/layout/style/test/mapped2.css
@@ -1,3 +1,4 @@
 span {
   color: #f06;
 }
+//# sourceMappingURL: overridden-by-headers
--- a/layout/style/test/test_parser_diagnostics_unprintables.html
+++ b/layout/style/test/test_parser_diagnostics_unprintables.html
@@ -39,18 +39,17 @@ let patterns = [
   // _Dimension
   { i: "@namespace fnord 14<t>;",  o: "within @namespace: \u201814<i>\u2019" },
   // _AtKeyword
   { i: "x{@<t>: }",        o: "declaration but found \u2018@<i>\u2019." },
   // _String
   { i: "x{ '<t>'}" ,       o: isStylo ? 'declaration but found \u2018"<s>"\u2019.'
                                       : "declaration but found \u2018'<s>'\u2019." },
   // _Bad_String
-  // FIXME: temporarily disabled https://bugzilla.mozilla.org/show_bug.cgi?id=1396664
-  { i: "x{ '<t>\n}",       o: isStylo ? "declaration but found \u2018\"<bad string>\n\u2019."
+  { i: "x{ '<t>\n}",       o: isStylo ? 'declaration but found \u2018"<s>\u2019.'
                                       : "declaration but found \u2018'<s>\u2019." },
 ];
 
 // Stylo's CSS parser only reports the 'url(' token, not the actual bad URL.
 if (!isStylo) {
   patterns.push(
     // _URL
     { i: "x{ url('<t>')}",   o: "declaration but found \u2018url('<s>')\u2019." })
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -80,21 +80,18 @@ nsSVGClipPathFrame::ApplyClipPath(gfxCon
     aContext.Clip(Rect());
   }
 }
 
 already_AddRefed<DrawTarget>
 nsSVGClipPathFrame::CreateClipMask(gfxContext& aReferenceContext,
                                    IntPoint& aOffset)
 {
-  gfxContextMatrixAutoSaveRestore autoRestoreMatrix(&aReferenceContext);
-
-  aReferenceContext.SetMatrix(gfxMatrix());
-  gfxRect rect = aReferenceContext.GetClipExtents();
-  IntRect bounds = RoundedOut(ToRect(rect));
+  IntRect bounds =
+    RoundedOut(ToRect(aReferenceContext.GetClipExtents(gfxContext::eDeviceSpace)));
   if (bounds.IsEmpty()) {
     // We don't need to create a mask surface, all drawing is clipped anyway.
     return nullptr;
   }
 
   DrawTarget* referenceDT = aReferenceContext.GetDrawTarget();
   RefPtr<DrawTarget> maskDT =
     referenceDT->CreateSimilarDrawTarget(bounds.Size(), SurfaceFormat::A8);
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -58,18 +58,17 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(Ma
 
   gfxRect maskArea = GetMaskArea(aParams.maskedFrame);
   gfxContext* context = aParams.ctx;
   // Get the clip extents in device space:
   // Minimizing the mask surface extents (using both the current clip extents
   // and maskArea) is important for performance.
   context->Save();
   nsSVGUtils::SetClipRect(context, aParams.toUserSpace, maskArea);
-  context->SetMatrix(gfxMatrix());
-  gfxRect maskSurfaceRect = context->GetClipExtents();
+  gfxRect maskSurfaceRect = context->GetClipExtents(gfxContext::eDeviceSpace);
   maskSurfaceRect.RoundOut();
   context->Restore();
 
   bool resultOverflows;
   IntSize maskSurfaceSize =
     nsSVGUtils::ConvertToSurfaceSize(maskSurfaceRect.Size(), &resultOverflows);
 
   if (resultOverflows || maskSurfaceSize.IsEmpty()) {
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -634,18 +634,18 @@ private:
         overflowRect = overflowRect + mFrame->GetPosition();
       }
       mSourceCtx->Clip(NSRectToSnappedRect(overflowRect,
                                            mFrame->PresContext()->AppUnitsPerDevPixel(),
                                            *mSourceCtx->GetDrawTarget()));
     }
 
     // Get the clip extents in device space.
-    mSourceCtx->SetMatrix(gfxMatrix());
-    gfxRect clippedFrameSurfaceRect = mSourceCtx->GetClipExtents();
+    gfxRect clippedFrameSurfaceRect =
+      mSourceCtx->GetClipExtents(gfxContext::eDeviceSpace);
     clippedFrameSurfaceRect.RoundOut();
 
     IntRect result;
     ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
 
     return Factory::CheckSurfaceSize(result.Size()) ? result : IntRect();
   }
 
--- a/layout/tables/crashtests/crashtests.list
+++ b/layout/tables/crashtests/crashtests.list
@@ -112,17 +112,17 @@ load 444431-1.html
 load 444702-1.html
 load 448988-1.xhtml
 load 450311-1.html
 load 451170.html
 load 451355-1.html
 load 456041.html
 load 457115.html
 load 460637-1.xhtml
-asserts(1) load 460637-2.xhtml # bug 1389295
+load 460637-2.xhtml
 load 460637-3.xhtml
 load 462849.xhtml
 load 467141-1.html
 load 488388-1.html
 load 501870-1.html
 load 509562-1.xhtml
 load 512749-1.html
 load 513732-1.html
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -1486,18 +1486,18 @@ nsCellMap::AppendCell(nsTableCellMap&   
     if (!origData) ABORT1(origData);
     SetDataAt(aMap, *origData, aRowIndex, startColIndex);
   }
 
   if (aRebuildIfNecessary) {
     //the caller depends on the damageArea
     // The special case for zeroRowSpan is to adjust for the '2' in
     // GetRowSpanForNewCell.
-    uint32_t height = zeroRowSpan ? endRowIndex - aRowIndex  :
-                                    1 + endRowIndex - aRowIndex;
+    uint32_t height = std::min(zeroRowSpan ? rowSpan - 1 : rowSpan,
+                               GetRowCount() - aRowIndex);
     SetDamageArea(startColIndex, aRgFirstRowIndex + aRowIndex,
                   1 + endColIndex - startColIndex, height, aDamageArea);
   }
 
   if (!aCellFrame) {
     return origData;
   }
 
--- a/layout/xul/nsScrollbarFrame.cpp
+++ b/layout/xul/nsScrollbarFrame.cpp
@@ -164,25 +164,24 @@ nsresult
 nsScrollbarFrame::GetXULMargin(nsMargin& aMargin)
 {
   nsresult rv = NS_ERROR_FAILURE;
   aMargin.SizeTo(0,0,0,0);
 
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     nsPresContext* presContext = PresContext();
     nsITheme* theme = presContext->GetTheme();
-    if (theme) {
+    if (theme && theme->ThemeSupportsWidget(presContext, this, NS_THEME_SCROLLBAR)) {
       LayoutDeviceIntSize size;
       bool isOverridable;
       theme->GetMinimumWidgetSize(presContext, this, NS_THEME_SCROLLBAR, &size,
                                   &isOverridable);
       if (IsXULHorizontal()) {
         aMargin.top = -presContext->DevPixelsToAppUnits(size.height);
-      }
-      else {
+      } else {
         aMargin.left = -presContext->DevPixelsToAppUnits(size.width);
       }
       rv = NS_OK;
     }
   }
 
   if (NS_FAILED(rv)) {
     rv = nsBox::GetXULMargin(aMargin);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1979,16 +1979,21 @@ PeerConnectionImpl::RemoveOldRemoteTrack
 
   std::vector<RefPtr<JsepTrack>> removedTracks =
     mJsepSession->GetRemoteTracksRemoved();
 
   for (auto& removedTrack : removedTracks) {
     const std::string& streamId = removedTrack->GetStreamId();
     const std::string& trackId = removedTrack->GetTrackId();
 
+    if (removedTrack->GetMediaType() == SdpMediaSection::kApplication) {
+      // TODO do we need to notify content somehow here?
+      continue;
+    }
+
     RefPtr<RemoteSourceStreamInfo> info = mMedia->GetRemoteStreamById(streamId);
     if (!info) {
       MOZ_ASSERT(false, "A stream/track was removed that wasn't in PCMedia. "
                         "This is a bug.");
       continue;
     }
 
     mMedia->RemoveRemoteTrack(streamId, trackId);
deleted file mode 100644
index f1338d8031ce95bd4ee12befcf44868e3ce293dd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f1338d8031ce95bd4ee12befcf44868e3ce293dd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/mobile/android/app/src/main/res/layout/bookmark_folder_row.xml
+++ b/mobile/android/app/src/main/res/layout/bookmark_folder_row.xml
@@ -3,13 +3,9 @@
    - 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/. -->
 
 <org.mozilla.gecko.home.BookmarkFolderView xmlns:android="http://schemas.android.com/apk/res/android"
                                            style="@style/Widget.FolderView"
                                            android:layout_width="match_parent"
                                            android:layout_height="wrap_content"
                                            android:minHeight="@dimen/page_row_height"
-                                           android:paddingLeft="16dp"
-                                           android:paddingStart="16dp"
-                                           android:paddingRight="16dp"
-                                           android:paddingEnd="16dp"
                                            android:gravity="center_vertical" />
--- a/mobile/android/app/src/main/res/layout/tabs_panel_default.xml
+++ b/mobile/android/app/src/main/res/layout/tabs_panel_default.xml
@@ -32,18 +32,16 @@
                 android:src="@drawable/tabs_panel_nav_back"
                 android:contentDescription="@string/back"
                 android:background="@drawable/action_bar_button_inverse"/>
 
             <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_widget"
                                                     android:layout_width="wrap_content"
                                                     android:layout_height="match_parent"
                                                     android:tabStripEnabled="false"
-                                                    android:divider="@drawable/tab_indicator_divider"
-                                                    android:dividerPadding="@dimen/tab_panel_divider_vertical_padding"
                                                     android:layout="@layout/tabs_panel_indicator"/>
 
             <View android:layout_width="0dip"
                   android:layout_height="match_parent"
                   android:layout_weight="1.0"/>
 
             <ImageButton android:id="@+id/add_tab"
                          style="@style/UrlBar.ImageButton"
--- a/mobile/android/app/src/main/res/layout/two_line_folder_row.xml
+++ b/mobile/android/app/src/main/res/layout/two_line_folder_row.xml
@@ -1,51 +1,66 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:gecko="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
-       xmlns:gecko="http://schemas.android.com/apk/res-auto"
-       tools:context=".BrowserApp">
-
-    <ImageView android:id="@+id/icon"
-               android:src="@drawable/folder_closed"
-               android:layout_width="@dimen/favicon_small_size"
-               android:layout_height="@dimen/favicon_small_size"
-               android:scaleType="fitCenter" />
+       tools:context=".BrowserApp"
+       tools:layout_height="wrap_content"
+       tools:layout_width="match_parent"
+       tools:minHeight="@dimen/page_row_height"
+       tools:orientation="horizontal"
+       tools:parentTag="LinearLayout">
 
-    <LinearLayout android:layout_width="0dp"
-                  android:layout_height="wrap_content"
-                  android:layout_weight="1"
-                  android:layout_gravity="center_vertical"
-                  android:paddingLeft="16dp"
-                  android:paddingStart="16dp"
-                  android:paddingRight="16dp"
-                  android:paddingEnd="16dp"
-                  android:orientation="vertical">
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/favicon_small_size"
+        android:layout_height="@dimen/favicon_small_size"
+        android:layout_gravity="center"
+        android:layout_marginLeft="20dp"
+        android:layout_marginRight="20dp"
+        android:scaleType="fitCenter"
+        android:src="@drawable/folder_closed"/>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingEnd="@dimen/page_row_edge_padding"
+        android:paddingRight="@dimen/page_row_edge_padding">
 
         <org.mozilla.gecko.widget.FadedSingleColorTextView
-                android:id="@+id/title"
-                style="@style/Widget.TwoLinePageRow.Title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                gecko:fadeWidth="90dp"
-                tools:text="This is a long test title"/>
+            android:id="@+id/title"
+            style="@style/Widget.TwoLinePageRow.Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            gecko:fadeWidth="90dp"
+            tools:text="This is a long test title"/>
 
-        <org.mozilla.gecko.widget.FadedSingleColorTextView android:id="@+id/subtitle"
-                  style="@style/Widget.TwoLinePageRow.Url"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:visibility="gone"
-                  gecko:fadeWidth="90dp"
-                  tools:text="1 items"/>
+        <org.mozilla.gecko.widget.FadedSingleColorTextView
+            android:id="@+id/subtitle"
+            style="@style/Widget.TwoLinePageRow.Url"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            gecko:fadeWidth="90dp"
+            tools:text="1 items"/>
 
     </LinearLayout>
 
-    <ImageView android:id="@+id/indicator"
-               android:layout_width="wrap_content"
-               android:layout_height="wrap_content"
-               android:layout_gravity="center"
-               android:src="@drawable/arrow" />
+    <ImageView
+        android:id="@+id/indicator"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:layout_gravity="center"
+        android:scaleType="centerInside"
+        android:src="@drawable/arrow"/>
 
+    <View
+        android:id="@+id/padding_end"
+        android:layout_width="@dimen/page_row_edge_padding"
+        android:layout_height="1dp"/>
 </merge>
--- a/mobile/android/app/src/photon/res/layout/two_line_page_row.xml
+++ b/mobile/android/app/src/photon/res/layout/two_line_page_row.xml
@@ -35,17 +35,17 @@
             android:id="@+id/title"
             style="@style/Widget.TwoLinePageRow.Title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginBottom="2dp"
             android:background="@null"
             android:lineSpacingMultiplier="1.1"
             android:textColor="@color/two_line_page_row_title"
-            android:textSize="14sp"
+            android:textSize="15sp"
             gecko:fadeWidth="90dp"
             tools:text="This is a long test title"/>
 
         <org.mozilla.gecko.widget.FadedSingleColorTextView
             android:id="@+id/url"
             style="@style/Widget.TwoLinePageRow.Url"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -66,9 +66,13 @@
         android:id="@+id/status_icon_bookmark"
         android:layout_width="20dp"
         android:layout_height="20dp"
         android:layout_gravity="center"
         android:src="@drawable/star_blue"
         android:visibility="gone"
         tools:visibility="visible"/>
 
+    <View
+        android:id="@+id/padding_end"
+        android:layout_width="@dimen/page_row_edge_padding"
+        android:layout_height="1dp"/>
 </merge>
--- a/mobile/android/app/src/photon/res/values/dimens.xml
+++ b/mobile/android/app/src/photon/res/values/dimens.xml
@@ -42,20 +42,16 @@
     <!-- If you update one of these values, update the others. -->
     <dimen name="tablet_nav_button_width">48dp</dimen>
     <dimen name="tablet_nav_button_width_half">21dp</dimen>
     <dimen name="tablet_nav_button_width_plus_half">36dp</dimen>
 
     <dimen name="tablet_fwd_button_padding_start">4dp</dimen>
     <dimen name="tablet_fwd_button_padding_end">4dp</dimen>
 
-    <!-- This is the system default for the vertical padding for the divider of the TabWidget.
-         Used to mimic the divider padding on the tablet tabs panel back button. -->
-    <dimen name="tab_panel_divider_vertical_padding">12dp</dimen>
-
     <dimen name="tablet_tab_strip_height">48dp</dimen>
     <dimen name="tablet_tab_strip_item_width">178dp</dimen>
     <dimen name="tablet_tab_strip_item_height">40dp</dimen>
     <dimen name="tablet_tab_strip_fading_edge_size">15dp</dimen>
     <dimen name="tablet_tab_strip_item_margin">0dp</dimen>
     <dimen name="tablet_tab_strip_divider_width">1dp</dimen>
     <dimen name="tablet_tab_strip_divider_height">30dp</dimen>
     <dimen name="tablet_tab_strip_divider_padding_bottom">4dp</dimen>
--- a/mobile/android/app/src/photon/res/values/styles.xml
+++ b/mobile/android/app/src/photon/res/values/styles.xml
@@ -168,20 +168,16 @@
     </style>
 
     <style name="Widget.FolderView" parent="Widget.FolderTitle.OneLine">
         <item name="android:layout_height">@dimen/page_group_height</item>
         <item name="android:minHeight">@dimen/page_group_height</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">none</item>
         <item name="android:background">@color/about_page_header_grey</item>
-        <item name="android:paddingLeft">20dp</item>
-        <item name="android:paddingStart">20dp</item>
-        <item name="android:paddingRight">0dp</item>
-        <item name="android:paddingEnd">0dp</item>
         <item name="android:drawablePadding">20dp</item>
     </style>
 
     <style name="Widget.PanelItemView" />
 
     <style name="Widget.PanelItemView.Title">
         <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemTitle</item>
         <item name="android:maxLines">2</item>
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -73,31 +73,27 @@ import android.support.annotation.NonNul
 import android.support.annotation.WorkerThread;
 import android.support.design.widget.Snackbar;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
-import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.OrientationEventListener;
-import android.view.SurfaceView;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.Button;
-import android.widget.FrameLayout;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -908,16 +904,17 @@ public abstract class GeckoApp extends G
             }
         });
     }
 
     // Checks the necessary permissions before attempting to download and set the image as wallpaper.
     private void setImageAs(final String aSrc) {
         Permissions
                 .from(this)
+                .onBackgroundThread()
                 .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                 .andFallback(new Runnable() {
                     @Override
                     public void run() {
                         showSetImageResult(/* success */ false, R.string.set_image_path_fail, null);
                     }
                 })
                 .run(new Runnable() {
@@ -931,16 +928,19 @@ public abstract class GeckoApp extends G
 
     /**
      * Downloads the image given by <code>aSrc</code> synchronously and then displays the Chooser
      * activity to set the image as wallpaper.
      *
      * @param aSrc The URI to download the image from.
      */
     private void downloadImageForSetImage(final String aSrc) {
+        // Network access from the main thread can cause a StrictMode crash on release builds.
+        ThreadUtils.assertOnBackgroundThread();
+
         boolean isDataURI = aSrc.startsWith("data:");
         Bitmap image = null;
         InputStream is = null;
         ByteArrayOutputStream os = null;
         try {
             if (isDataURI) {
                 int dataStart = aSrc.indexOf(",");
                 byte[] buf = Base64.decode(aSrc.substring(dataStart + 1), Base64.DEFAULT);
--- a/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
@@ -65,18 +65,16 @@ public class TwoLinePageRow extends Them
     }
 
     public TwoLinePageRow(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         setGravity(Gravity.CENTER_VERTICAL);
 
         LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this);
-        // Merge layouts lose their padding, so set it dynamically.
-        ViewCompat.setPaddingRelative(this, 0, 0, (int) getResources().getDimension(R.dimen.page_row_edge_padding), 0);
 
         mTitle = (ThemedTextView) findViewById(R.id.title);
         mUrl = (ThemedTextView) findViewById(R.id.url);
         mStatusIcon = (ImageView) findViewById(R.id.status_icon_bookmark);
 
         mSwitchToTabIconId = NO_ICON;
         mShowIcons = true;
 
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/TopSitesPanelsPreference.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/TopSitesPanelsPreference.java
@@ -17,12 +17,11 @@ public class TopSitesPanelsPreference ex
 
     TopSitesPanelsPreference(Context context, CustomListCategory parentCategory, boolean isRemovable, int index, boolean animate) {
         super(context, parentCategory, isRemovable, index, animate);
     }
 
     @Override
     protected void configureDialogBuilder(AlertDialog.Builder builder) {
         final LayoutInflater inflater = LayoutInflater.from(getContext());
-        builder.setView(R.layout.preference_topsites_panel_dialog);
         builder.setView(inflater.inflate(R.layout.preference_topsites_panel_dialog, null));
     }
 }
\ No newline at end of file
--- a/mobile/android/base/java/org/mozilla/gecko/updater/UpdateService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/updater/UpdateService.java
@@ -17,17 +17,16 @@ import org.mozilla.gecko.util.ProxySelec
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import android.Manifest;
 import android.app.AlarmManager;
 import android.app.IntentService;
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
@@ -51,17 +50,16 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URI;
 import java.net.URL;
 import java.net.URLConnection;
 import java.security.MessageDigest;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
-import java.util.List;
 import java.util.TimeZone;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
 public class UpdateService extends IntentService {
     private static final int BUFSIZE = 8192;
     private static final int NOTIFICATION_ID = 0x3e40ddbd;
--- a/mobile/android/components/extensions/ext-pageAction.js
+++ b/mobile/android/components/extensions/ext-pageAction.js
@@ -142,17 +142,18 @@ class PageAction extends EventEmitter {
     return this.tabContext.get(tab.id)[prop] || this.defaults[prop];
   }
 
   /**
    * Show the page action for the active tab.
    * @returns {Promise} resolves when the page action is shown.
    */
   show() {
-    if (this.id) {
+    // The PageAction icon has been created or it is being converted.
+    if (this.id || this.shouldShow) {
       return Promise.resolve();
     }
 
     if (this.options.icon) {
       this.id = PageActions.add(this.options);
       return Promise.resolve();
     }
 
@@ -172,16 +173,20 @@ class PageAction extends EventEmitter {
 
     let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
     return IconDetails.convertImageURLToDataURL(icon, contentWindow, browserWindow).then(dataURI => {
       if (this.shouldShow) {
         this.options.icon = dataURI;
         this.id = PageActions.add(this.options);
       }
     }).catch(() => {
+      // The "icon conversion" promise has been rejected, set `this.shouldShow` to `false`
+      // so that we will try again on the next `pageAction.show` call.
+      this.shouldShow = false;
+
       return Promise.reject({
         message: "Failed to load PageAction icon",
       });
     });
   }
 
   /**
    * Hides the page action for the active tab.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/permissions/PermissionBlock.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/permissions/PermissionBlock.java
@@ -15,16 +15,17 @@ import android.support.annotation.NonNul
  * Helper class to run code blocks depending on whether a user has granted or denied certain runtime permissions.
  */
 public class PermissionBlock {
     private final PermissionsHelper helper;
 
     private Context context;
     private String[] permissions;
     private boolean onUIThread;
+    private boolean onBackgroundThread;
     private Runnable onPermissionsGranted;
     private Runnable onPermissionsDenied;
     private boolean doNotPrompt;
 
     /* package-private */ PermissionBlock(Context context, PermissionsHelper helper) {
         this.context = context;
         this.helper = helper;
     }
@@ -41,17 +42,27 @@ public class PermissionBlock {
      * Execute all callbacks on the UI thread.
      */
     public PermissionBlock onUIThread() {
         this.onUIThread = true;
         return this;
     }
 
     /**
+     * Execute all callbacks on the background thread.
+     */
+    public PermissionBlock onBackgroundThread() {
+        this.onBackgroundThread = true;
+        return this;
+    }
+
+    /**
      * Do not prompt the user to accept the permission if it has not been granted yet.
+     * This also guarantees that the callback will run on the current thread if no callback
+     * thread has been explicitly specified.
      */
     public PermissionBlock doNotPrompt() {
         doNotPrompt = true;
         return this;
     }
 
     /**
      * If the condition is true then do not prompt the user to accept the permission if it has not
@@ -111,18 +122,24 @@ public class PermissionBlock {
         executeRunnable(onPermissionsDenied);
     }
 
     private void executeRunnable(Runnable runnable) {
         if (runnable == null) {
             return;
         }
 
-        if (onUIThread) {
+        if (onUIThread && onBackgroundThread) {
+            throw new IllegalStateException("Cannot run callback on more than one thread");
+        }
+
+        if (onUIThread && !ThreadUtils.isOnUiThread()) {
             ThreadUtils.postToUiThread(runnable);
+        } else if (onBackgroundThread && !ThreadUtils.isOnBackgroundThread()) {
+            ThreadUtils.postToBackgroundThread(runnable);
         } else {
             runnable.run();
         }
     }
 
     /* package-private */ String[] getPermissions() {
         return permissions;
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/permissions/Permissions.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/permissions/Permissions.java
@@ -7,21 +7,19 @@ package org.mozilla.gecko.permissions;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.support.annotation.NonNull;
 
 import org.mozilla.gecko.util.ThreadUtils;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
 
 /**
  * Convenience class for checking and prompting for runtime permissions.
@@ -31,18 +29,21 @@ import java.util.concurrent.FutureTask;
  *    Permissions.from(activity)
  *               .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
  *               .onUiThread()
  *               .andFallback(onPermissionDenied())
  *               .run(onPermissionGranted())
  *
  * This example will run the runnable returned by onPermissionGranted() if the WRITE_EXTERNAL_STORAGE permission is
  * already granted. Otherwise it will prompt the user and run the runnable returned by onPermissionGranted() or
- * onPermissionDenied() depending on whether the user accepted or not. If onUiThread() is specified then all callbacks
- * will be run on the UI thread.
+ * onPermissionDenied() depending on whether the user accepted or not.
+ * <p>
+ * If onUiThread()/onBackgroundThread() is specified, all callbacks will be run on the respective
+ * thread. Otherwise, the callback may run on the current thread, but will switch to the UI thread
+ * if a permissions prompt is required.
  */
 public class Permissions {
     private static final Queue<PermissionBlock> waiting = new LinkedList<>();
     private static final Queue<PermissionBlock> prompt = new LinkedList<>();
 
     private static PermissionsHelper permissionHelper = new PermissionsHelper();
 
     /**
--- a/mobile/android/modules/WebsiteMetadata.jsm
+++ b/mobile/android/modules/WebsiteMetadata.jsm
@@ -386,17 +386,17 @@ function knowledgebase() {
 function resultsOf(rule, node, flavor, kb) {
     // If more types of rule pop up someday, do fancier dispatching here.
     return rule.source.flavor === "flavor" ? resultsOfFlavorRule(rule, node, flavor) : resultsOfDomRule(rule, node, kb);
 }
 
 
 // Pull the DOM tree off the special property of the root "dom" fact, and query
 // against it.
-function *resultsOfDomRule(rule, specialDomNode, kb) {
+function* resultsOfDomRule(rule, specialDomNode, kb) {
     // Use the special "tree" property of the special starting node:
     const matches = specialDomNode.tree.querySelectorAll(rule.source.selector);
 
     for (let i = 0; i < matches.length; i++) {  // matches is a NodeList, which doesn't conform to iterator protocol
         const element = matches[i];
         const newFacts = explicitFacts(rule.ranker(kb.nodeForElement(element)));
         for (let fact of newFacts) {
             if (fact.element === undefined) {
@@ -406,17 +406,17 @@ function *resultsOfDomRule(rule, special
                 throw new Error("Rankers of dom() rules must return a flavor in each fact. Otherwise, there is no way for that fact to be used later.");
             }
             yield fact;
         }
     }
 }
 
 
-function *resultsOfFlavorRule(rule, node, flavor) {
+function* resultsOfFlavorRule(rule, node, flavor) {
     const newFacts = explicitFacts(rule.ranker(node));
 
     for (let fact of newFacts) {
         // If the ranker didn't specify a different element, assume it's
         // talking about the one we passed in:
         if (fact.element === undefined) {
             fact.element = node.element;
         }
@@ -428,17 +428,17 @@ function *resultsOfFlavorRule(rule, node
 }
 
 
 // Take the possibly abbreviated output of a ranker function, and make it
 // explicitly an iterable with a defined score.
 //
 // Rankers can return undefined, which means "no facts", a single fact, or an
 // array of facts.
-function *explicitFacts(rankerResult) {
+function* explicitFacts(rankerResult) {
     const array = (rankerResult === undefined) ? [] : (Array.isArray(rankerResult) ? rankerResult : [rankerResult]);
     for (let fact of array) {
         if (fact.score === undefined) {
             fact.score = 1;
         }
         yield fact;
     }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/permissions/TestPermissions.java
@@ -218,16 +218,30 @@ public class TestPermissions {
                 .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                 .doNotPromptIf(true)
                 .andFallback(mock(Runnable.class))
                 .run(mock(Runnable.class));
 
         verify(helper, never()).prompt(anyActivity(), any(String[].class));
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testCannotRunCallbackOnMultipleThreads() {
+        PermissionsHelper helper = mockDenyingHelper();
+        Permissions.setPermissionHelper(helper);
+
+        Permissions.from(mockActivity())
+                .onBackgroundThread()
+                .onUIThread()
+                .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                .doNotPromptIf(true)
+                .andFallback(mock(Runnable.class))
+                .run(mock(Runnable.class));
+    }
+
     private Activity mockActivity() {
         return mock(Activity.class);
     }
 
     private PermissionsHelper mockGrantingHelper() {
         PermissionsHelper helper = mock(PermissionsHelper.class);
         doReturn(true).when(helper).hasPermissions(any(Context.class), anyPermissions());
         return helper;
--- a/mobile/android/themes/geckoview/content.css
+++ b/mobile/android/themes/geckoview/content.css
@@ -93,17 +93,17 @@ select[size="1"] xul|scrollbarbutton {
   margin-left: 0;
   min-width: 16px;
 }
 
 /* Override inverse OS themes */
 textarea,
 button,
 xul|button,
-* > input:not([type="image"]) {
+* > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])) {
   -moz-appearance: none !important;  /* See bug 598421 for fixing the platform */
 }
 
 textarea,
 button,
 xul|button,
 * > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])) {
   border-radius: var(--form_border_radius);
@@ -133,37 +133,29 @@ select[size="1"],
 * > input[type="reset"],
 button {
   border-style: solid;
   border-color: var(--form_border);
   color: var(--form_text);
   background-color: var(--form_background);
 }
 
-input[type="checkbox"] {
-  background-color: var(--form_background);
-}
-
-input[type="radio"] {
-  background-color: var(--form_background)
-}
-
 select {
   border-width: 1px;
   padding: 1px;
   border-radius: var(--form_border_radius);
 }
 
 select:not([size]):not([multiple]),
 select[size="0"],
 select[size="1"] {
   padding: 0 1px 0 1px;
 }
 
-* > input:not([type="image"]) {
+* > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])) {
   border-width: 1px;
   padding: 1px;
 }
 
 textarea {
   resize: none;
   border-width: 1px;
   padding-inline-start: 1px;
@@ -178,25 +170,16 @@ input[type="reset"],
 button {
   border-width: 1px;
   padding-inline-start: 7px;
   padding-inline-end: 7px;
   padding-block-start: 0;
   padding-block-end: 0;
 }
 
-input[type="radio"],
-input[type="checkbox"] {
-  border: 1px solid var(--form_border) !important;
-  padding-inline-start: 1px;
-  padding-inline-end: 1px;
-  padding-block-start: 2px;
-  padding-block-end: 2px;
-}
-
 select > button {
   border-width: 0px !important;
   margin: 0px !important;
   padding: 0px !important;
   border-radius: 0;
   color: #414141;
 
   background-size: auto auto;
@@ -208,17 +191,17 @@ select > button {
   font-size: inherit;
 }
 
 select[size]:focus,
 select[multiple]:focus,
 select[size][multiple]:focus,
 textarea:focus,
 input[type="file"]:focus > input[type="text"],
-* > input:not([type="image"]):focus {
+* > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])):focus {
   outline: 0px !important;
   border-style: solid;
   border-color: var(--form_border);
   background-color: var(--form_background);
 }
 
 select:not([size]):not([multiple]):focus,
 select[size="0"]:focus,
@@ -228,41 +211,28 @@ input[type="submit"]:focus,
 input[type="reset"]:focus,
 button:focus {
   outline: 0px !important;
   border-style: solid;
   border-color: var(--form_border);
   background-color: var(--form_background);
 }
 
-input[type="checkbox"]:focus,
-input[type="radio"]:focus {
-  border-color: var(--form_border) !important;
-}
-
-input[type="checkbox"]:focus {
-  background-color: var(--form_background);
-}
-
-input[type="radio"]:focus {
-  background-color: var(--form_background);
-}
-
 /* we need to be specific for selects because the above rules are specific too */
 textarea:disabled,
 select[size]:disabled,
 select[multiple]:disabled,
 select[size][multiple]:disabled,
 select:not([size]):not([multiple]):disabled,
 select[size="0"]:disabled,
 select[size="1"]:disabled,
 button:disabled,
 button:disabled:active,
-* > input:not([type="image"]):disabled,
-* > input:not([type="image"]):disabled:active {
+* > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])):disabled,
+* > input:not(:-moz-any([type="image"], [type="checkbox"], [type="radio"])):disabled:active {
   color: var(--form_text_disabled);
   border-color: var(--form_border);
   border-style: solid;
   border-width: 1px;
   background-color: var(--form_background_disabled);
 }
 
 select:not([size]):not([multiple]):disabled,
@@ -281,27 +251,16 @@ button:disabled,
 button:disabled:active {
   padding-inline-start: 7px;
   padding-inline-end: 7px;
   padding-block-start: 0;
   padding-block-end: 0;
   background-color: var(--form_background_disabled);
 }
 
-input[type="radio"]:disabled,
-input[type="radio"]:disabled:active,
-input[type="radio"]:disabled:hover,
-input[type="radio"]:disabled:hover:active,
-input[type="checkbox"]:disabled,
-input[type="checkbox"]:disabled:active,
-input[type="checkbox"]:disabled:hover,
-input[type="checkbox"]:disabled:hover:active {
-  border:1px solid var(--form_border) !important;
-}
-
 select:disabled > button {
   opacity: 0.6;
   padding-inline-start: 7px;
   padding-inline-end: 7px;
   padding-block-start: 1px;
   padding-block-end: 1px;
 }
 
@@ -314,17 +273,17 @@ select:disabled > button {
 video:not([controls]) > xul|videocontrols {
   visibility: visible;
   -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#noControls");
 }
 
 *:any-link:active,
 *[role=button]:active,
 button:not(:disabled):active,
-input:not(:focus):not(:disabled):active,
+input:not(:-moz-any([type="checkbox"], [type="radio"])):not(:focus):not(:disabled):active,
 select:not(:disabled):active,
 textarea:not(:focus):not(:disabled):active,
 option:active,
 label:active,
 xul|menulist:active {
   background-color: var(--color_background_highlight_overlay);
 }
 
--- a/mobile/locales/searchplugins/diec2.xml
+++ b/mobile/locales/searchplugins/diec2.xml
@@ -1,13 +1,13 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>DIEC2</ShortName>
 <InputEncoding>ISO-8859-1</InputEncoding>
 <Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAe1BMVEX/AAAAAAD/CQn/AAD/AAD/AAD/AAD/AAD/Hh7/AAD/Hh7/Hh7/Hh7/AAD/////7u7/ERH/Hh7/m5v/hob/9vb/DAz/Kyv/6ur/19f/x8f/V1f/GBj/a2v/Pj7/8fH//Pz/ZWX/Ojr/6+v/2tr/y8v/kZH/fX3/dXX/S0skbqqmAAAADXRSTlPuAAbStWbnG/nPxW9s6wiaZQAAAOtJREFUaN7t2kkOwjAMBVCnbRoKpAO0Ze7AfP8TIiUsLFXdQL0A/b+J9KX4HcAmpQIdxSSQONKBUqRMYsWSGEVBaAUTBrS0otE0t6KJaObeKp88lRscU+HeezZ5bm4wvYF1OnlWAD4B2oylTF0aVjXDKvNVyat2FLjkLJ3/WbOq99OerCrOrnrwn9dRYGtZ9h44sKr2QM+qauOqzrLsvgVOQ+AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAQWBLJrbnEF3V/vMv8ZUBu5S5+NCB/9rCwotHypyfKCAqhUf78h0Tizn9eQ9P7dVgF1toAAAAASUVORK5CYII=</Image>
-<Url type="text/html" method="GET" template="http://mdlc.iec.cat/results.asp">
+<Url type="text/html" method="GET" template="https://mdlc.iec.cat/results.asp">
   <Param name="txtEntrada" value="{searchTerms}"/>
   <Param name="operEntrada" value="0"/>
 </Url>
-<SearchForm>http://mdlc.iec.cat</SearchForm>
+<SearchForm>https://mdlc.iec.cat</SearchForm>
 </SearchPlugin>
--- a/security/.eslintrc.js
+++ b/security/.eslintrc.js
@@ -12,19 +12,16 @@ module.exports = {
     "constructor-super": "error",
 
     // Require braces around blocks that start a new line
     "curly": ["error", "multi-line"],
 
     // Require default case in switch statements.
<