Merge mozilla-central to autoland. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Wed, 07 Nov 2018 00:03:28 +0200
changeset 444771 b8c47ee525017a9c3eaf283fafd4deec229584f3
parent 444770 634b4c2dad356201628394ca1e8f20ac14b9035a (current diff)
parent 444663 6e842238034cd847ede178b4e65ea07704e4ffe6 (diff)
child 444772 86f720f7f3a6becc39a71aa40430cbc45ff2ca58
push id109636
push userncsoregi@mozilla.com
push dateWed, 07 Nov 2018 10:00:15 +0000
treeherdermozilla-inbound@64e32a13c482 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.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 mozilla-central to autoland. a=merge
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/browser.xul
modules/libmar/src/mar_read.c
modules/libmar/src/moz.build
modules/libmar/tool/moz.build
other-licenses/nsis/Contrib/CityHash/cityhash/city.h
testing/web-platform/meta/workers/worker-performance.worker.js.ini
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -3,54 +3,21 @@
  * 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/. */
 
 var TabsInTitlebar = {
   init() {
     this._readPref();
     Services.prefs.addObserver(this._prefName, this);
 
-    // We need to update the appearance of the titlebar when the menu changes
-    // from the active to the inactive state. We can't, however, rely on
-    // DOMMenuBarInactive, because the menu fires this event and then removes
-    // the inactive attribute after an event-loop spin.
-    //
-    // Because updating the appearance involves sampling the heights and margins
-    // of various elements, it's important that the layout be more or less
-    // settled before updating the titlebar. So instead of listening to
-    // DOMMenuBarActive and DOMMenuBarInactive, we use a MutationObserver to
-    // watch the "invalid" attribute directly.
-    let menu = document.getElementById("toolbar-menubar");
-    this._menuObserver = new MutationObserver(this._onMenuMutate);
-    this._menuObserver.observe(menu, {attributes: true});
-
-    this.onAreaReset = function(aArea) {
-      if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR)
-        this.update();
-    };
-    this.onWidgetAdded = this.onWidgetRemoved = function(aWidgetId, aArea) {
-      if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR)
-        this.update();
-    };
-    CustomizableUI.addListener(this);
-
-    window.addEventListener("resolutionchange", this);
-    window.addEventListener("resize", this);
-
     gDragSpaceObserver.init();
-
     this._initialized = true;
     this.update();
   },
 
-  whenWindowLayoutReady() {
-    this._windowLayoutReady = true;
-    this.update();
-  },
-
   allowedBy(condition, allow) {
     if (allow) {
       if (condition in this._disallowed) {
         delete this._disallowed[condition];
         this.update();
       }
     } else if (!(condition in this._disallowed)) {
       this._disallowed[condition] = null;
@@ -77,64 +44,19 @@ var TabsInTitlebar = {
     return document.documentElement.getAttribute("tabsintitlebar") == "true";
   },
 
   observe(subject, topic, data) {
     if (topic == "nsPref:changed")
       this._readPref();
   },
 
-  handleEvent(aEvent) {
-    switch (aEvent.type) {
-      case "resolutionchange":
-        if (aEvent.target == window) {
-          this.update();
-        }
-        break;
-      case "resize":
-        if (window.fullScreen || aEvent.target != window) {
-           break;
-        }
-        // We use resize events because the window is not ready after
-        // sizemodechange events. However, we only care about the event when
-        // the sizemode is different from the last time we updated the
-        // appearance of the tabs in the titlebar.
-        let sizemode = document.documentElement.getAttribute("sizemode");
-        if (this._lastSizeMode == sizemode) {
-          break;
-        }
-        let oldSizeMode = this._lastSizeMode;
-        this._lastSizeMode = sizemode;
-        // Don't update right now if we are leaving fullscreen, since the UI is
-        // still changing in the consequent "fullscreen" event. Code there will
-        // call this function again when everything is ready.
-        // See browser-fullScreen.js: FullScreen.toggle and bug 1173768.
-        if (oldSizeMode == "fullscreen") {
-          break;
-        }
-        this.update();
-        break;
-    }
-  },
-
-  _onMenuMutate(aMutations) {
-    for (let mutation of aMutations) {
-      if (mutation.attributeName == "inactive" ||
-          mutation.attributeName == "autohide") {
-        TabsInTitlebar.update();
-        return;
-      }
-    }
-  },
-
   _initialized: false,
-  _windowLayoutReady: false,
   _disallowed: {},
   _prefName: "browser.tabs.drawInTitlebar",
-  _lastSizeMode: null,
 
   _readPref() {
     this.allowedBy("pref",
                    Services.prefs.getBoolPref(this._prefName));
   },
 
   update() {
     if (!this._initialized || window.fullScreen) {
@@ -154,158 +76,21 @@ var TabsInTitlebar = {
     } else {
       document.documentElement.removeAttribute("tabsintitlebar");
       document.documentElement.removeAttribute("chromemargin");
       if (AppConstants.platform == "macosx") {
         document.documentElement.setAttribute("drawtitle", "true");
       }
     }
 
-    this._layOutTitlebar(allowed);
-
     ToolbarIconColor.inferFromText("tabsintitlebar", allowed);
   },
 
-  _layOutTitlebar(drawInTitlebar) {
-    if (!this._windowLayoutReady) {
-      return;
-    }
-
-    let $ = id => document.getElementById(id);
-    let rect = ele => ele.getBoundingClientRect();
-    let verticalMargins = cstyle => parseFloat(cstyle.marginBottom) + parseFloat(cstyle.marginTop);
-
-    let titlebar = $("titlebar");
-    let menubar = $("toolbar-menubar");
-
-    if (!drawInTitlebar) {
-      if (AppConstants.platform == "macosx") {
-        let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
-        this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
-      }
-
-      // Reset styles that might have been modified:
-      titlebar.style.marginBottom = "";
-      menubar.style.paddingBottom = "";
-      return;
-    }
-
-    let titlebarContent = $("titlebar-content");
-    let titlebarButtons = $("titlebar-buttonbox");
-
-    // Reset the custom titlebar height if the menubar is shown,
-    // because we will want to calculate its original height.
-    let buttonsShouldMatchTabHeight =
-      AppConstants.isPlatformAndVersionAtLeast("win", "10.0") ||
-      AppConstants.platform == "linux";
-    if (buttonsShouldMatchTabHeight &&
-        (menubar.getAttribute("inactive") != "true" ||
-         menubar.getAttribute("autohide") != "true")) {
-      titlebarButtons.style.removeProperty("height");
-    }
-
-    // Try to avoid reflows in this code by calculating dimensions first and
-    // then later set the properties affecting layout together in a batch.
-
-    // Get the height of the tabs toolbar:
-    let fullTabsHeight = rect($("TabsToolbar")).height;
-
-    // Buttons first:
-    let captionButtonsBoxWidth = rect(titlebarButtons).width;
-
-    let secondaryButtonsWidth, menuHeight, fullMenuHeight, menuStyles;
-    if (AppConstants.platform == "macosx") {
-      secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
-      // No need to look up the menubar stuff on OS X:
-      menuHeight = 0;
-      fullMenuHeight = 0;
-    } else {
-      // Otherwise, get the height and margins separately for the menubar
-      menuHeight = rect(menubar).height;
-      menuStyles = window.getComputedStyle(menubar);
-      fullMenuHeight = verticalMargins(menuStyles) + menuHeight;
-    }
-
-    // And get the height of what's in the titlebar:
-    let titlebarContentHeight = rect(titlebarContent).height;
-
-    // Begin setting CSS properties which will cause a reflow
-
-    // Adjust the window controls to span the entire
-    // tab strip height if we're not showing a menu bar.
-    if (buttonsShouldMatchTabHeight && !menuHeight) {
-      titlebarContentHeight = fullTabsHeight;
-      titlebarButtons.style.height = titlebarContentHeight + "px";
-    }
-
-    // If the menubar is around (menuHeight is non-zero), try to adjust
-    // its full height (i.e. including margins) to match the titlebar,
-    // by changing the menubar's bottom padding
-    if (menuHeight) {
-      // Calculate the difference between the titlebar's height and that of the menubar
-      let menuTitlebarDelta = titlebarContentHeight - fullMenuHeight;
-      let paddingBottom;
-      // The titlebar is bigger:
-      if (menuTitlebarDelta > 0) {
-        fullMenuHeight += menuTitlebarDelta;
-        // If there is already padding on the menubar, we need to add that
-        // to the difference so the total padding is correct:
-        if ((paddingBottom = menuStyles.paddingBottom)) {
-          menuTitlebarDelta += parseFloat(paddingBottom);
-        }
-        menubar.style.paddingBottom = menuTitlebarDelta + "px";
-      // The menubar is bigger, but has bottom padding we can remove:
-      } else if (menuTitlebarDelta < 0 && (paddingBottom = menuStyles.paddingBottom)) {
-        let existingPadding = parseFloat(paddingBottom);
-        // menuTitlebarDelta is negative; work out what's left, but don't set negative padding:
-        let desiredPadding = Math.max(0, existingPadding + menuTitlebarDelta);
-        menubar.style.paddingBottom = desiredPadding + "px";
-        // We've changed the menu height now:
-        fullMenuHeight += desiredPadding - existingPadding;
-      }
-    }
-
-    // Next, we calculate how much we need to stretch the titlebar down to
-    // go all the way to the bottom of the tab strip, if necessary.
-    let tabAndMenuHeight = fullTabsHeight + fullMenuHeight;
-
-    if (tabAndMenuHeight > titlebarContentHeight) {
-      // We need to increase the titlebar content's outer height (ie including margins)
-      // to match the tab and menu height:
-      let extraMargin = tabAndMenuHeight - titlebarContentHeight;
-      if (AppConstants.platform != "macosx") {
-        titlebarContent.style.marginBottom = extraMargin + "px";
-      }
-
-      titlebarContentHeight += extraMargin;
-    } else {
-      titlebarContent.style.removeProperty("margin-bottom");
-    }
-
-    // Then add a negative margin to the titlebar, so that the following elements
-    // will overlap it by the greater of the titlebar height or the tabstrip+menu.
-    let maxTitlebarOrTabsHeight = Math.max(titlebarContentHeight, tabAndMenuHeight);
-    titlebar.style.marginBottom = "-" + maxTitlebarOrTabsHeight + "px";
-
-    // Finally, size the placeholders:
-    if (AppConstants.platform == "macosx") {
-      this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
-    }
-    this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
-  },
-
-  _sizePlaceholder(type, width) {
-    Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='" + type + "']"),
-                  function(node) { node.style.width = width + "px"; });
-  },
-
   uninit() {
     Services.prefs.removeObserver(this._prefName, this);
-    this._menuObserver.disconnect();
-    CustomizableUI.removeListener(this);
     gDragSpaceObserver.uninit();
   },
 };
 
 function onTitlebarMaxClick() {
   if (window.windowState == window.STATE_MAXIMIZED)
     window.restore();
   else
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -84,16 +84,17 @@ toolbar[customizable="true"] {
   height: 0 !important;
   -moz-appearance: none !important;
 }
 %endif
 
 %ifdef XP_MACOSX
 #toolbar-menubar {
   -moz-binding: none;
+  visibility: collapse;
 }
 %endif
 
 panelmultiview {
   -moz-box-align: start;
 }
 
 panelmultiview[transitioning] {
@@ -148,17 +149,17 @@ panelview[mainview] > .panel-header {
   }
 }
 
 
 #tabbrowser-tabs:not([overflow="true"]):not([hashiddentabs]) ~ #alltabs-button,
 #tabbrowser-tabs[hasadjacentnewtabbutton]:not([overflow="true"]) ~ #new-tab-button,
 #tabbrowser-tabs[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
 #tabbrowser-tabs:not([hasadjacentnewtabbutton]) > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
-#TabsToolbar[customizing="true"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+#TabsToolbar[customizing="true"] #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
   visibility: collapse;
 }
 
 #tabbrowser-tabs:not([overflow="true"])[using-closing-tabs-spacer] ~ #alltabs-button {
   visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
 }
 
 .tabbrowser-tab {
@@ -235,26 +236,26 @@ panelview[mainview] > .panel-header {
 }
 
 .tabbrowser-tab[tab-grouping][multiselected]:not([selected]) {
   z-index: 2;
 }
 
 /* The next 3 rules allow dragging tabs slightly outside of the tabstrip
  * to make it easier to drag tabs. */
-#TabsToolbar[movingtab] {
+#navigator-toolbox[movingtab] > #titlebar > #TabsToolbar {
   padding-bottom: 15px;
 }
 
-#TabsToolbar[movingtab] > #tabbrowser-tabs {
+#navigator-toolbox[movingtab] #tabbrowser-tabs {
   padding-bottom: 15px;
   margin-bottom: -15px;
 }
 
-#TabsToolbar[movingtab] + #nav-bar {
+#navigator-toolbox[movingtab] > #nav-bar {
   margin-top: -15px;
   pointer-events: none;
 }
 
 /* Allow dropping a tab on buttons with associated drop actions. */
 #TabsToolbar[movingtab] + #nav-bar > #nav-bar-customization-target > #personal-bookmarks,
 #TabsToolbar[movingtab] + #nav-bar > #nav-bar-customization-target > #home-button,
 #TabsToolbar[movingtab] + #nav-bar > #nav-bar-customization-target > #downloads-button,
@@ -281,69 +282,81 @@ window:not([chromehidden~="toolbar"]) #n
  */
 #widget-overflow-list:empty + #widget-overflow-fixed-separator,
 #widget-overflow:not([hasfixeditems]) #widget-overflow-fixed-separator {
   display: none;
 }
 
 
 %ifdef MENUBAR_CAN_AUTOHIDE
-#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-placeholder,
+#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-item,
+#toolbar-menubar:not([autohide=true]) + #TabsToolbar .titlebar-placeholder,
 %endif
 %ifndef MOZ_WIDGET_COCOA
 #main-window:not([sizemode=normal]) .titlebar-placeholder[type="pre-tabs"],
 %endif
-#main-window:not([chromemargin]) > #titlebar,
-#main-window[inFullscreen] > #titlebar,
+#main-window:not([chromemargin]) .titlebar-buttonbox-container,
+#main-window[inFullscreen] .titlebar-buttonbox-container,
 #main-window[inFullscreen] .titlebar-placeholder,
 #main-window:not([tabsintitlebar]) .titlebar-placeholder {
   display: none;
 }
 
+%ifdef MENUBAR_CAN_AUTOHIDE
+#toolbar-menubar[autohide=true]:not([inactive]) + #TabsToolbar > .titlebar-buttonbox-container {
+  visibility: hidden;
+}
+%endif
+
 #titlebar {
   -moz-window-dragging: drag;
 }
 
-#titlebar-spacer {
-  pointer-events: none;
-}
-
-#main-window[tabsintitlebar] #titlebar-buttonbox {
+#main-window[tabsintitlebar] .titlebar-buttonbox {
   position: relative;
 }
 
-#titlebar-buttonbox {
+#main-window:not([tabsintitlebar]) .titlebar-buttonbox {
+  display: none;
+}
+
+.titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box;
+  position: relative;
 }
 
 #personal-bookmarks {
   -moz-window-dragging: inherit;
 }
 
 toolbarpaletteitem {
   -moz-window-dragging: no-drag;
 }
 
+.titlebar-buttonbox-container {
+  -moz-box-ordinal-group: 1000;
+}
+
 %ifdef XP_MACOSX
 #titlebar-fullscreen-button {
   -moz-appearance: -moz-mac-fullscreen-button;
 }
 
-/* Fullscreen and caption buttons don't move with RTL on OS X so override the automatic ordering. */
-#titlebar-secondary-buttonbox:-moz-locale-dir(ltr),
-#titlebar-buttonbox-container:-moz-locale-dir(rtl),
-.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(ltr),
-.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(rtl) {
+/**
+ * On macOS, the window caption buttons are on the left side of the window titlebar,
+ * even when using the RTL UI direction. Similarly, the fullscreen button is on the
+ * right side of the window titlebar, even when using the RTL UI direction. These
+ * next rules enforce that ordering.
+ */
+#titlebar-secondary-buttonbox:-moz-locale-dir(ltr) {
   -moz-box-ordinal-group: 1000;
 }
 
 #titlebar-secondary-buttonbox:-moz-locale-dir(rtl),
-#titlebar-buttonbox-container:-moz-locale-dir(ltr),
-.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(ltr),
-.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(rtl) {
+.titlebar-buttonbox-container:-moz-locale-dir(ltr) {
   -moz-box-ordinal-group: 0;
 }
 %endif
 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1328,20 +1328,16 @@ var gBrowserInit = {
       if (uriToLoad == "about:home" || uriToLoad == "about:newtab" || uriToLoad == "about:welcome") {
         gBrowser.setIcon(gBrowser.selectedTab, "chrome://branding/content/icon32.png");
       } else if (uriToLoad == "about:privatebrowsing") {
         gBrowser.setIcon(gBrowser.selectedTab, "chrome://browser/skin/privatebrowsing/favicon.svg");
       }
     });
 
     this._setInitialFocus();
-
-    // Update the UI density before TabsInTitlebar lays out the titlbar.
-    gUIDensity.init();
-    TabsInTitlebar.whenWindowLayoutReady();
   },
 
   onLoad() {
     gBrowser.addEventListener("DOMUpdateBlockedPopups", gPopupBlockerObserver);
 
     Services.obs.addObserver(gPluginHandler.NPAPIPluginCrashed, "plugin-crashed");
 
     window.addEventListener("AppCommand", HandleAppCommandEvent, true);
@@ -1388,16 +1384,17 @@ var gBrowserInit = {
     Services.obs.notifyObservers(window, "browser-window-before-show");
 
     if (!window.toolbar.visible) {
       // adjust browser UI for popups
       gURLBar.setAttribute("readonly", "true");
     }
 
     // Misc. inits.
+    gUIDensity.init();
     TabletModeUpdater.init();
     CombinedStopReload.ensureInitialized();
     gPrivateBrowsingUI.init();
     BrowserSearch.init();
     BrowserPageActions.init();
     gAccessibilityServiceIndicator.init();
     AccessibilityRefreshBlocker.init();
 
@@ -5579,17 +5576,17 @@ function onViewToolbarsPopupShowing(aEve
   for (var i = popup.children.length - 1; i >= 0; --i) {
     var deadItem = popup.children[i];
     if (deadItem.hasAttribute("toolbarId"))
       popup.removeChild(deadItem);
   }
 
   var firstMenuItem = aInsertPoint || popup.firstElementChild;
 
-  let toolbarNodes = gNavToolbox.children;
+  let toolbarNodes = gNavToolbox.querySelectorAll("toolbar");
 
   for (let toolbar of toolbarNodes) {
     if (!toolbar.hasAttribute("toolbarname")) {
       continue;
     }
 
     let menuItem = document.createXULElement("menuitem");
     let hidingAttribute = toolbar.getAttribute("type") == "menubar" ?
@@ -5856,17 +5853,16 @@ var gUIDensity = {
       if (tree) {
         // Tree items don't update their styles without changing some property on the
         // parent tree element, like background-color or border. See bug 1407399.
         tree.style.border = "1px";
         tree.style.border = "";
       }
     }
 
-    TabsInTitlebar.update();
     gBrowser.tabContainer.uiDensityChanged();
   },
 };
 
 const nodeToTooltipMap = {
   "bookmarks-menu-button": "bookmarksMenuButton.tooltip",
   "context-reload": "reloadButton.tooltip",
   "context-stop": "stopButton.tooltip",
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -719,120 +719,108 @@ xmlns="http://www.w3.org/1999/xhtml"
                aria-live="off"
                flex="1"
                crop="end"/>
       </hbox>
     </hbox>
   </popupset>
   <box id="appMenu-viewCache" hidden="true"/>
 
-<vbox id="titlebar">
-  <hbox id="titlebar-content">
-    <spacer id="titlebar-spacer" flex="1"/>
-    <hbox id="titlebar-buttonbox-container">
-      <hbox id="titlebar-buttonbox" class="titlebar-color">
-        <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
-        <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
-        <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
-      </hbox>
-    </hbox>
-#ifdef XP_MACOSX
-    <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
-         buttonbox from reversing order in RTL by forcing an LTR direction. -->
-    <hbox id="titlebar-secondary-buttonbox" dir="ltr">
-      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
-      <hbox class="private-browsing-indicator"/>
-      <hbox id="titlebar-fullscreen-button"/>
-    </hbox>
+  <toolbox id="navigator-toolbox">
+
+    <vbox id="titlebar">
+      <!-- Menu -->
+      <toolbar type="menubar" id="toolbar-menubar"
+               class="browser-toolbar chromeclass-menubar titlebar-color"
+               customizable="true"
+               mode="icons"
+#ifdef MENUBAR_CAN_AUTOHIDE
+               toolbarname="&menubarCmd.label;"
+               accesskey="&menubarCmd.accesskey;"
+               autohide="true"
 #endif
-  </hbox>
-</vbox>
-
-  <toolbox id="navigator-toolbox">
-    <!-- Menu -->
-    <toolbar type="menubar" id="toolbar-menubar"
-             class="browser-toolbar chromeclass-menubar titlebar-color"
-             customizable="true"
-             mode="icons"
-#ifdef MENUBAR_CAN_AUTOHIDE
-             toolbarname="&menubarCmd.label;"
-             accesskey="&menubarCmd.accesskey;"
-             autohide="true"
-#endif
-             context="toolbar-context-menu">
-      <toolbaritem id="menubar-items" align="center">
+               context="toolbar-context-menu">
+        <toolbaritem id="menubar-items" align="center">
 # The entire main menubar is placed into browser-menubar.inc, so that it can be
 # shared with other top level windows in macWindow.inc.xul.
 #include browser-menubar.inc
-      </toolbaritem>
-
-#ifndef XP_MACOSX
-      <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"
-            skipintoolbarset="true"/>
-#endif
-    </toolbar>
+        </toolbaritem>
+        <spacer flex="1" />
+#include titlebar-items.inc.xul
+      </toolbar>
 
-    <toolbar id="TabsToolbar"
-             class="browser-toolbar titlebar-color"
-             fullscreentoolbar="true"
-             customizable="true"
-             mode="icons"
-             aria-label="&tabsToolbar.label;"
-             context="toolbar-context-menu">
-      <hbox class="titlebar-placeholder" type="pre-tabs"
-            skipintoolbarset="true"/>
+      <toolbar id="TabsToolbar"
+               class="browser-toolbar titlebar-color"
+               fullscreentoolbar="true"
+               customizable="true"
+               customizationtarget="TabsToolbar-customization-target"
+               mode="icons"
+               aria-label="&tabsToolbar.label;"
+               context="toolbar-context-menu"
+               flex="1">
+        <vbox flex="1" class="toolbar-items">
+          <spacer flex="1000"/>
 
-      <tabs id="tabbrowser-tabs"
-            flex="1"
-            setfocus="false"
-            tooltip="tabbrowser-tab-tooltip"
-            stopwatchid="FX_TAB_CLICK_MS">
-        <tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
-      </tabs>
+          <hbox id="TabsToolbar-customization-target" flex="1">
+            <hbox class="titlebar-placeholder" type="pre-tabs"
+                  skipintoolbarset="true"/>
+
+            <tabs id="tabbrowser-tabs"
+                  flex="1"
+                  setfocus="false"
+                  tooltip="tabbrowser-tab-tooltip"
+                  stopwatchid="FX_TAB_CLICK_MS">
+              <tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
+            </tabs>
 
-      <toolbarbutton id="new-tab-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&tabCmd.label;"
-                     command="cmd_newNavigatorTab"
-                     onclick="checkForMiddleClick(this, event);"
-                     tooltip="dynamic-shortcut-tooltip"
-                     ondrop="newTabButtonObserver.onDrop(event)"
-                     ondragover="newTabButtonObserver.onDragOver(event)"
-                     ondragenter="newTabButtonObserver.onDragOver(event)"
-                     ondragexit="newTabButtonObserver.onDragExit(event)"
-                     cui-areatype="toolbar"
-                     removable="true"/>
+            <toolbarbutton id="new-tab-button"
+                           class="toolbarbutton-1 chromeclass-toolbar-additional"
+                           label="&tabCmd.label;"
+                           command="cmd_newNavigatorTab"
+                           onclick="checkForMiddleClick(this, event);"
+                           tooltip="dynamic-shortcut-tooltip"
+                           ondrop="newTabButtonObserver.onDrop(event)"
+                           ondragover="newTabButtonObserver.onDragOver(event)"
+                           ondragenter="newTabButtonObserver.onDragOver(event)"
+                           ondragexit="newTabButtonObserver.onDragExit(event)"
+                           cui-areatype="toolbar"
+                           removable="true"/>
 
-      <toolbarbutton id="alltabs-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button badged-button"
-                     oncommand="gTabsPanel.showAllTabsPanel();"
-                     label="&listAllTabs.label;"
-                     tooltiptext="&listAllTabs.label;"
-                     removable="false"/>
-
-      <hbox class="titlebar-placeholder" type="post-tabs"
-            ordinal="1000"
-            skipintoolbarset="true"/>
+            <toolbarbutton id="alltabs-button"
+                           class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button badged-button"
+                           oncommand="gTabsPanel.showAllTabsPanel();"
+                           label="&listAllTabs.label;"
+                           tooltiptext="&listAllTabs.label;"
+                           removable="false"/>
 
-      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
-              ordinal="1000"
-              aria-live="polite" skipintoolbarset="true"/>
-      <hbox class="private-browsing-indicator" skipintoolbarset="true"
-            ordinal="1000"/>
-      <hbox class="titlebar-placeholder" type="caption-buttons"
-#ifndef XP_MACOSX
-            ordinal="1000"
-#endif
-            skipintoolbarset="true"/>
+            <hbox class="titlebar-placeholder" type="post-tabs"
+                  ordinal="1000"
+                  skipintoolbarset="true"/>
+          </hbox>
+        </vbox>
+
+        <button class="accessibility-indicator titlebar-item"  tooltiptext="&accessibilityIndicator.tooltip;"
+                ordinal="1000"
+                aria-live="polite" skipintoolbarset="true"/>
+        <hbox class="private-browsing-indicator titlebar-item" skipintoolbarset="true"
+              ordinal="1000"/>
+#include titlebar-items.inc.xul
 
 #ifdef XP_MACOSX
-      <hbox class="titlebar-placeholder" type="fullscreen-button"
-            skipintoolbarset="true"/>
+        <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
+             buttonbox from reversing order in RTL by forcing an LTR direction. -->
+        <hbox id="titlebar-secondary-buttonbox" dir="ltr">
+          <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
+          <hbox class="private-browsing-indicator"/>
+          <hbox id="titlebar-fullscreen-button"/>
+        </hbox>
 #endif
-    </toolbar>
+      </toolbar>
+
+    </vbox>
 
     <toolbar id="nav-bar"
              class="browser-toolbar"
              aria-label="&navbarCmd.label;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -5354,16 +5354,18 @@ var TabBarVisibility = {
     }
 
     if (collapse == toolbar.collapsed && this._initialUpdateDone) {
       return;
     }
     this._initialUpdateDone = true;
 
     toolbar.collapsed = collapse;
+    let navbar = document.getElementById("nav-bar");
+    navbar.setAttribute("tabs-hidden", collapse);
 
     document.getElementById("menu_closeWindow").hidden = collapse;
     document.getElementById("menu_close").setAttribute("label",
       gTabBrowserBundle.GetStringFromName(collapse ? "tabs.close" : "tabs.closeTab"));
 
     TabsInTitlebar.allowedBy("tabs-visible", !collapse);
   },
 };
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -585,17 +585,17 @@
       <method name="_animateTabMove">
         <parameter name="event"/>
         <body><![CDATA[
           let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
           let movingTabs = draggedTab._dragData.movingTabs;
 
           if (this.getAttribute("movingtab") != "true") {
             this.setAttribute("movingtab", "true");
-            this.parentNode.setAttribute("movingtab", "true");
+            gNavToolbox.setAttribute("movingtab", "true");
             if (!draggedTab.multiselected)
               this.selectedItem = draggedTab;
           }
 
           if (!("animLastScreenX" in draggedTab._dragData))
             draggedTab._dragData.animLastScreenX = draggedTab._dragData.screenX;
 
           let screenX = event.screenX;
@@ -712,17 +712,17 @@
             return;
           }
 
           for (let tab of this._getVisibleTabs()) {
             tab.style.transform = "";
           }
 
           this.removeAttribute("movingtab");
-          this.parentNode.removeAttribute("movingtab");
+          gNavToolbox.removeAttribute("movingtab");
 
           this._handleTabSelect();
         ]]></body>
       </method>
 
       <!--  Regroup all selected tabs around the
             tab in param  -->
       <method name="_groupSelectedTabs">
@@ -1138,17 +1138,17 @@
       </method>
 
       <method name="onWidgetAfterDOMChange">
         <parameter name="aNode"/>
         <parameter name="aNextNode"/>
         <parameter name="aContainer"/>
         <body><![CDATA[
           if (aContainer.ownerDocument == document &&
-              aContainer.id == "TabsToolbar") {
+              aContainer.id == "TabsToolbar-customization-target") {
             this._updateNewTabVisibility();
           }
         ]]></body>
       </method>
 
       <method name="onAreaNodeRegistered">
         <parameter name="aArea"/>
         <parameter name="aContainer"/>
--- a/browser/base/content/test/performance/browser_windowopen.js
+++ b/browser/base/content/test/performance/browser_windowopen.js
@@ -13,45 +13,16 @@
  * for tips on how to do that.
  */
 const EXPECTED_REFLOWS = [
   /**
    * Nothing here! Please don't add anything new!
    */
 ];
 
-if (Services.appinfo.OS == "WINNT") {
-  EXPECTED_REFLOWS.push(
-    {
-      stack: [
-        "verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
-        "_layOutTitlebar@chrome://browser/content/browser-tabsintitlebar.js",
-        "update@chrome://browser/content/browser-tabsintitlebar.js",
-        "whenWindowLayoutReady@chrome://browser/content/browser-tabsintitlebar.js",
-      ],
-      maxCount: 2, // This number should only ever go down - never up.
-    },
-  );
-}
-
-if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
-  EXPECTED_REFLOWS.push(
-    {
-      stack: [
-        "rect@chrome://browser/content/browser-tabsintitlebar.js",
-        "_layOutTitlebar@chrome://browser/content/browser-tabsintitlebar.js",
-        "update@chrome://browser/content/browser-tabsintitlebar.js",
-        "whenWindowLayoutReady@chrome://browser/content/browser-tabsintitlebar.js",
-      ],
-      // These numbers should only ever go down - never up.
-      maxCount: Services.appinfo.OS == "WINNT" ? 5 : 4,
-    },
-  );
-}
-
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows or flickering areas when opening new windows.
  */
 add_task(async function() {
   // Flushing all caches helps to ensure that we get consistent
   // behaviour when opening a new window, even if windows have been
   // opened in previous tests.
@@ -110,41 +81,16 @@ add_task(async function() {
     });
 
     await TestUtils.topicObserved("browser-delayed-startup-finished",
                                   subject => subject == win);
 
     await BrowserTestUtils.firstBrowserLoaded(win, false);
     await BrowserTestUtils.browserStopped(win.gBrowser.selectedBrowser, "about:home");
 
-    if (Services.appinfo.OS == "WINNT" && win.windowState == win.STATE_MAXIMIZED) {
-      // The reflows below are triggered by maximizing the window after
-      // layout. They should be fixed by bug 1447864.
-      EXPECTED_REFLOWS.push(
-        {
-          stack: [
-            "rect@chrome://browser/content/browser-tabsintitlebar.js",
-            "_layOutTitlebar@chrome://browser/content/browser-tabsintitlebar.js",
-            "update@chrome://browser/content/browser-tabsintitlebar.js",
-            "handleEvent@chrome://browser/content/browser-tabsintitlebar.js",
-          ],
-          maxCount: 4,
-        },
-        {
-          stack: [
-            "verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
-            "_layOutTitlebar@chrome://browser/content/browser-tabsintitlebar.js",
-            "update@chrome://browser/content/browser-tabsintitlebar.js",
-            "handleEvent@chrome://browser/content/browser-tabsintitlebar.js",
-          ],
-          maxCount: 2,
-        },
-      );
-    }
-
     await new Promise(resolve => {
       // 10 is an arbitrary value here, it needs to be at least 2 to avoid
       // races with code initializing itself using idle callbacks.
       (function waitForIdle(count = 10) {
         if (!count) {
           resolve();
           return;
         }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/titlebar-items.inc.xul
@@ -0,0 +1,11 @@
+# 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/.
+
+<hbox class="titlebar-buttonbox-container titlebar-item">
+  <hbox class="titlebar-buttonbox titlebar-color">
+    <toolbarbutton class="titlebar-button titlebar-min" oncommand="window.minimize();"/>
+    <toolbarbutton class="titlebar-button titlebar-max" oncommand="onTitlebarMaxClick();"/>
+    <toolbarbutton class="titlebar-button titlebar-close" command="cmd_closeWindow"/>
+  </hbox>
+</hbox>
--- a/browser/components/payments/paymentUIService.js
+++ b/browser/components/payments/paymentUIService.js
@@ -45,17 +45,17 @@ PaymentUIService.prototype = {
   DIALOG_URL: "chrome://payments/content/paymentDialogWrapper.xul",
   REQUEST_ID_PREFIX: "paymentRequest-",
 
   // nsIPaymentUIService implementation:
 
   showPayment(requestId) {
     this.log.debug("showPayment:", requestId);
     let request = paymentSrv.getPaymentRequestById(requestId);
-    let merchantBrowser = this.findBrowserByTabId(request.tabId);
+    let merchantBrowser = this.findBrowserByOuterWindowId(request.topOuterWindowId);
     let chromeWindow = merchantBrowser.ownerGlobal;
     let {gBrowser} = chromeWindow;
     let browserContainer = gBrowser.getBrowserContainer(merchantBrowser);
     let container = chromeWindow.document.createElementNS(XHTML_NS, "div");
     container.dataset.requestId = requestId;
     container.classList.add("paymentDialogContainer");
     container.hidden = true;
     let paymentsBrowser = chromeWindow.document.createElementNS(XHTML_NS, "iframe");
@@ -195,26 +195,24 @@ PaymentUIService.prototype = {
             browser: dialogContainer.parentElement.querySelector("browser"),
           };
         }
       }
     }
     return {};
   },
 
-  findBrowserByTabId(tabId) {
+  findBrowserByOuterWindowId(outerWindowId) {
     for (let win of BrowserWindowTracker.orderedWindows) {
-      for (let browser of win.gBrowser.browsers) {
-        if (!browser.frameLoader || !browser.frameLoader.tabParent) {
-          continue;
-        }
-        if (browser.frameLoader.tabParent.tabId == tabId) {
-          return browser;
-        }
+      let browser = win.gBrowser.getBrowserForOuterWindowID(outerWindowId);
+      if (!browser) {
+        continue;
       }
+      return browser;
     }
 
-    this.log.error("findBrowserByTabId: No browser found for tabId:", tabId);
+    this.log.error("findBrowserByOuterWindowId: No browser found for outerWindowId:",
+                   outerWindowId);
     return null;
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUIService]);
--- a/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
+++ b/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
@@ -10,42 +10,33 @@ https://trac.torproject.org/projects/tor
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/AddTask.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/1517">Tor Bug 1517</a>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1424341">Mozilla Bug 1424341</a>
 
-<!-- Canvas for testing 'currentTime' -->
-<canvas id="test-canvas" width="100" height="100"></canvas>
-
 <!-- The main testing script -->
 <script type="application/javascript">
   SimpleTest.requestFlakyTimeout("testing JS time-based fingerprinting");
 
   // Prepare for test of AudioContext.currentTime
   let audioContext = new AudioContext();
-  // Prepare for test of CanvasStream.currentTime
-  let canvas = document.getElementById("test-canvas");
-  let context = canvas.getContext("2d");
-  context.fillText("test", 20, 20);
-  let canvasStream = canvas.captureStream(25);
 
   // Known ways to generate time stamps, in milliseconds
   const timeStampCodes = [
     "performance.now()",
     "new Date().getTime()",
     "new Event(\"\").timeStamp",
     "new File([], \"\").lastModified",
   ];
   // These are measured in seconds, so we need to scale them up
   var timeStampCodesDOM = timeStampCodes.concat([
     "audioContext.currentTime * 1000",
-    "canvasStream.currentTime * 1000",
   ]);
 
   let isRounded = (x, expectedPrecision) => {
     let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
     // First we do the perfectly normal check that should work just fine
     if (rounded === x || x === 0)
       return true;
 
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -48,20 +48,16 @@
   --arrowpanel-dimmed-further: rgba(249,249,250,.15);
   --arrowpanel-dimmed-even-further: rgba(249,249,250,.2);
 }
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
-#main-menubar {
-  -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
-}
-
 #navigator-toolbox {
   -moz-appearance: none;
   background-color: transparent;
   border-top: none;
 }
 
 .browser-toolbar {
   padding: 0;
@@ -70,17 +66,17 @@
 .browser-toolbar:not(.titlebar-color) {
   background-color: var(--toolbar-bgcolor);
   background-image: var(--toolbar-bgimage);
   color: var(--toolbar-color);
   -moz-appearance: none;
   border-style: none;
 }
 
-#TabsToolbar:not([collapsed="true"]) + #nav-bar {
+#nav-bar:not([tabs-hidden="true"]) {
   box-shadow: 0 -@navbarTabsShadowSize@ 0 var(--tabs-border-color);
   /* This is needed for some toolbar button animations. Gross :( */
   position: relative;
 }
 
 #browser-bottombox {
   /* opaque for layers optimization */
   background-color: -moz-Dialog;
@@ -612,116 +608,102 @@ notification[value="translation"] menuli
   overflow: hidden;
 }
 
 .webextension-popup-browser,
 .webextension-popup-stack {
   border-radius: inherit;
 }
 
-/* Hide the titlebar explicitly on versions of GTK+ where
- * it's rendered by window manager. */
-@media (-moz-gtk-csd-available: 0) {
-  #titlebar {
-    display: none;
-  }
-}
-
 /* We draw to titlebar when Gkt+ CSD is available */
 @media (-moz-gtk-csd-available) {
   /* Some Gtk+ themes use non-rectangular toplevel windows. To fully support
    * such themes we need to make toplevel window transparent.
    * It may cause performanance issues so let's put it under a preference
    * and enable it for desktop environment which do that by default.
    * See nsWindow::TopLevelWindowUseARGBVisual() for details. */
   @media (-moz-gtk-csd-transparent-background) {
     :root[tabsintitlebar]:not(:-moz-lwtheme) {
       background-color: transparent;
       -moz-appearance: none;
     }
   }
 
-  :root[tabsintitlebar] > #titlebar:-moz-lwtheme {
-    visibility: hidden;
-  }
-  :root[tabsintitlebar] #titlebar-content:-moz-lwtheme {
-    visibility: visible;
-  }
-
-  :root[tabsintitlebar] > #titlebar {
+  :root[tabsintitlebar] > #navigator-toolbox > #titlebar:not(:-moz-lwtheme) {
     -moz-appearance: -moz-window-titlebar-maximized;
   }
-  :root[tabsintitlebar][sizemode="normal"] > #titlebar {
+  :root[tabsintitlebar][sizemode="normal"] > #navigator-toolbox > #titlebar:not(:-moz-lwtheme) {
     -moz-appearance: -moz-window-titlebar;
   }
 
   /* Add extra space to titlebar for dragging */
   :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar,
   :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar {
     padding-top: var(--space-above-tabbar);
   }
 
-  /* Private browsing and accessibility indicators */
-  :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .private-browsing-indicator,
-  :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .accessibility-indicator,
-  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .private-browsing-indicator,
-  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .accessibility-indicator {
-    padding-top: calc(-1 * var(--space-above-tabbar));
+  /**
+   * Titlebar items (window caption buttons, private browsing indicator,
+   * accessibility indicator, etc)
+   */
+  :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .titlebar-item,
+  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .titlebar-item {
+    margin-top: calc(-1 * var(--space-above-tabbar));
   }
 
   /* Make #TabsToolbar transparent as we style underlying #titlebar with
    * -moz-window-titlebar (Gtk+ theme).
    */
   :root[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) #TabsToolbar,
   :root[tabsintitlebar][sizemode="maximized"] #TabsToolbar,
   :root[tabsintitlebar] #toolbar-menubar {
     -moz-appearance: none;
   }
 
   /* The button box must appear on top of the navigator-toolbox in order for
    * click and hover mouse events to work properly for the button in the restored
    * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
    * can swallow those events.
    */
-  #titlebar-buttonbox {
+  .titlebar-buttonbox {
     z-index: 1;
     -moz-box-align: center;
   }
 
   /* Render titlebar command buttons according to system config.
    * Use full scale icons here as the Gtk+ does.
    */
   @media (-moz-gtk-csd-minimize-button) {
-    #titlebar-min {
+    .titlebar-min {
       -moz-appearance: -moz-window-button-minimize;
     }
   }
   @media (-moz-gtk-csd-minimize-button: 0) {
-    #titlebar-min {
+    .titlebar-min {
       display: none;
     }
   }
 
   @media (-moz-gtk-csd-maximize-button) {
-    #titlebar-max {
+    .titlebar-max {
       -moz-appearance: -moz-window-button-maximize;
     }
-    :root[sizemode="maximized"] #titlebar-max {
+    :root[sizemode="maximized"] .titlebar-max {
       -moz-appearance: -moz-window-button-restore;
     }
   }
   @media (-moz-gtk-csd-maximize-button: 0) {
-    #titlebar-max {
+    .titlebar-max {
       display: none;
     }
   }
 
   @media (-moz-gtk-csd-close-button) {
-    #titlebar-close {
+    .titlebar-close {
       -moz-appearance: -moz-window-button-close;
     }
   }
   @media (-moz-gtk-csd-close-button: 0) {
-    #titlebar-close {
+    .titlebar-close {
       display: none;
     }
   }
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -80,101 +80,84 @@
 
 /** Begin titlebar **/
 
 #titlebar {
   /* Centrally align content items vertically */
   -moz-box-pack: center;
 }
 
-#titlebar-content {
-  /* Ensure the the content part of the titlebar does not shrink. */
-  min-height: inherit;
-}
-
 #titlebar-buttonbox > .titlebar-button {
   display: none;
 }
 
 /* Making the toolbox position:relative (browser.inc.css) occludes titlebar indicators
  * if the toolbox has a background. Fix this by positioning the relevant elements, too: */
 #titlebar-secondary-buttonbox {
   position: relative;
   z-index: 1;
   /* Centrally align indicators and full screen button vertically */
   -moz-box-align: center;
 }
 
-#titlebar-buttonbox-container {
+.titlebar-buttonbox-container {
   -moz-box-align: center;
 }
 
 /* These would be margin-inline-start/end if it wasn't for the fact that OS X
  * doesn't reverse the order of the items in the titlebar in RTL mode. */
-.titlebar-placeholder[type="caption-buttons"],
-#titlebar-buttonbox {
+.titlebar-buttonbox {
   margin-left: 12px;
+  margin-top: calc(-1 * var(--space-above-tabbar));
 }
 
 /* The fullscreen button doesnt show on Yosemite(10.10) or above so dont give it a
    border there */
 @media (-moz-mac-yosemite-theme: 0) {
   .titlebar-placeholder[type="fullscreen-button"] {
     margin-right: 4px;
   }
 }
 
-#main-window:not([tabsintitlebar]) > #titlebar {
-  height: 22px; /* The native titlebar on OS X is 22px tall. */
-}
-
-/**
- * For tabs in titlebar on OS X, we stretch the titlebar down so that the
- * tabstrip can overlap it.
- */
-#main-window[tabsintitlebar] > #titlebar {
-  min-height: calc(var(--tab-min-height) + var(--space-above-tabbar));
-}
-
 /** End titlebar **/
 
 #main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
   border-top: 1px solid rgba(0,0,0,0.65);
 }
 
 .browser-toolbar:not(.titlebar-color) {
   -moz-appearance: none;
   background: var(--toolbar-bgcolor);
   color: var(--toolbar-color);
 }
 
 /* Draw the bottom border of the tabs toolbar when it's not using
    -moz-appearance: toolbar. */
-#main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
-#main-window:not([tabsintitlebar]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
-#TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-lwtheme {
+#main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #nav-bar:not([tabs-hidden="true"]),
+#main-window:not([tabsintitlebar]) #nav-bar:not([tabs-hidden="true"]),
+#nav-bar:not([tabs-hidden="true"]):-moz-lwtheme {
   box-shadow: 0 -@navbarTabsShadowSize@ 0 var(--tabs-border-color);
 }
 
 /* Always draw a border on Yosemite to ensure the border is well-defined there
  * (the default border is too light). */
 @media (-moz-mac-yosemite-theme) {
   #navigator-toolbox:not(:-moz-lwtheme) {
     --tabs-border-color: rgba(0,0,0,.2);
   }
   #navigator-toolbox:not(:-moz-lwtheme):-moz-window-inactive {
     --tabs-border-color: rgba(0,0,0,.05);
   }
 
-  #main-window[tabsintitlebar] #TabsToolbar:not([collapsed="true"]) + #nav-bar:not(:-moz-lwtheme) {
+  #main-window[tabsintitlebar] #nav-bar:not([tabs-hidden="true"]):not(:-moz-lwtheme) {
     box-shadow: 0 -@navbarTabsShadowSize@ 0 var(--tabs-border-color);
   }
 }
 
-#TabsToolbar:not([collapsed="true"]) + #nav-bar {
+#nav-bar:not([tabs-hidden="true"]) {
   /* The toolbar buttons that animate are only visible when the #TabsToolbar is not collapsed.
      The animations use position:absolute and require a positioned #nav-bar. */
   position: relative;
 }
 
 #PersonalToolbar:not(:-moz-lwtheme):-moz-window-inactive,
 #nav-bar:not(:-moz-lwtheme):-moz-window-inactive {
   background-color: -moz-mac-chrome-inactive;
@@ -638,24 +621,19 @@ html|input.urlbar-input {
 
 :-moz-any(.keyboard-focused-tab, .tabbrowser-tab:focus:not([aria-activedescendant])) > .tab-stack > .tab-content > .tab-label-container:not([pinned]),
 :-moz-any(.keyboard-focused-tab, .tabbrowser-tab:focus:not([aria-activedescendant])) > .tab-stack > .tab-content > .tab-icon-image[pinned],
 :-moz-any(.keyboard-focused-tab, .tabbrowser-tab:focus:not([aria-activedescendant])) > .tab-stack > .tab-content > .tab-throbber[pinned] {
   box-shadow: var(--focus-ring-box-shadow);
 }
 
 #TabsToolbar {
-  -moz-appearance: none;
   padding-top: var(--space-above-tabbar);
 }
 
-:root:not([customizing]):not([tabsintitlebar]):not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
-  -moz-appearance: toolbar;
-}
-
 #TabsToolbar:not(:-moz-lwtheme) {
   color: #333;
   text-shadow: @loweredShadow@;
 }
 
 :root:-moz-any([inFullscreen], [tabsintitlebar]) #TabsToolbar:not(:-moz-lwtheme) {
   -moz-appearance: -moz-mac-vibrant-titlebar-dark;
   -moz-font-smoothing-background-color: -moz-mac-vibrant-titlebar-dark;
@@ -956,20 +934,20 @@ html|*.addon-webext-perm-list {
 /* Customization mode */
 
 %include ../shared/customizableui/customizeMode.inc.css
 
 /* End customization mode */
 
 /* Private browsing and accessibility indicators */
 
-:root[accessibilitymode][tabsintitlebar]:not([inFullscreen]) > #navigator-toolbox > #TabsToolbar > .accessibility-indicator,
-:root[privatebrowsingmode=temporary][tabsintitlebar]:not([inFullscreen]) > #navigator-toolbox > #TabsToolbar > .private-browsing-indicator,
-:root[accessibilitymode]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .accessibility-indicator,
-:root[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
+:root[accessibilitymode][tabsintitlebar]:not([inFullscreen]) > #navigator-toolbox > #titlebar > #TabsToolbar > .accessibility-indicator,
+:root[privatebrowsingmode=temporary][tabsintitlebar]:not([inFullscreen]) > #navigator-toolbox > #titlebar > #TabsToolbar > .private-browsing-indicator,
+:root[accessibilitymode]:not([tabsintitlebar]) > #navigator-toolbox > #titlebar > #TabsToolbar > #titlebar-secondary-buttonbox > .accessibility-indicator,
+:root[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #navigator-toolbox > #titlebar > #TabsToolbar > #titlebar-secondary-buttonbox > .private-browsing-indicator {
   display: none;
 }
 
 #TabsToolbar > .private-browsing-indicator:-moz-locale-dir(rtl),
 #TabsToolbar > .accessibility-indicator:-moz-locale-dir(rtl) {
   -moz-box-ordinal-group: 0;
 }
 
--- a/browser/themes/osx/compacttheme.css
+++ b/browser/themes/osx/compacttheme.css
@@ -1,19 +1,14 @@
 % This Source Code Form is subject to the terms of the Mozilla Public
 % License, v. 2.0. If a copy of the MPL was not distributed with this
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 %include ../shared/compacttheme.inc.css
 
-/* Get rid of 1px bright strip at the top of window */
-#main-window[tabsintitlebar] #titlebar-content {
-  background: var(--lwt-accent-color);
-}
-
 #TabsToolbar:-moz-lwtheme-darktext {
   -moz-appearance: -moz-mac-vibrant-titlebar-light;
   -moz-font-smoothing-background-color: -moz-mac-vibrant-titlebar-light;
 }
 
 .tabbrowser-tab[visuallyselected=true] {
   -moz-font-smoothing-background-color: var(--toolbar-bgcolor);
 }
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -146,16 +146,17 @@
 }
 
 /* TRACKING PROTECTION ICON */
 
 #tracking-protection-icon-box {
   visibility: collapse;
   overflow: hidden;
   width: 20px;
+  height: 20px;
   margin-inline-end: -20px;
 }
 
 #tracking-protection-icon-box[active],
 #tracking-protection-icon-box[hasException] {
   margin-inline-end: 0px;
   visibility: visible;
 }
@@ -167,17 +168,16 @@
 #tracking-protection-icon-box:not([hasException])[active][animationsenabled] > #tracking-protection-icon,
 #tracking-protection-icon-box:not([animationsenabled]) > #tracking-protection-icon-animatable-box {
   display: none;
 }
 
 #tracking-protection-icon-box > #tracking-protection-icon-animatable-box {
   position: absolute;
   overflow: hidden;
-  top: calc(50% - 10px); /* half the height of the sprite */
   margin-inline-start: 4px;
   width: 16px;
   height: 20px;
 }
 
 #tracking-protection-icon-box:not([hasException])[active] #tracking-protection-icon-animatable-image {
   background-image: url(chrome://browser/skin/tracking-protection-animation.svg);
   transform: translateX(-1232px);
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -507,17 +507,17 @@
 #toolbar-menubar:not([autohide=true]) + #TabsToolbar,
 %endif
 :root:not([tabsintitlebar]),
 :root[extradragspace] {
   --tabs-top-border-width: 1px;
 }
 
 %ifdef MENUBAR_CAN_AUTOHIDE
-#toolbar-menubar:not([autohide=true]) + #TabsToolbar > #tabbrowser-tabs > .tabbrowser-tab > .tab-stack > .tab-background,
+#toolbar-menubar:not([autohide=true]) + #TabsToolbar .tabbrowser-tab > .tab-stack > .tab-background,
 %endif
 :root:not([tabsintitlebar]) .tab-background,
 :root[extradragspace] .tab-background {
   border-top-style: solid;
 }
 
 .tab-background[selected=true] {
   border-top-color: var(--tabs-border-color);
@@ -549,48 +549,48 @@
 }
 
 /* Tab hover */
 
 .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]) {
   background-color: rgba(0,0,0,.1);
 }
 
-#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]) {
+#TabsToolbar[brighttext] .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]) {
   background-color: rgba(255,255,255,.1);
 }
 
 .tab-line:not([selected=true]):not([multiselected]) {
   opacity: 0;
   transform: scaleX(0);
   transition: transform 250ms var(--animation-easing-function), opacity 250ms var(--animation-easing-function);
 }
 
 .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true]):not([multiselected]) {
   background-color: rgba(0,0,0,.2);
   opacity: 1;
   transform: none;
 }
 
-#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true]):not([multiselected]) {
+#TabsToolbar[brighttext] .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true]):not([multiselected]) {
   background-color: rgba(255,255,255,.2);
 }
 
 .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true])[multiselected],
-#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true])[multiselected] {
+#TabsToolbar[brighttext] .tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-line:not([selected=true])[multiselected] {
   opacity: 0.5;
 }
 
 /* Tab multi-selected */
 
 .tabbrowser-tab[multiselected] > .tab-stack > .tab-background:not([selected=true]) {
   background-color: rgba(0,0,0,.1);
 }
 
-#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab[multiselected] > .tab-stack > .tab-background:not([selected=true]) {
+#TabsToolbar[brighttext] .tabbrowser-tab[multiselected] > .tab-stack > .tab-background:not([selected=true]) {
   background-color: rgba(255,255,255,.1);
 }
 
 /* Pinned tabs */
 
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
 #tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::after {
   position: absolute;
@@ -663,17 +663,17 @@
  * may still resize very slightly) on some DPI settings with uneven
  * scaling factors on Windows, because of bug 477157.
  */
 .tabbrowser-tab::before {
   margin-inline-start: -1px;
 }
 
 %ifdef MENUBAR_CAN_AUTOHIDE
-:root[tabsintitlebar]:not([extradragspace]) #toolbar-menubar[autohide=true] + #TabsToolbar > #tabbrowser-tabs > .tabbrowser-tab::after,
+:root[tabsintitlebar]:not([extradragspace]) #toolbar-menubar[autohide=true] + #TabsToolbar .tabbrowser-tab::after,
 %else
 :root[tabsintitlebar]:not([extradragspace]) .tabbrowser-tab::after,
 %endif
 /* Show full height tab separators on hover and multiselection. */
 .tabbrowser-tab:hover::after,
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab[beforehovered]::after,
 .tabbrowser-tab[multiselected]::after,
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab[before-multiselected]::after {
@@ -712,18 +712,17 @@
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr) {
   transform: scaleX(-1);
 }
 
 /* New tab button */
 
 .tabs-newtab-button,
-#TabsToolbar > #new-tab-button ,
-#TabsToolbar > toolbarpaletteitem > #new-tab-button {
+#TabsToolbar #new-tab-button {
   list-style-image: url(chrome://browser/skin/add.svg);
 }
 
 /* All tabs button and menupopup */
 
 #alltabs-button {
   list-style-image: url(chrome://global/skin/icons/arrow-dropdown-16.svg);
 }
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -78,17 +78,17 @@ toolbar[brighttext] {
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-appearance: none;
   padding: 0 var(--toolbarbutton-inner-padding) !important;
 }
 
-#navigator-toolbox:not(:hover) > #TabsToolbar > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .scrollbutton-down:not([highlight]) {
+#navigator-toolbox:not(:hover) > #TabsToolbar .tabbrowser-arrowscrollbox > .scrollbutton-down:not([highlight]) {
   transition: 1s background-color ease-out;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[highlight] {
   background-color: Highlight;
 }
 
 .findbar-button {
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -3,19 +3,43 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %filter substitution
 %define glassActiveBorderColor rgb(37, 44, 51)
 %define glassInactiveBorderColor rgb(102, 102, 102)
 
 @media (-moz-os-version: windows-win7) {
   @media (-moz-windows-classic: 0) {
-    #main-window[sizemode="normal"] > #navigator-toolbox > #toolbar-menubar {
+    #main-window[sizemode="normal"] > #navigator-toolbox > #titlebar > #toolbar-menubar:not([autohide="true"]) > #menubar-items,
+    #main-window[sizemode="normal"] > #navigator-toolbox > #titlebar > #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .toolbar-items {
       margin-top: 1px;
     }
+    /**
+     * For all Windows configurations except for Windows Aero and
+     * Windows Aero Basic, the -moz-window-button-box appearance on
+     * the .titlebar-buttonbox adds an unwanted margin at the top of
+     * the button box.
+     *
+     * For Windows Aero:
+     *   We want the -moz-window-button-box applied in the restored case,
+     *   and -moz-window-button-box-maximized in the maximized case.
+     *
+     * For Windows Aero Basic:
+     *   The margin is also unwanted in the maximized case, but we want
+     *   it in the restored window case.
+     */
+    #main-window[sizemode="normal"] .titlebar-buttonbox {
+      -moz-appearance: -moz-window-button-box;
+    }
+
+    @media (-moz-windows-compositor) {
+      #main-window[sizemode="maximized"] .titlebar-buttonbox {
+        -moz-appearance: -moz-window-button-box-maximized;
+      }
+    }
   }
 }
 
 @media (-moz-windows-default-theme) {
   .menu-accel,
   .menu-iconic-accel {
     color: graytext;
   }
@@ -72,17 +96,17 @@
         /* On win10, if we don't set this on the entire browser container including
          * the sidebar, if the sidebar is open the accent color bleeds through in
          * the titlebar */
         #browser {
           -moz-appearance: -moz-win-exclude-glass;
         }
       }
 
-      #titlebar-buttonbox,
+      .titlebar-buttonbox,
       .titlebar-button {
         -moz-appearance: none !important;
       }
 
       .titlebar-button {
         border: none;
         margin: 0 !important;
         padding: 8px 17px;
@@ -90,45 +114,45 @@
         stroke: currentColor;
       }
 
       .titlebar-button > .toolbarbutton-icon {
         width: 12px;
         height: 12px;
       }
 
-      #titlebar-min {
+      .titlebar-min {
         list-style-image: url(chrome://browser/skin/window-controls/minimize.svg);
       }
 
-      #titlebar-max {
+      .titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/maximize.svg);
       }
 
-      :root[sizemode="maximized"] #titlebar-max {
+      :root[sizemode="maximized"] .titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
       }
 
-      #titlebar-close {
+      .titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close.svg);
       }
 
       :root[lwtheme-image] .titlebar-button {
         -moz-context-properties: unset;
       }
-      :root[lwtheme-image] #titlebar-min {
+      :root[lwtheme-image] .titlebar-min {
         list-style-image: url(chrome://browser/skin/window-controls/minimize-themes.svg);
       }
-      :root[lwtheme-image] #titlebar-max {
+      :root[lwtheme-image] .titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/maximize-themes.svg);
       }
-      :root[lwtheme-image][sizemode="maximized"] #titlebar-max {
+      :root[lwtheme-image][sizemode="maximized"] .titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore-themes.svg);
       }
-      :root[lwtheme-image] #titlebar-close {
+      :root[lwtheme-image] .titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close-themes.svg);
       }
 
       /* the 12px image renders a 10px icon, and the 10px upscaled gets rounded to 12.5, which
        * rounds up to 13px, which makes the icon one pixel too big on 1.25dppx. Fix: */
       @media (min-resolution: 1.20dppx) and (max-resolution: 1.45dppx) {
         .titlebar-button > .toolbarbutton-icon {
           width: 11.5px;
@@ -192,63 +216,63 @@
         .titlebar-button:-moz-lwtheme-darktext:hover:active {
           background-color: hsla(0,0%,0%,.22);
         }
 
         .titlebar-button:not(:hover) > .toolbarbutton-icon:-moz-window-inactive {
           opacity: 0.5;
         }
 
-        #titlebar-close:hover {
+        .titlebar-close:hover {
           stroke: white;
           background-color: hsl(355,86%,49%);
         }
 
-        #titlebar-close:hover:active {
+        .titlebar-close:hover:active {
           background-color: hsl(355,82%,69%);
         }
       }
 
       @media (-moz-windows-default-theme: 0) {
         .titlebar-button {
           background-color: -moz-field;
           stroke: ButtonText;
         }
         .titlebar-button:hover {
           background-color: Highlight;
           stroke: HighlightText;
         }
 
-        #titlebar-min {
+        .titlebar-min {
           list-style-image: url(chrome://browser/skin/window-controls/minimize-highcontrast.svg);
         }
 
-        #titlebar-max {
+        .titlebar-max {
           list-style-image: url(chrome://browser/skin/window-controls/maximize-highcontrast.svg);
         }
 
-        :root[sizemode="maximized"] #titlebar-max {
+        :root[sizemode="maximized"] .titlebar-max {
           list-style-image: url(chrome://browser/skin/window-controls/restore-highcontrast.svg);
         }
 
-        #titlebar-close {
+        .titlebar-close {
           list-style-image: url(chrome://browser/skin/window-controls/close-highcontrast.svg);
         }
       }
     }
   }
 
   @media (-moz-os-version: windows-win7),
          (-moz-os-version: windows-win8) {
     :root {
       background-color: transparent;
       -moz-appearance: -moz-win-borderless-glass;
     }
 
-    :root[sizemode="maximized"] #titlebar-buttonbox {
+    :root[sizemode="maximized"] .titlebar-buttonbox {
       margin-inline-end: 3px;
     }
 
     /* These should be hidden w/ glass enabled. Windows draws its own buttons. */
     .titlebar-button {
       display: none;
     }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -74,20 +74,16 @@
 #navigator-toolbox:-moz-lwtheme {
   --tabs-border-color: rgba(0,0,0,.3);
 }
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
-#main-menubar {
-  -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
-}
-
 #main-menubar > menu {
   -moz-appearance: none;
   color: inherit;
 }
 
 #main-menubar > menu[_moz-menuactive="true"] {
   background-color: -moz-menuhover;
   color: -moz-menuhovertext;
@@ -100,22 +96,16 @@
 @media (-moz-windows-default-theme) {
   @media not all and (-moz-os-version: windows-win7) {
     #toolbar-menubar:not(:-moz-lwtheme):-moz-window-inactive {
       color: ThreeDShadow;
     }
   }
 }
 
-/* Hides the titlebar-placeholder underneath the window caption buttons when we
-   are not autohiding the menubar. */
-#toolbar-menubar:not([autohide="true"]) + #TabsToolbar > .titlebar-placeholder[type="caption-buttons"] {
-  display: none;
-}
-
 :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar,
 :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar {
   padding-top: var(--space-above-tabbar);
 }
 
 /* Add 4px extra margin on top of the tabs toolbar on Windows 7. */
 @media (-moz-os-version: windows-win7) {
   :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar,
@@ -191,27 +181,16 @@
     color: CaptionText;
   }
 
   :root[tabsintitlebar]:not([inFullscreen]):not(:-moz-lwtheme):-moz-window-inactive {
     color: InactiveCaptionText;
   }
 }
 
-@media (-moz-windows-compositor: 0) {
-  #main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
-    visibility: hidden;
-  }
-
-  #main-window[tabsintitlebar] #titlebar-content:-moz-lwtheme {
-    visibility: visible;
-    -moz-window-dragging: drag;
-  }
-}
-
 /**
  * In the classic themes, the titlebar has a horizontal gradient, which is
  * problematic for reading the text of background tabs when they're in the
  * titlebar. We side-step this issue by layering our own background underneath
  * the tabs. Unfortunately, this requires a bunch of positioning in order to get
  * text and icons to not appear fuzzy.
  */
 @media (-moz-windows-classic) {
@@ -270,95 +249,118 @@
 
   /* End classic titlebar gradient */
 
   #main-window[tabsintitlebar]:not([inFullscreen]) :-moz-any(#TabsToolbar, #toolbar-menubar) toolbarbutton:not(:-moz-lwtheme) {
     color: inherit;
   }
 }
 
-#TabsToolbar:not([collapsed="true"]) + #nav-bar {
+#nav-bar:not([tabs-hidden="true"]) {
   /* This is needed for some toolbar button animations. Gross :( */
   position: relative;
 }
 
 #nav-bar {
   box-shadow: 0 -@navbarTabsShadowSize@ 0 var(--tabs-border-color);
 }
 @media (-moz-windows-compositor: 0) {
-  #TabsToolbar[collapsed="true"] + #nav-bar {
+  #nav-bar[tabs-hidden="true"] {
     box-shadow: none;
   }
 }
 
 #print-preview-toolbar:not(:-moz-lwtheme) {
   -moz-appearance: toolbox;
 }
 
 #browser-bottombox:not(:-moz-lwtheme) {
   background-color: -moz-dialog;
 }
 
 /* ::::: titlebar ::::: */
 
-#main-window[sizemode="normal"] > #titlebar {
+#main-window[tabsintitlebar][sizemode="normal"] > #navigator-toolbox > #titlebar {
   -moz-appearance: -moz-window-titlebar;
 }
 
-#main-window[sizemode="maximized"] > #titlebar {
+#main-window[tabsintitlebar][sizemode="maximized"] > #navigator-toolbox > #titlebar {
   -moz-appearance: -moz-window-titlebar-maximized;
 }
 
+@media (-moz-windows-compositor: 0) {
+  /**
+   * Anytime we're not using the compositor on Windows, the -moz-window-titlebar
+   * and -moz-window-titlebar-maximized values for -moz-appearance override
+   * backgrounds supplied by lwthemes. We make the #titlebar itself hidden, but
+   * it's children visible in order to hide the background but keep the margin and
+   * padding that comes from those -moz-window-titlebar rules.
+   */
+  #titlebar:-moz-lwtheme {
+    visibility: hidden;
+  }
+  #toolbar-menubar:-moz-lwtheme,
+  #TabsToolbar:-moz-lwtheme {
+    visibility: visible;
+  }
+}
+
 @media (-moz-windows-classic) {
-  #main-window[tabsintitlebar][sizemode="normal"] > #navigator-toolbox > #toolbar-menubar {
+  #main-window[tabsintitlebar][sizemode="normal"] > #navigator-toolbox > #titlebar > #toolbar-menubar {
     margin-top: 4px;
   }
 }
 
-/* The button box must appear on top of the navigator-toolbox in order for
- * click and hover mouse events to work properly for the button in the restored
- * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
- * can swallow those events. It will also place the buttons above the fog on
- * Windows 7 with Aero Glass.
- */
-#titlebar-buttonbox {
+.titlebar-buttonbox {
+  /* For all Windows configurations except for Windows Aero and Windows Aero Basic,
+   * the default -moz-appearance of -moz-window-button-box and
+   * -moz-window-button-box-maximized adds unwanted margins to the button box. We
+   * special case Windows Aero and Windows Aero Basic in browser-aero.css.
+   */
+  -moz-appearance: none;
+  /* The button box must appear on top of the navigator-toolbox in order for
+   * click and hover mouse events to work properly for the button in the restored
+   * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
+   * can swallow those events. It will also place the buttons above the fog on
+   * Windows 7 with Aero Glass.
+   */
   z-index: 1;
 }
 
-#titlebar-buttonbox-container {
-  -moz-box-align: center;
+.titlebar-buttonbox-container {
+  -moz-box-align: stretch;
 }
 
 @media (-moz-os-version: windows-win7) {
   /* Preserve window control buttons position at the top of the button box. */
-  #titlebar-buttonbox-container {
+  .titlebar-buttonbox-container {
     -moz-box-align: start;
   }
 }
 
 /* titlebar command buttons */
 
-#titlebar-min {
+.titlebar-min {
   -moz-appearance: -moz-window-button-minimize;
 }
 
-#titlebar-max {
+.titlebar-max {
   -moz-appearance: -moz-window-button-maximize;
 }
 
-#main-window[sizemode="maximized"] #titlebar-max {
+#main-window[sizemode="maximized"] .titlebar-max {
   -moz-appearance: -moz-window-button-restore;
 }
 
-#titlebar-close {
+.titlebar-close {
   -moz-appearance: -moz-window-button-close;
 }
 
 @media (-moz-windows-classic: 0) {
-  #titlebar-min {
+  .titlebar-min {
     margin-inline-end: 2px;
   }
 }
 
 /* ::::: bookmark menus ::::: */
 
 menu.bookmark-item,
 menuitem.bookmark-item {
@@ -941,31 +943,31 @@ notification[value="translation"] {
  * paint, so this hack is how we sidestep that performance bottleneck.
  */
 #main-window:-moz-any([customize-entering],[customize-exiting]) label {
   transform: perspective(0.01px);
 }
 
 /* End customization mode */
 
-/* Private browsing and accessibility indicators */
-
-:root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .private-browsing-indicator,
-:root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .accessibility-indicator,
-:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .private-browsing-indicator,
-:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .accessibility-indicator {
+/**
+ * Titlebar items (window caption buttons, private browsing indicator,
+ * accessibility indicator, etc)
+ */
+:root[sizemode="normal"][chromehidden~="menubar"] .titlebar-item,
+:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .titlebar-item,
+:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] > .titlebar-item {
   margin-top: calc(-1 * var(--space-above-tabbar));
 }
 
 /* Compensate for 4px extra margin on top of the tabs toolbar on Windows 7. */
 @media (-moz-os-version: windows-win7) {
-  :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .private-browsing-indicator,
-  :root[sizemode="normal"][chromehidden~="menubar"] #TabsToolbar > .accessibility-indicator,
-  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .private-browsing-indicator,
-  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .accessibility-indicator {
+  :root[sizemode="normal"][chromehidden~="menubar"] .titlebar-item,
+  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar > .titlebar-item,
+  :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] > .titlebar-item {
     margin-top: calc(-1 * (var(--space-above-tabbar) + 4px));
   }
 }
 
 :root:not([privatebrowsingmode=temporary]) .accessibility-indicator,
 .private-browsing-indicator {
   margin-inline-end: 12px;
 }
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -12,17 +12,17 @@
 }
 
 /* The window background is white due to no accentcolor in the lightweight
    theme. It can't be changed to transparent when there is no compositor
    (Win 7 in classic / basic theme), or else dragging and focus become
    broken. So instead just show the normal titlebar in that case, and override
    the window color as transparent when the compositor is available. */
 @media (-moz-windows-compositor: 0) {
-  #main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
+  #main-window[tabsintitlebar] > #navigator-toolbox > #titlebar:-moz-lwtheme {
     visibility: visible;
   }
 
   /* Prevent accent color overriding the window background for
    * light and dark theme on Aero Basic. This is copied from browser-aero.css. */
   @media (-moz-windows-default-theme) {
     #main-window {
       background-color: rgb(185,209,234) !important;
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -656,16 +656,17 @@ support-files =
 [browser_dbg-asm.js]
 [browser_dbg-async-stepping.js]
 [browser_dbg-sourcemapped-breakpoint-console.js]
 skip-if = (os == "win" && ccov) # Bug 1453549
 [browser_dbg-xhr-breakpoints.js]
 [browser_dbg-sourcemapped-scopes.js]
 skip-if = ccov || (verify && debug && (os == 'linux')) # Bug 1441545
 [browser_dbg-sourcemapped-stepping.js]
+skip-if = (os == 'win' && os_version == '10.0' && ccov) # Bug 1480680
 [browser_dbg-sourcemapped-preview.js]
 skip-if = os == "win" # Bug 1448523, Bug 1448450
 [browser_dbg-breaking.js]
 [browser_dbg-breaking-from-console.js]
 [browser_dbg-breakpoints.js]
 [browser_dbg-breakpoints-actions.js]
 [browser_dbg-breakpoints-cond.js]
 [browser_dbg-browser-content-toolbox.js]
--- a/dom/interfaces/payments/nsIPaymentRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -76,17 +76,17 @@ interface nsIPaymentOptions : nsISupport
   readonly attribute boolean requestPayerPhone;
   readonly attribute boolean requestShipping;
   readonly attribute AString shippingType;
 };
 
 [scriptable, builtinclass, uuid(2fa36783-d684-4487-b7a8-9def6ae3128f)]
 interface nsIPaymentRequest : nsISupports
 {
-  readonly attribute uint64_t tabId;
+  readonly attribute uint64_t topOuterWindowId;
   readonly attribute nsIPrincipal topLevelPrincipal;
   readonly attribute AString requestId;
   readonly attribute AString completeStatus;
   readonly attribute nsIArray paymentMethods;
   readonly attribute nsIPaymentDetails paymentDetails;
   readonly attribute nsIPaymentOptions paymentOptions;
   readonly attribute AString shippingOption;
 };
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -3212,17 +3212,17 @@ TabParent::DeallocPPluginWidgetParent(mo
 {
   delete aActor;
   return true;
 }
 
 PPaymentRequestParent*
 TabParent::AllocPPaymentRequestParent()
 {
-  RefPtr<PaymentRequestParent> actor = new PaymentRequestParent(GetTabId());
+  RefPtr<PaymentRequestParent> actor = new PaymentRequestParent();
   return actor.forget().take();
 }
 
 bool
 TabParent::DeallocPPaymentRequestParent(PPaymentRequestParent* aActor)
 {
   RefPtr<PaymentRequestParent> actor =
     dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -27,33 +27,20 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIUUIDGenerator.h"
 #include "nsPIDOMWindow.h"
 #include "nsProxyRelease.h"
 #include "nsRFPService.h"
 #include "nsServiceManagerUtils.h"
 
-// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
-// GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
-// currentTime getter.
-#ifdef GetCurrentTime
-#undef GetCurrentTime
-#endif
-
 #ifdef LOG
 #undef LOG
 #endif
 
-// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
-// GetTickCount() and conflicts with MediaStream::GetCurrentTime.
-#ifdef GetCurrentTime
-#undef GetCurrentTime
-#endif
-
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::media;
 
 static LazyLogModule gMediaStreamLog("MediaStream");
 #define LOG(type, msg) MOZ_LOG(gMediaStreamLog, type, msg)
 
@@ -409,19 +396,19 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAu
 NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMAudioNodeMediaStream)
 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
 DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow,
                                MediaStreamTrackSourceGetter* aTrackSourceGetter)
-  : mLogicalStreamStartTime(0), mWindow(aWindow),
-    mInputStream(nullptr), mOwnedStream(nullptr), mPlaybackStream(nullptr),
-    mTracksPendingRemoval(0), mTrackSourceGetter(aTrackSourceGetter),
+  : mWindow(aWindow), mInputStream(nullptr), mOwnedStream(nullptr),
+    mPlaybackStream(nullptr), mTracksPendingRemoval(0),
+    mTrackSourceGetter(aTrackSourceGetter),
     mPlaybackTrackListener(MakeAndAddRef<PlaybackTrackListener>(this)),
     mTracksCreated(false), mNotifiedOfMediaStreamGraphShutdown(false),
     mActive(false), mSetInactiveOnFinish(false), mCORSMode(CORS_NONE)
 {
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidgen =
     do_GetService("@mozilla.org/uuid-generator;1", &rv);
 
@@ -560,30 +547,16 @@ DOMMediaStream::Constructor(const Global
       MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER, ownerWindow,
                                     MediaStreamGraph::REQUEST_DEFAULT_SAMPLE_RATE);
     newStream->InitPlaybackStreamCommon(graph);
   }
 
   return newStream.forget();
 }
 
-double
-DOMMediaStream::CurrentTime()
-{
-  if (!mPlaybackStream) {
-    return 0.0;
-  }
-  // The value of a MediaStream's CurrentTime will always advance forward; it will never
-  // reset (even if one rewinds a video.) Therefore we can use a single Random Seed
-  // initialized at the same time as the object.
-  return nsRFPService::ReduceTimePrecisionAsSecs(mPlaybackStream->
-    StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime),
-    GetRandomTimelineSeed());
-}
-
 already_AddRefed<Promise>
 DOMMediaStream::CountUnderlyingStreams(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
--- a/dom/media/DOMMediaStream.h
+++ b/dom/media/DOMMediaStream.h
@@ -14,22 +14,16 @@
 #include "StreamTracks.h"
 #include "nsIDOMWindow.h"
 #include "nsIPrincipal.h"
 #include "MediaTrackConstraints.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/RelativeTimeline.h"
 #include "PrincipalChangeObserver.h"
 
-// X11 has a #define for CurrentTime. Unbelievable :-(.
-// See dom/media/webaudio/AudioContext.h for more fun!
-#ifdef CurrentTime
-#undef CurrentTime
-#endif
-
 namespace mozilla {
 
 class AbstractThread;
 class DOMMediaStream;
 class MediaStream;
 class MediaInputPort;
 class MediaStreamGraph;
 class ProcessedMediaStream;
@@ -352,18 +346,16 @@ public:
               const DOMMediaStream& aStream,
               ErrorResult& aRv);
 
   static already_AddRefed<DOMMediaStream>
   Constructor(const dom::GlobalObject& aGlobal,
               const dom::Sequence<OwningNonNull<MediaStreamTrack>>& aTracks,
               ErrorResult& aRv);
 
-  double CurrentTime();
-
   static already_AddRefed<dom::Promise>
   CountUnderlyingStreams(const dom::GlobalObject& aGlobal, ErrorResult& aRv);
 
   void GetId(nsAString& aID) const;
 
   void GetAudioTracks(nsTArray<RefPtr<AudioStreamTrack> >& aTracks) const;
   void GetAudioTracks(nsTArray<RefPtr<MediaStreamTrack> >& aTracks) const;
   void GetVideoTracks(nsTArray<RefPtr<VideoStreamTrack> >& aTracks) const;
@@ -517,21 +509,16 @@ public:
    * Create an DOMMediaStream whose underlying input stream is an
    * AudioCaptureStream.
    */
   static already_AddRefed<DOMMediaStream>
   CreateAudioCaptureStreamAsInput(nsPIDOMWindowInner* aWindow,
                                   nsIPrincipal* aPrincipal,
                                   MediaStreamGraph* aGraph);
 
-  void SetLogicalStreamStartTime(StreamTime aTime)
-  {
-    mLogicalStreamStartTime = aTime;
-  }
-
   /**
    * Adds a MediaStreamTrack to mTracks and raises "addtrack".
    *
    * Note that "addtrack" is raised synchronously and only has an effect if
    * this MediaStream is already exposed to script. For spec compliance this is
    * to be called from an async task.
    */
   void AddTrackInternal(MediaStreamTrack* aTrack);
@@ -657,19 +644,16 @@ protected:
    */
   void NotifyPlaybackTrackBlocked();
 
   // Recomputes the current principal of this stream based on the set of tracks
   // it currently contains. PrincipalChangeObservers will be notified only if
   // the principal changes.
   void RecomputePrincipal();
 
-  // StreamTime at which the currentTime attribute would return 0.
-  StreamTime mLogicalStreamStartTime;
-
   // We need this to track our parent object.
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 
   // MediaStreams are owned by the graph, but we tell them when to die,
   // and they won't die until we let them.
 
   // This stream contains tracks used as input by us. Cloning happens from this
   // stream. Tracks may exist in these stream but not in |mOwnedStream| if they
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1307,20 +1307,16 @@ public:
     {}
     void NotifyTracksAvailable(DOMMediaStream* aStream) override
     {
       // We're on the main thread, so no worries here.
       if (!mManager->IsWindowListenerStillActive(mWindowListener)) {
         return;
       }
 
-      // Start currentTime from the point where this stream was successfully
-      // returned.
-      aStream->SetLogicalStreamStartTime(aStream->GetPlaybackStream()->GetCurrentTime());
-
       // This is safe since we're on main-thread, and the windowlist can only
       // be invalidated from the main-thread (see OnNavigation)
       LOG(("Returning success for getUserMedia()"));
       CallOnSuccess(mOnSuccess, *aStream);
     }
     RefPtr<GetUserMediaWindowListener> mWindowListener;
     nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback> mOnSuccess;
     RefPtr<MediaManager> mManager;
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -1216,19 +1216,16 @@ class RTCPeerConnection {
     });
   }
 
   addStream(stream) {
     stream.getTracks().forEach(track => this.addTrack(track, stream));
   }
 
   addTrack(track, stream) {
-    if (stream.currentTime === undefined) {
-      throw new this._win.DOMException("invalid stream.", "InvalidParameterError");
-    }
     this._checkClosed();
 
     if (this._transceivers.some(
           transceiver => transceiver.sender.track == track)) {
       throw new this._win.DOMException("This track is already set on a sender.",
                                        "InvalidAccessError");
     }
 
--- a/dom/media/test/test_streams_element_capture.html
+++ b/dom/media/test/test_streams_element_capture.html
@@ -33,17 +33,16 @@ function isGreaterThanOrEqualEps(a, b, m
 function startTest(test) {
   var v = document.createElement('video');
   var vout = document.createElement('video');
 
   v.src = test.name;
   var stream;
 
   var checkEnded = function() {
-    is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
     if (test.duration) {
       isGreaterThanOrEqualEps(vout.currentTime, test.duration,
          test.name + " current time at end");
     }
     is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
     ok(vout.ended, test.name + " checking playback has ended");
     if (test.type.match(/^video/)) {
       checkDrawImage(vout);
@@ -53,17 +52,16 @@ function startTest(test) {
     SimpleTest.finish();
   };
   vout.addEventListener("ended", checkEnded);
 
   document.body.appendChild(vout);
 
   var onloadedmetadata = function (ev) {
     stream = v.mozCaptureStreamUntilEnded();
-    is(stream.currentTime, 0, test.name + " stream initial currentTime");
     vout.srcObject = stream;
     is(vout.srcObject, stream, test.name + " set output element .srcObject correctly");
     v.play();
     vout.play();
   }
 
   v.preload = 'metadata';
   v.addEventListener('loadedmetadata', onloadedmetadata);
--- a/dom/media/tests/mochitest/mediaStreamPlayback.js
+++ b/dom/media/tests/mochitest/mediaStreamPlayback.js
@@ -87,22 +87,20 @@ MediaStreamPlayback.prototype = {
     this.mediaElement.srcObject = this.mediaStream;
     this.mediaElement.play();
   },
 
   /**
    * Verifies that media is playing.
    */
   verifyPlaying : function() {
-    var lastStreamTime = this.mediaStream.currentTime;
     var lastElementTime = this.mediaElement.currentTime;
 
     var mediaTimeProgressed = listenUntil(this.mediaElement, 'timeupdate',
-        () => this.mediaStream.currentTime > lastStreamTime &&
-              this.mediaElement.currentTime > lastElementTime);
+        () => this.mediaElement.currentTime > lastElementTime);
 
     return timeout(Promise.all([this.canPlayThroughFired, mediaTimeProgressed]),
                    VERIFYPLAYING_TIMEOUT_LENGTH, "verifyPlaying timed out")
       .then(() => {
         is(this.mediaElement.paused, false,
            "Media element should be playing");
         is(this.mediaElement.duration, Number.POSITIVE_INFINITY,
            "Duration should be infinity");
--- a/dom/media/tests/mochitest/test_peerConnection_callbacks.html
+++ b/dom/media/tests/mochitest/test_peerConnection_callbacks.html
@@ -70,17 +70,17 @@ runNetworkTest(function() {
     .then(() => pcall(pc1, pc1.createOffer))
     .then(offer => pcall(pc1, pc1.setLocalDescription, offer))
     .then(() => pcall(pc2, pc2.setRemoteDescription, pc1.localDescription))
     .then(() => pcall(pc2, pc2.createAnswer))
     .then(answer => pcall(pc2, pc2.setLocalDescription, answer))
     .then(() => pcall(pc1, pc1.setRemoteDescription, pc2.localDescription))
     .then(() => delivered)
   //    .then(() => canPlayThrough)    // why doesn't this fire?
-    .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
+    .then(() => waitUntil(() => v2.currentTime > 0))
     .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
     .then(() => ok(true, "Connected."))
     .then(() => pcall(pc1, pc1.getStats, null))
     .then(stats => ok(Object.keys(stats).length > 0, "pc1 has stats"))
     .then(() => pcall(pc2, pc2.getStats, null))
     .then(stats => ok(Object.keys(stats).length > 0, "pc2 has stats"))
     .then(() => { v1.pause(); v2.pause(); })
     .catch(reason => ok(false, "unexpected failure: " + reason))
--- a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
+++ b/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
@@ -46,17 +46,17 @@
     .then(() => pc1.createOffer({})) // check that createOffer accepts arg.
     .then(offer => pc1.setLocalDescription(offer))
     .then(() => pc2.setRemoteDescription(pc1.localDescription))
     .then(() => pc2.createAnswer({}))  // check that createAnswer accepts arg.
     .then(answer => pc2.setLocalDescription(answer))
     .then(() => pc1.setRemoteDescription(pc2.localDescription))
     .then(() => delivered)
 //    .then(() => canPlayThrough)    // why doesn't this fire?
-    .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
+    .then(() => waitUntil(() => v2.currentTime > 0))
     .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
     .then(() => ok(true, "Connected."))
     .catch(reason => ok(false, "unexpected failure: " + reason))
     .then(networkTestFinished);
   });
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
+++ b/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
@@ -59,17 +59,17 @@
     await pc2.setLocalDescription(answer);
     await pc1.setRemoteDescription(pc2.localDescription);
     let trackevent = await ontrackfired;
 
     v2.srcObject = trackevent.streams[0];
 
     await v2loadedmetadata;
 
-    await waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0);
+    await waitUntil(() => v2.currentTime > 0);
     ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")");
 
     ok(v1.videoWidth > 0, "source width is positive");
     ok(v1.videoHeight > 0, "source height is positive");
     is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
     is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
     stream.getTracks().forEach(track => track.stop());
     v1.srcObject = v2.srcObject = null;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -198,16 +198,18 @@ MediaEngineWebRTCMicrophoneSource::Recon
          this,
          name.Data()));
     Stop(nullptr);
     return NS_ERROR_UNEXPECTED;
   }
 
   ApplySettings(outputPrefs);
 
+  mCurrentPrefs = outputPrefs;
+
   return NS_OK;
 }
 
 void
 MediaEngineWebRTCMicrophoneSource::Pull(
   const RefPtr<const AllocationHandle>&,
   const RefPtr<SourceMediaStream>& aStream,
   TrackID aTrackID,
@@ -491,16 +493,18 @@ MediaEngineWebRTCMicrophoneSource::Alloc
     media::NewRunnableFrom([that, prefs = outputPrefs]() mutable {
       that->mSettings->mEchoCancellation.Value() = prefs.mAecOn;
       that->mSettings->mAutoGainControl.Value() = prefs.mAgcOn;
       that->mSettings->mNoiseSuppression.Value() = prefs.mNoiseOn;
       that->mSettings->mChannelCount.Value() = prefs.mChannels;
       return NS_OK;
     }));
 
+  mCurrentPrefs = outputPrefs;
+
   return rv;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Deallocate(
   const RefPtr<const AllocationHandle>&)
 {
   AssertIsOnOwningThread();
@@ -666,16 +670,18 @@ MediaEngineWebRTCMicrophoneSource::Start
           that->mInputProcessing, StartStopMessage::Start));
       }
 
       that->mStream->OpenAudioInput(deviceID, that->mInputProcessing);
 
       return NS_OK;
     }));
 
+  ApplySettings(mCurrentPrefs);
+
   MOZ_ASSERT(mState != kReleased);
   mState = kStarted;
 
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Stop(const RefPtr<const AllocationHandle>&)
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.h
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.h
@@ -131,16 +131,19 @@ private:
   // Constructed on the MediaManager thread, and then only ever accessed on the
   // main thread.
   const nsMainThreadPtrHandle<media::Refcountable<dom::MediaTrackSettings>>
     mSettings;
 
   // Current state of the resource for this source.
   MediaEngineSourceState mState;
 
+  // The current preferences for the APM's various processing stages.
+  MediaEnginePrefs mCurrentPrefs;
+
   // The SourecMediaStream on which to append data for this microphone. Set in
   // SetTrack as part of the initialization, and nulled in ::Deallocate.
   RefPtr<SourceMediaStream> mStream;
 
   // See note at the top of this class.
   RefPtr<AudioInputProcessing> mInputProcessing;
 };
 
--- a/dom/payments/PaymentRequestData.cpp
+++ b/dom/payments/PaymentRequestData.cpp
@@ -669,39 +669,39 @@ PaymentOptions::GetShippingType(nsAStrin
   return NS_OK;
 }
 
 /* PaymentReqeust */
 
 NS_IMPL_ISUPPORTS(PaymentRequest,
                   nsIPaymentRequest)
 
-PaymentRequest::PaymentRequest(const uint64_t aTabId,
+PaymentRequest::PaymentRequest(const uint64_t aTopOuterWindowId,
                                const nsAString& aRequestId,
                                nsIPrincipal* aTopLevelPrincipal,
                                nsIArray* aPaymentMethods,
                                nsIPaymentDetails* aPaymentDetails,
                                nsIPaymentOptions* aPaymentOptions,
                                const nsAString& aShippingOption)
-  : mTabId(aTabId)
+  : mTopOuterWindowId(aTopOuterWindowId)
   , mRequestId(aRequestId)
   , mTopLevelPrincipal(aTopLevelPrincipal)
   , mPaymentMethods(aPaymentMethods)
   , mPaymentDetails(aPaymentDetails)
   , mPaymentOptions(aPaymentOptions)
   , mShippingOption(aShippingOption)
   , mState(eCreated)
 {
 }
 
 NS_IMETHODIMP
-PaymentRequest::GetTabId(uint64_t* aTabId)
+PaymentRequest::GetTopOuterWindowId(uint64_t* aTopOuterWindowId)
 {
-  NS_ENSURE_ARG_POINTER(aTabId);
-  *aTabId = mTabId;
+  NS_ENSURE_ARG_POINTER(aTopOuterWindowId);
+  *aTopOuterWindowId = mTopOuterWindowId;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PaymentRequest::GetTopLevelPrincipal(nsIPrincipal** aTopLevelPrincipal)
 {
   NS_ENSURE_ARG_POINTER(aTopLevelPrincipal);
   MOZ_ASSERT(mTopLevelPrincipal);
--- a/dom/payments/PaymentRequestData.h
+++ b/dom/payments/PaymentRequestData.h
@@ -187,17 +187,17 @@ private:
 };
 
 class PaymentRequest final : public nsIPaymentRequest
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTREQUEST
 
-  PaymentRequest(const uint64_t aTabId,
+  PaymentRequest(const uint64_t aTopOuterWindowId,
                  const nsAString& aRequestId,
                  nsIPrincipal* aPrincipal,
                  nsIArray* aPaymentMethods,
                  nsIPaymentDetails* aPaymentDetails,
                  nsIPaymentOptions* aPaymentOptions,
                  const nsAString& aShippingOption);
 
   void SetIPC(PaymentRequestParent* aIPC)
@@ -251,17 +251,17 @@ public:
   GetState() const
   {
     return mState;
   }
 
 private:
   ~PaymentRequest() = default;
 
-  uint64_t mTabId;
+  uint64_t mTopOuterWindowId;
   nsString mRequestId;
   nsString mCompleteStatus;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<nsIArray> mPaymentMethods;
   nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
   nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
   nsString mShippingOption;
 
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -458,17 +458,25 @@ PaymentRequestManager::CreatePayment(JSC
   rv = ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   IPCPaymentOptions options;
   ConvertOptions(aOptions, options);
 
-  IPCPaymentCreateActionRequest action(internalId,
+  nsCOMPtr<nsPIDOMWindowOuter> outerWindow = aWindow->GetOuterWindow();
+  MOZ_ASSERT(outerWindow);
+  if (nsCOMPtr<nsPIDOMWindowOuter> topOuterWindow = outerWindow->GetTop()) {
+    outerWindow = topOuterWindow;
+  }
+  uint64_t topOuterWindowId = outerWindow->WindowID();
+
+  IPCPaymentCreateActionRequest action(topOuterWindowId,
+                                       internalId,
                                        IPC::Principal(aTopLevelPrincipal),
                                        methodData,
                                        details,
                                        options,
                                        shippingOption);
 
   rv = SendRequestPayment(request, action, false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -229,34 +229,33 @@ PaymentRequestService::RequestPayment(co
       request->SetIPC(aIPC);
     }
   }
 
   switch (type) {
     case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
       MOZ_ASSERT(!request);
       const IPCPaymentCreateActionRequest& action = aAction;
-      uint64_t tabId = aIPC->GetTabId();
       nsCOMPtr<nsIMutableArray> methodData = do_CreateInstance(NS_ARRAY_CONTRACTID);
       MOZ_ASSERT(methodData);
       for (IPCPaymentMethodData data : action.methodData()) {
         nsCOMPtr<nsIPaymentMethodData> method;
         rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
         NS_ENSURE_SUCCESS(rv, rv);
         rv = methodData->AppendElement(method);
         NS_ENSURE_SUCCESS(rv, rv);
       }
       nsCOMPtr<nsIPaymentDetails> details;
       rv = payments::PaymentDetails::Create(action.details(), getter_AddRefs(details));
       NS_ENSURE_SUCCESS(rv, rv);
       nsCOMPtr<nsIPaymentOptions> options;
       rv = payments::PaymentOptions::Create(action.options(), getter_AddRefs(options));
       NS_ENSURE_SUCCESS(rv, rv);
       RefPtr<payments::PaymentRequest> request =
-        new payments::PaymentRequest(tabId,
+        new payments::PaymentRequest(action.topOuterWindowId(),
                                      aRequestId,
                                      action.topLevelPrincipal(),
                                      methodData,
                                      details,
                                      options,
                                      action.shippingOption());
 
       if (!mRequestQueue.AppendElement(request, mozilla::fallible)) {
--- a/dom/payments/ipc/PPaymentRequest.ipdl
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -65,16 +65,17 @@ struct IPCPaymentOptions
   bool requestPayerEmail;
   bool requestPayerPhone;
   bool requestShipping;
   nsString shippingType;
 };
 
 struct IPCPaymentCreateActionRequest
 {
+  uint64_t topOuterWindowId;
   nsString requestId;
   Principal topLevelPrincipal;
   IPCPaymentMethodData[] methodData;
   IPCPaymentDetails details;
   IPCPaymentOptions options;
   nsString shippingOption;
 };
 
--- a/dom/payments/ipc/PaymentRequestParent.cpp
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -12,19 +12,18 @@
 #include "nsServiceManagerUtils.h"
 #include "PaymentRequestData.h"
 #include "PaymentRequestParent.h"
 #include "PaymentRequestService.h"
 
 namespace mozilla {
 namespace dom {
 
-PaymentRequestParent::PaymentRequestParent(uint64_t aTabId)
+PaymentRequestParent::PaymentRequestParent()
   : mActorAlive(true)
-  , mTabId(aTabId)
   , mRequestId(EmptyString())
 {
 }
 
 mozilla::ipc::IPCResult
 PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest)
 {
   if (!mActorAlive) {
@@ -83,22 +82,16 @@ PaymentRequestParent::RecvRequestPayment
   MOZ_ASSERT(rowService);
   nsresult rv = rowService->RequestPayment(mRequestId, aRequest, this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return IPC_FAIL(this, "nsIPaymentRequestService::RequestPayment failed");
   }
   return IPC_OK();
 }
 
-uint64_t
-PaymentRequestParent::GetTabId()
-{
-  return mTabId;
-}
-
 nsresult
 PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
 {
   if (!NS_IsMainThread()) {
     RefPtr<PaymentRequestParent> self = this;
     nsCOMPtr<nsIPaymentActionResponse> response = aResponse;
     nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("PaymentRequestParent::RespondPayment",
                                                      [self, response] ()
--- a/dom/payments/ipc/PaymentRequestParent.h
+++ b/dom/payments/ipc/PaymentRequestParent.h
@@ -13,19 +13,18 @@
 
 namespace mozilla {
 namespace dom {
 
 class PaymentRequestParent final : public PPaymentRequestParent
 {
   NS_INLINE_DECL_REFCOUNTING(PaymentRequestParent)
 public:
-  explicit PaymentRequestParent(uint64_t aTabId);
+  PaymentRequestParent();
 
-  uint64_t GetTabId();
   nsresult RespondPayment(nsIPaymentActionResponse* aResponse);
   nsresult ChangeShippingAddress(const nsAString& aRequestId,
                                  nsIPaymentAddress* aAddress);
   nsresult ChangeShippingOption(const nsAString& aRequestId,
                                 const nsAString& aOption);
   nsresult ChangePayerDetail(const nsAString& aRequestId,
                              const nsAString& aPayerName,
                              const nsAString& aPayerEmail,
@@ -42,16 +41,15 @@ private:
   ~PaymentRequestParent() = default;
 
   nsresult SerializeAddress(IPCPaymentAddress& ipcAddress,
                             nsIPaymentAddress* aAddress);
   nsresult SerializeResponseData(IPCPaymentResponseData& ipcData,
                                  nsIPaymentResponseData* aData);
 
   bool mActorAlive;
-  uint64_t mTabId;
   nsString mRequestId;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/webidl/MediaStream.webidl
+++ b/dom/webidl/MediaStream.webidl
@@ -34,17 +34,16 @@ interface MediaStream : EventTarget {
     sequence<MediaStreamTrack> getTracks ();
     MediaStreamTrack?          getTrackById (DOMString trackId);
     void                       addTrack (MediaStreamTrack track);
     void                       removeTrack (MediaStreamTrack track);
     MediaStream                clone ();
     readonly    attribute boolean      active;
                 attribute EventHandler onaddtrack;
                 attribute EventHandler onremovetrack;
-    readonly attribute double currentTime;
 
     [ChromeOnly, Throws]
     static Promise<long> countUnderlyingStreams();
 
     // Webrtc allows the remote side to name a stream whatever it wants, and we
     // need to surface this to content.
     [ChromeOnly]
     void assignId(DOMString id);
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -1,69 +1,74 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * http://w3c.github.io/hr-time/
+ * https://w3c.github.io/hr-time/#sec-performance
+ * https://w3c.github.io/navigation-timing/#extensions-to-the-performance-interface
+ * https://w3c.github.io/performance-timeline/#extensions-to-the-performance-interface
+ * https://w3c.github.io/resource-timing/#sec-extensions-performance-interface
+ * https://w3c.github.io/user-timing/#extensions-performance-interface
  *
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang).
  * W3C liability, trademark and document use rules apply.
  */
 
 typedef double DOMHighResTimeStamp;
 typedef sequence <PerformanceEntry> PerformanceEntryList;
 
+// https://w3c.github.io/hr-time/#sec-performance
 [Exposed=(Window,Worker)]
 interface Performance : EventTarget {
   [DependsOn=DeviceState, Affects=Nothing]
   DOMHighResTimeStamp now();
 
   [Constant]
   readonly attribute DOMHighResTimeStamp timeOrigin;
+
+  [Default] object toJSON();
 };
 
+// https://w3c.github.io/navigation-timing/#extensions-to-the-performance-interface
 [Exposed=Window]
 partial interface Performance {
   [Constant]
   readonly attribute PerformanceTiming timing;
   [Constant]
   readonly attribute PerformanceNavigation navigation;
-
-  [Default] object toJSON();
 };
 
-// http://www.w3.org/TR/performance-timeline/#sec-window.performance-attribute
+// https://w3c.github.io/performance-timeline/#extensions-to-the-performance-interface
 [Exposed=(Window,Worker)]
 partial interface Performance {
   PerformanceEntryList getEntries();
   PerformanceEntryList getEntriesByType(DOMString entryType);
   PerformanceEntryList getEntriesByName(DOMString name, optional DOMString
     entryType);
 };
 
-// http://www.w3.org/TR/resource-timing/#extensions-performance-interface
+// https://w3c.github.io/resource-timing/#sec-extensions-performance-interface
 [Exposed=(Window,Worker)]
 partial interface Performance {
   void clearResourceTimings();
   void setResourceTimingBufferSize(unsigned long maxSize);
   attribute EventHandler onresourcetimingbufferfull;
 };
 
 // GC microbenchmarks, pref-guarded, not for general use (bug 1125412)
 [Exposed=Window]
 partial interface Performance {
   [Pref="dom.enable_memory_stats"]
   readonly attribute object mozMemory;
 };
 
-// http://www.w3.org/TR/user-timing/
+// https://w3c.github.io/user-timing/#extensions-performance-interface
 [Exposed=(Window,Worker)]
 partial interface Performance {
   [Throws]
   void mark(DOMString markName);
   void clearMarks(optional DOMString markName);
   [Throws]
   void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
   void clearMeasures(optional DOMString measureName);
 };
-
--- a/dom/webidl/PerformanceEntry.webidl
+++ b/dom/webidl/PerformanceEntry.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * http://www.w3c-test.org/webperf/specs/PerformanceTimeline/#sec-PerformanceEntry-interface
+ * https://w3c.github.io/performance-timeline/#dom-performanceentry
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Exposed=(Window,Worker)]
 interface PerformanceEntry
 {
--- a/dom/webidl/PerformanceNavigation.webidl
+++ b/dom/webidl/PerformanceNavigation.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * http://www.w3.org/TR/hr-time/
+ * https://w3c.github.io/navigation-timing/#the-performancenavigation-interface
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface PerformanceNavigation {
   const unsigned short TYPE_NAVIGATE = 0;
   const unsigned short TYPE_RELOAD = 1;
--- a/dom/webidl/PerformanceNavigationTiming.webidl
+++ b/dom/webidl/PerformanceNavigationTiming.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
+ * https://w3c.github.io/navigation-timing/#sec-PerformanceNavigationTiming
  *
  * Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang).
  * W3C liability, trademark and document use rules apply.
  */
 
 enum NavigationType {
   "navigate",
   "reload",
--- a/dom/webidl/PerformanceResourceTiming.webidl
+++ b/dom/webidl/PerformanceResourceTiming.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * https://w3c.github.io/resource-timing/#performanceresourcetiming
+ * https://w3c.github.io/resource-timing/#sec-performanceresourcetiming
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Exposed=(Window,Worker)]
 interface PerformanceResourceTiming : PerformanceEntry
 {
--- a/dom/webidl/PerformanceServerTiming.webidl
+++ b/dom/webidl/PerformanceServerTiming.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * https://w3c.github.io/server-timing/
+ * https://w3c.github.io/server-timing/#the-performanceservertiming-interface
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [SecureContext,Exposed=(Window,Worker)]
 interface PerformanceServerTiming {
   readonly attribute DOMString           name;
--- a/dom/webidl/PerformanceTiming.webidl
+++ b/dom/webidl/PerformanceTiming.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * http://www.w3.org/TR/hr-time/
+ * https://w3c.github.io/navigation-timing/#the-performancetiming-interface
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface PerformanceTiming {
   readonly attribute unsigned long long navigationStart;
   readonly attribute unsigned long long unloadEventStart;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -673,16 +673,23 @@ struct WebRenderMemoryReporterHelper {
 
   void ReportTexture(size_t aBytes, const char* aName) const
   {
     nsPrintfCString path("gfx/webrender/textures/%s", aName);
     nsCString desc(NS_LITERAL_CSTRING("GPU texture memory used by WebRender"));
     ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
   }
 
+  void ReportTotalGPUBytes(size_t aBytes) const
+  {
+    nsCString path(NS_LITERAL_CSTRING("gfx/webrender/total-gpu-bytes"));
+    nsCString desc(NS_LITERAL_CSTRING("Total GPU bytes used by WebRender (should match textures/ sum)"));
+    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
+  }
+
   void ReportInternal(size_t aBytes, nsACString& aPath, nsACString& aDesc, int32_t aKind) const
   {
     // Generally, memory reporters pass the empty string as the process name to
     // indicate "current process". However, if we're using a GPU process, the
     // measurements will actually take place in that process, and it's easier to
     // just note that here rather than trying to invoke the memory reporter in
     // the GPU process.
     nsAutoCString processName;
@@ -736,16 +743,19 @@ WebRenderMemoryReporter::CollectReports(
 
       // GPU Memory.
       helper.ReportTexture(aReport.gpu_cache_textures, "gpu-cache");
       helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
       helper.ReportTexture(aReport.render_target_textures, "render-targets");
       helper.ReportTexture(aReport.texture_cache_textures, "texture-cache");
       helper.ReportTexture(aReport.depth_target_textures, "depth-targets");
 
+      // Total GPU bytes, for sanity-checking the above.
+      helper.ReportTotalGPUBytes(aReport.total_gpu_bytes_allocated);
+
       FinishAsyncMemoryReport();
     },
     [](mozilla::ipc::ResponseRejectReason aReason) {
       FinishAsyncMemoryReport();
     }
   );
 
   return NS_OK;
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -971,19 +971,22 @@ LongestPhaseSelfTimeInMajorGC(const Stat
     // We have the total time spent in each phase, including descendant times.
     // Loop over the children and subtract their times from their parent's self
     // time.
     for (auto i : AllPhases()) {
         Phase parent = phases[i].parent;
         if (parent != Phase::NONE) {
             bool ok = CheckSelfTime(parent, i, times, selfTimes, times[i]);
 
-            // This happens very occasionally in release builds. Skip collecting
-            // longest phase telemetry if it does.
+            // This happens very occasionally in release builds and frequently
+            // in Windows debug builds. Skip collecting longest phase telemetry
+            // if it does.
+#ifndef XP_WIN
             MOZ_ASSERT(ok, "Inconsistent time data; see bug 1400153");
+#endif
             if (!ok) {
                 return PhaseKind::NONE;
             }
 
             selfTimes[parent] -= times[i];
         }
     }
 
--- a/js/src/jit-test/tests/wasm/bench/wasm_box2d.js
+++ b/js/src/jit-test/tests/wasm/bench/wasm_box2d.js
@@ -4,18 +4,18 @@ const isSimulator = build['arm-simulator
                     build['mips32-simulator'] ||
                     build['mips64-simulator'];
 
 // This test often times out on debug simulators due to the extreme slowdown.
 if (build['debug'] && isSimulator)
   quit();
 
 // All the glue code is wrapped in a function so it can be executed uncached and
-// cached (via the shared cacheEntry argument).
-function runBox2d(cacheEntry) {
+// cached or compiled separately.
+function runBox2d(cacheEntryOrModule) {
 
 // The Module object: Our interface to the outside world. We import
 // and export values on it, and do the work to get that through
 // closure compiler if necessary. There are various ways Module can be used:
 // 1. Not defined. We create it here
 // 2. A function parameter, function(Module) { ..generated code.. }
 // 3. pre-run appended it, var Module = {}; ..generated code..
 // 4. External script tag defines var Module.
@@ -1494,22 +1494,25 @@ function integrateWasmJS(Module) {
       exports = instance.exports;
       if (exports.memory) mergeMemory(exports.memory);
       Module['asm'] = exports;
       Module["usingWasm"] = true;
     }
     Module['printErr']('asynchronously preparing wasm');
     addRunDependency('wasm-instantiate'); // we can't run yet
 
-    (wasmStreamingIsSupported()
-     ? WebAssembly.instantiateStreaming(cacheEntry, info)
-     : WebAssembly.instantiate(cacheEntry.getBuffer(), info))
+    (cacheEntryOrModule instanceof WebAssembly.Module
+     ? WebAssembly.instantiate(cacheEntryOrModule, info)
+       .then(instance => ({instance, module:cacheEntryOrModule}))
+     : wasmStreamingIsSupported()
+       ? WebAssembly.instantiateStreaming(cacheEntryOrModule, info)
+       : WebAssembly.instantiate(cacheEntryOrModule.getBuffer(), info))
     .then(function(output) {
-      if (!cacheEntry.module)
-        cacheEntry.module = output.module;
+      if (!cacheEntryOrModule.module)
+        cacheEntryOrModule.module = output.module;
 
       // receiveInstance() will swap in the exports (to Module.asm) so they can be called
       receiveInstance(output.instance);
       removeRunDependency('wasm-instantiate');
     })
     .catch(function(reason) {
       Module['printErr']('failed to asynchronously prepare wasm:\n  ' + reason);
     });
@@ -3039,17 +3042,23 @@ if (Module['noInitialRun']) {
 }
 
 
 run();
 drainJobQueue();
 
 };  // End of function wrapping the whole top-level Emscripten glue code
 
+const bytecode = os.file.readFile(scriptdir + 'wasm_box2d.wasm', 'binary');
+
 setBufferStreamParams(/* delayMillis = */ 1, /* chunkSize = */ 1000);
-const cacheEntry = streamCacheEntry(os.file.readFile(scriptdir + 'wasm_box2d.wasm', 'binary'));
+const cacheEntry = streamCacheEntry(bytecode);
 
 runBox2d(cacheEntry);
 
 while (!wasmHasTier2CompilationCompleted(cacheEntry.module)) sleep(1);
 assertEq(cacheEntry.cached, wasmCachingIsSupported());
 
 runBox2d(cacheEntry);
+
+if (wasmCachingIsSupported()) {
+    runBox2d(wasmCompileInSeparateProcess(bytecode));
+}
--- a/js/src/jit-test/tests/wasm/caching.js
+++ b/js/src/jit-test/tests/wasm/caching.js
@@ -16,24 +16,46 @@ function testCached(code, imports, test)
             sleep(1);
          }
          assertEq(cache.cached, wasmCachingIsSupported());
          return compileStreaming(cache);
      })
      .then(m => {
          test(new Instance(m, imports));
          assertEq(cache.cached, wasmCachingIsSupported());
+
+         if (wasmCachingIsSupported()) {
+             let m2 = wasmCompileInSeparateProcess(code);
+             test(new Instance(m2, imports));
+         }
+
          success = true;
      })
      .catch(err => { print(String(err) + " at:\n" + err.stack) });
 
      drainJobQueue();
      assertEq(success, true);
 }
 
+testCached(`(module
+    (func $test (param i64) (result f64)
+        get_local 0
+        f64.convert_u/i64
+    )
+    (func (export "run") (result i32)
+        i64.const 1
+        call $test
+        f64.const 1
+        f64.eq
+    )
+)`,
+    undefined,
+    i => { assertEq(i.exports.run(), 1); }
+);
+
 testCached(
     `(module
        (func (export "run") (result i32)
          (i32.const 42)))`,
     undefined,
     i => { assertEq(i.exports.run(), 42); }
 );
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2554,17 +2554,17 @@ jit::RemoveUnmarkedBlocks(MIRGenerator* 
         // since we may have removed edges even if we didn't remove any blocks.
         graph.unmarkBlocks();
     } else {
         // As we are going to remove edges and basic blocks, we have to mark
         // instructions which would be needed by baseline if we were to
         // bailout.
         for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) {
             MBasicBlock* block = *it++;
-            if (!block->isMarked()) {
+            if (block->isMarked()) {
                 continue;
             }
 
             FlagAllOperandsAsHavingRemovedUses(mir, block);
         }
 
         // Find unmarked blocks and remove them.
         for (ReversePostorderIterator iter(graph.rpoBegin()); iter != graph.rpoEnd();) {
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -30,16 +30,17 @@
 #include "vm/GeckoProfiler.h"
 #include "vm/Interpreter.h"
 #include "vm/JSFunction.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/TraceLogging.h"
 #include "vm/TypeInference.h"
 #include "wasm/WasmBuiltins.h"
+#include "wasm/WasmInstance.h"
 
 #include "gc/Nursery-inl.h"
 #include "jit/JSJitFrameIter-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/Probes-inl.h"
 #include "vm/TypeInference-inl.h"
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -115,17 +115,16 @@
 #include "vm/MutexIDs.h"
 #include "vm/Printer.h"
 #include "vm/Shape.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/Time.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 #include "wasm/WasmJS.h"
-#include "wasm/WasmModule.h"
 
 #include "vm/Compartment-inl.h"
 #include "vm/ErrorObject-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/Realm-inl.h"
 #include "vm/Stack-inl.h"
 
@@ -5630,39 +5629,16 @@ runOffThreadDecodedScript(JSContext* cx,
     RootedScript script(cx, JS::FinishOffThreadScriptDecoder(cx, token));
     if (!script) {
         return false;
     }
 
     return JS_ExecuteScript(cx, script, args.rval());
 }
 
-struct MOZ_RAII FreeOnReturn
-{
-    JSContext* cx;
-    const char* ptr;
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-
-    explicit FreeOnReturn(JSContext* cx, const char* ptr = nullptr
-                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : cx(cx), ptr(ptr)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    void init(const char* ptr) {
-        MOZ_ASSERT(!this->ptr);
-        this->ptr = ptr;
-    }
-
-    ~FreeOnReturn() {
-        JS_free(cx, (void*)ptr);
-    }
-};
-
 static int sArgc;
 static char** sArgv;
 
 class AutoCStringVector
 {
     Vector<char*> argv_;
   public:
     explicit AutoCStringVector(JSContext* cx) : argv_(cx) {}
@@ -5843,16 +5819,323 @@ NestedShell(JSContext* cx, unsigned argc
         return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
+ReadAll(int fd, wasm::Bytes* bytes)
+{
+    size_t lastLength = bytes->length();
+    while (true) {
+        static const int ChunkSize = 64 * 1024;
+        if (!bytes->growBy(ChunkSize)) {
+            return false;
+        }
+
+        intptr_t readCount;
+        while (true) {
+            readCount = read(fd, bytes->begin() + lastLength, ChunkSize);
+            if (readCount >= 0) {
+                break;
+            }
+            if (errno != EINTR) {
+                return false;
+            }
+        }
+
+        if (readCount < ChunkSize) {
+            bytes->shrinkTo(lastLength + readCount);
+            if (readCount == 0) {
+                return true;
+            }
+        }
+
+        lastLength = bytes->length();
+    }
+}
+
+static bool
+WriteAll(int fd, const uint8_t* bytes, size_t length)
+{
+    while (length > 0) {
+        int written = write(fd, bytes, length);
+        if (written < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            return false;
+        }
+        MOZ_ASSERT(unsigned(written) <= length);
+        length -= written;
+        bytes += written;
+    }
+
+    return true;
+}
+
+class AutoPipe
+{
+    int fds_[2];
+
+  public:
+    AutoPipe()
+    {
+        fds_[0] = -1;
+        fds_[1] = -1;
+    }
+
+    ~AutoPipe() {
+        if (fds_[0] != -1) {
+            close(fds_[0]);
+        }
+        if (fds_[1] != -1) {
+            close(fds_[1]);
+        }
+    }
+
+    bool init() {
+#ifdef XP_WIN
+        return !_pipe(fds_, 4096, O_BINARY);
+#else
+        return !pipe(fds_);
+#endif
+    }
+
+    int reader() const {
+        MOZ_ASSERT(fds_[0] != -1);
+        return fds_[0];
+    }
+
+    int writer() const {
+        MOZ_ASSERT(fds_[1] != -1);
+        return fds_[1];
+    }
+
+    void closeReader() {
+        MOZ_ASSERT(fds_[0] != -1);
+        close(fds_[0]);
+        fds_[0] = -1;
+    }
+
+    void closeWriter() {
+        MOZ_ASSERT(fds_[1] != -1);
+        close(fds_[1]);
+        fds_[1] = -1;
+    }
+};
+
+static bool
+CompileAndSerializeInSeparateProcess(JSContext* cx, const uint8_t* bytecode, size_t bytecodeLength,
+                                     wasm::Bytes* serialized)
+{
+    AutoPipe stdIn, stdOut;
+    if (!stdIn.init() || !stdOut.init()) {
+        return false;
+    }
+
+    AutoCStringVector argv(cx);
+
+    UniqueChars argv0 = DuplicateString(cx, sArgv[0]);
+    if (!argv0 || !argv.append(std::move(argv0))) {
+        return false;
+    }
+
+    UniqueChars argv1 = DuplicateString("--wasm-compile-and-serialize");
+    if (!argv1 || !argv.append(std::move(argv1))) {
+        return false;
+    }
+
+#ifdef XP_WIN
+    // The spawned process will have all the stdIn/stdOut file handles open, but
+    // without the power of fork, we need some other way to communicate the
+    // integer fd values so we encode them in argv and WasmCompileAndSerialize()
+    // has a matching #ifdef XP_WIN to parse them out. Communicate both ends of
+    // both pipes so the child process can closed the unused ends.
+
+    UniqueChars argv2 = JS_smprintf("%d", stdIn.reader());
+    if (!argv2 || !argv.append(std::move(argv2))) {
+        return false;
+    }
+
+    UniqueChars argv3 = JS_smprintf("%d", stdIn.writer());
+    if (!argv3 || !argv.append(std::move(argv3))) {
+        return false;
+    }
+
+    UniqueChars argv4 = JS_smprintf("%d", stdOut.reader());
+    if (!argv4 || !argv.append(std::move(argv4))) {
+        return false;
+    }
+
+    UniqueChars argv5 = JS_smprintf("%d", stdOut.writer());
+    if (!argv5 || !argv.append(std::move(argv5))) {
+        return false;
+    }
+#endif
+
+    for (unsigned i = 0; i < sPropagatedFlags.length(); i++) {
+        UniqueChars flags = DuplicateString(cx, sPropagatedFlags[i]);
+        if (!flags || !argv.append(std::move(flags))) {
+            return false;
+        }
+    }
+
+    if (!argv.append(nullptr)) {
+        return false;
+    }
+
+#ifdef XP_WIN
+    if (!EscapeForShell(cx, argv)) {
+        return false;
+    }
+
+    int childPid = _spawnv(P_NOWAIT, sArgv[0], argv.get());
+    if (childPid == -1) {
+        return false;
+    }
+#else
+    pid_t childPid = fork();
+    switch (childPid) {
+      case -1:
+        return false;
+      case 0:
+        // In the child process. Redirect stdin/stdout to the respective ends of
+        // the pipes. Closing stdIn.writer() is necessary for stdin to hit EOF.
+        // This case statement must not return before exec() takes over. Rather,
+        // exit(-1) is used to return failure to the parent process.
+        if (dup2(stdIn.reader(), STDIN_FILENO) == -1) {
+            exit(-1);
+        }
+        if (dup2(stdOut.writer(), STDOUT_FILENO) == -1) {
+            exit(-1);
+        }
+        close(stdIn.reader());
+        close(stdIn.writer());
+        close(stdOut.reader());
+        close(stdOut.writer());
+        execv(sArgv[0], argv.get());
+        exit(-1);
+    }
+#endif
+
+    // In the parent process. Closing stdOut.writer() is necessary for
+    // stdOut.reader() below to hit EOF.
+    stdIn.closeReader();
+    stdOut.closeWriter();
+
+    if (!WriteAll(stdIn.writer(), bytecode, bytecodeLength)) {
+        return false;
+    }
+
+    stdIn.closeWriter();
+
+    if (!ReadAll(stdOut.reader(), serialized)) {
+        return false;
+    }
+
+    stdOut.closeReader();
+
+    int status;
+#ifdef XP_WIN
+    if (_cwait(&status, childPid, WAIT_CHILD) == -1) {
+        return false;
+    }
+#else
+    while (true) {
+        if (waitpid(childPid, &status, 0) >= 0) {
+            break;
+        }
+        if (errno != EINTR) {
+            return false;
+        }
+    }
+#endif
+
+    return status == 0;
+}
+
+static bool
+WasmCompileAndSerialize(JSContext* cx)
+{
+    MOZ_ASSERT(wasm::HasCachingSupport(cx));
+
+#ifdef XP_WIN
+    // See CompileAndSerializeInSeparateProcess for why we've had to smuggle
+    // these fd values through argv. Closing the writing ends is necessary for
+    // the reading ends to hit EOF.
+    MOZ_RELEASE_ASSERT(sArgc >= 6);
+    MOZ_ASSERT(!strcmp(sArgv[1], "--wasm-compile-and-serialize"));
+    int stdIn = atoi(sArgv[2]);   // stdIn.reader()
+    close(atoi(sArgv[3]));        // stdIn.writer()
+    close(atoi(sArgv[4]));        // stdOut.reader()
+    int stdOut = atoi(sArgv[5]);  // stdOut.writer()
+#else
+    int stdIn = STDIN_FILENO;
+    int stdOut = STDOUT_FILENO;
+#endif
+
+    wasm::MutableBytes bytecode = js_new<wasm::ShareableBytes>();
+    if (!ReadAll(stdIn, &bytecode->bytes)) {
+        return false;
+    }
+
+    wasm::Bytes serialized;
+    if (!wasm::CompileAndSerialize(*bytecode, &serialized)) {
+        return false;
+    }
+
+    if (!WriteAll(stdOut, serialized.begin(), serialized.length())) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool
+WasmCompileInSeparateProcess(JSContext* cx, unsigned argc, Value* vp)
+{
+    if (!wasm::HasCachingSupport(cx)) {
+        JS_ReportErrorASCII(cx, "WebAssembly caching not supported");
+        return false;
+    }
+
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!args.requireAtLeast(cx, "wasmCompileInSeparateProcess", 1)) {
+        return false;
+    }
+
+    SharedMem<uint8_t*> bytecode;
+    size_t numBytes;
+    if (!args[0].isObject() || !IsBufferSource(&args[0].toObject(), &bytecode, &numBytes)) {
+        RootedObject callee(cx, &args.callee());
+        ReportUsageErrorASCII(cx, callee, "Argument must be a buffer source");
+        return false;
+    }
+
+    wasm::Bytes serialized;
+    if (!CompileAndSerializeInSeparateProcess(cx, bytecode.unwrap(), numBytes, &serialized)) {
+        if (!cx->isExceptionPending()) {
+            JS_ReportErrorASCII(cx, "creating and executing child process");
+        }
+        return false;
+    }
+
+    RootedObject module(cx);
+    if (!wasm::DeserializeModule(cx, serialized, &module)) {
+        return false;
+    }
+
+    args.rval().setObject(*module);
+    return true;
+}
+
+static bool
 DecompileFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1 || !args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
     RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
@@ -6526,17 +6809,17 @@ DisableGeckoProfiling(JSContext* cx, uns
 // These object types are shareable:
 //
 //   - SharedArrayBuffer
 //   - WasmMemoryObject (when constructed with shared:true)
 //   - WasmModuleObject
 //
 // For the SharedArrayBuffer and WasmMemoryObject we transmit the underlying
 // SharedArrayRawBuffer ("SARB"). For the WasmModuleObject we transmit the
-// underlying wasm::Module.  The transmitted types are refcounted.  When they
+// underlying JS::WasmModule.  The transmitted types are refcounted.  When they
 // are in the mailbox their reference counts are at least 1, accounting for the
 // reference from the mailbox.
 //
 // The lock guards the mailbox variable and prevents a race where two workers
 // try to set the mailbox at the same time to replace an object that is only
 // referenced from the mailbox: the workers will both decrement the reference
 // count on the old object, and one of those decrements will be on a garbage
 // object.  We could implement this with atomics and a CAS loop but it's not
@@ -6557,17 +6840,17 @@ enum class MailboxTag {
 
 struct SharedObjectMailbox
 {
     union Value {
         struct {
             SharedArrayRawBuffer* buffer;
             uint32_t              length;
         } sarb;
-        const wasm::Module*       module;
+        JS::WasmModule*           module;
         double                    number;
     };
 
     SharedObjectMailbox() : tag(MailboxTag::Empty) {}
 
     MailboxTag tag;
     Value      val;
 };
@@ -6678,18 +6961,17 @@ GetSharedObject(JSContext* cx, unsigned 
             MOZ_ASSERT(cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled());
 
             if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly)) {
                 return false;
             }
 
             // WasmModuleObject::create() increments the refcount on the module
             // and signals an error and returns null if that fails.
-            RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
-            newObj = WasmModuleObject::create(cx, *mbx->val.module, proto);
+            newObj = mbx->val.module->createObject(cx);
             if (!newObj) {
                 return false;
             }
             break;
           }
           default: {
             MOZ_CRASH();
           }
@@ -6733,20 +7015,19 @@ SetSharedObject(JSContext* cx, unsigned 
                 if (!value.sarb.buffer->addReference()) {
                     JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer");
                     return false;
                 }
             } else {
                 JS_ReportErrorASCII(cx, "Invalid argument to SetSharedObject");
                 return false;
             }
-        } else if (obj->is<WasmModuleObject>()) {
+        } else if (JS::IsWasmModuleObject(obj)) {
             tag = MailboxTag::WasmModule;
-            value.module = &obj->as<WasmModuleObject>().module();
-            value.module->AddRef();
+            value.module = JS::GetWasmModule(obj).forget().take();
         } else {
             JS_ReportErrorASCII(cx, "Invalid argument to SetSharedObject");
             return false;
         }
     } else if (args.get(0).isNumber()) {
         tag = MailboxTag::Number;
         value.number = args.get(0).toNumber();
         // Nothing
@@ -8610,16 +8891,22 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
 "addIntlExtras(obj)",
 "Adds various not-yet-standardized Intl functions as properties on the\n"
 "provided object (this should generally be Intl itself).  The added\n"
 "functions and their behavior are experimental: don't depend upon them\n"
 "unless you're willing to update your code if these experimental APIs change\n"
 "underneath you."),
 #endif // ENABLE_INTL_API
 
+    JS_FN_HELP("wasmCompileInSeparateProcess", WasmCompileInSeparateProcess, 1, 0,
+"wasmCompileInSeparateProcess(buffer)",
+"  Compile the given buffer in a separate process, serialize the resulting\n"
+"  wasm::Module into bytes, and deserialize those bytes in the current\n"
+"  process, returning the resulting WebAssembly.Module."),
+
     JS_FS_HELP_END
 };
 
 static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
     JS_FN_HELP("getSelfHostedValue", GetSelfHostedValue, 1, 0,
 "getSelfHostedValue()",
 "  Get a self-hosted value by its name. Note that these values don't get \n"
 "  cached, so repeatedly getting the same value creates multiple distinct clones."),
@@ -10408,16 +10695,25 @@ SetWorkerContextOptions(JSContext* cx)
 #endif
 
     JS_SetNativeStackQuota(cx, gMaxStackSize);
 }
 
 static int
 Shell(JSContext* cx, OptionParser* op, char** envp)
 {
+    if (op->getBoolOption("wasm-compile-and-serialize")) {
+        if (!WasmCompileAndSerialize(cx)) {
+            // Errors have been printed directly to stderr.
+            MOZ_ASSERT(!cx->isExceptionPending());
+            return -1;
+        }
+        return EXIT_SUCCESS;
+    }
+
 #ifdef MOZ_CODE_COVERAGE
     InstallCoverageSignalHandlers();
 #endif
 
     Maybe<JS::AutoDisableGenerationalGC> noggc;
     if (op->getBoolOption("no-ggc")) {
         noggc.emplace(cx);
     }
@@ -10783,16 +11079,17 @@ main(int argc, char** argv, char** envp)
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", gc::ZealModeHelpText)
 #else
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", "option ignored in non-gc-zeal builds")
 #endif
         || !op.addStringOption('\0', "module-load-path", "DIR", "Set directory to load modules from")
         || !op.addBoolOption('\0', "no-async-stacks", "Disable async stacks")
         || !op.addMultiStringOption('\0', "dll", "LIBRARY", "Dynamically load LIBRARY")
         || !op.addBoolOption('\0', "suppress-minidump", "Suppress crash minidumps")
+        || !op.addBoolOption('\0', "wasm-compile-and-serialize", "Compile the wasm bytecode from stdin and serialize the results to stdout")
     )
     {
         return EXIT_FAILURE;
     }
 
     op.setArgTerminatesOptions("script", true);
     op.setArgCapturesRest("scriptArgs");
 
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -24,17 +24,16 @@
 #include "js/Utility.h"
 #include "js/Wrapper.h"
 #include "vm/GeneratorObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 #include "vm/SavedStacks.h"
 #include "vm/Stack.h"
-#include "wasm/WasmJS.h"
 
 namespace js {
 
 /**
  * Tells how the JS engine should resume debuggee execution after firing a
  * debugger hook.  Most debugger hooks get to choose how the debuggee proceeds;
  * see js/src/doc/Debugger/Conventions.md under "Resumption Values".
  *
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -14,17 +14,16 @@
 
 #include "jit/BaselineFrame.h"
 #include "jit/RematerializedFrame.h"
 #include "js/Debug.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/GeneratorObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSScript.h"
-#include "wasm/WasmInstance.h"
 
 #include "jit/BaselineFrame-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 
 namespace js {
 
@@ -737,17 +736,17 @@ AbstractFramePtr::wasmInstance() const
 {
     return asWasmDebugFrame()->instance();
 }
 
 inline GlobalObject*
 AbstractFramePtr::global() const
 {
     if (isWasmDebugFrame()) {
-        return &wasmInstance()->object()->global();
+        return asWasmDebugFrame()->global();
     }
     return &script()->global();
 }
 
 inline JSFunction*
 AbstractFramePtr::callee() const
 {
     if (isInterpreterFrame()) {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -11,16 +11,17 @@
 #include "gc/Marking.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitRealm.h"
 #include "jit/shared/CodeGenerator-shared.h"
 #include "vm/Debugger.h"
 #include "vm/JSContext.h"
 #include "vm/Opcodes.h"
+#include "wasm/WasmInstance.h"
 
 #include "jit/JSJitFrameIter-inl.h"
 #include "vm/Compartment-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Probes-inl.h"
 
 using namespace js;
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -525,17 +525,17 @@ DecodeCodeSection(const ModuleEnvironmen
         return false;
     }
 
     return mg.finishFuncDefs();
 }
 
 SharedModule
 wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error,
-                    UniqueCharsVector* warnings)
+                    UniqueCharsVector* warnings, UniqueLinkData* maybeLinkData)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
     Decoder d(bytecode.bytes, 0, error, warnings);
 
     CompilerEnvironment compilerEnv(args);
     ModuleEnvironment env(args.gcTypesConfigured,
                           &compilerEnv,
@@ -564,17 +564,17 @@ wasm::CompileBuffer(const CompileArgs& a
     if (!DecodeCodeSection(env, d, mg)) {
         return nullptr;
     }
 
     if (!DecodeModuleTail(d, &env, mg.deferredValidationState())) {
         return nullptr;
     }
 
-    return mg.finishModule(bytecode);
+    return mg.finishModule(bytecode, nullptr, maybeLinkData);
 }
 
 void
 wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode, const Module& module,
                    Atomic<bool>* cancelled)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
--- a/js/src/wasm/WasmCompile.h
+++ b/js/src/wasm/WasmCompile.h
@@ -84,17 +84,18 @@ EstimateCompiledCodeSize(Tier tier, size
 // SharedModule pointer is null and either:
 //  - *error points to a string description of the error
 //  - *error is null and the caller should report out-of-memory.
 
 SharedModule
 CompileBuffer(const CompileArgs& args,
               const ShareableBytes& bytecode,
               UniqueChars* error,
-              UniqueCharsVector* warnings);
+              UniqueCharsVector* warnings,
+              UniqueLinkData* maybeLinkData = nullptr);
 
 // Attempt to compile the second tier of the given wasm::Module.
 
 void
 CompileTier2(const CompileArgs& args, const Bytes& bytecode, const Module& module,
              Atomic<bool>* cancelled);
 
 // Compile the given WebAssembly module which has been broken into three
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -1032,17 +1032,17 @@ ModuleGenerator::finishMetadata(const By
     SharedMetadata metadata = metadata_;
     metadata_ = nullptr;
     return metadata;
 }
 
 SharedModule
 ModuleGenerator::finishModule(const ShareableBytes& bytecode,
                               JS::OptimizedEncodingListener* maybeTier2Listener,
-                              UniqueLinkData* maybeLinkDataOut)
+                              UniqueLinkData* maybeLinkData)
 {
     MOZ_ASSERT(mode() == CompileMode::Once || mode() == CompileMode::Tier1);
 
     UniqueCodeTier codeTier = finishCodeTier();
     if (!codeTier) {
         return nullptr;
     }
 
@@ -1149,20 +1149,19 @@ ModuleGenerator::finishModule(const Shar
     }
 
     if (mode() == CompileMode::Tier1) {
         module->startTier2(*compileArgs_, bytecode, maybeTier2Listener);
     } else if (tier() == Tier::Serialized && maybeTier2Listener) {
         module->serialize(*linkData_, *maybeTier2Listener);
     }
 
-    if (maybeLinkDataOut) {
-        MOZ_ASSERT(isAsmJS());
+    if (maybeLinkData) {
         MOZ_ASSERT(!env_->debugEnabled());
-        *maybeLinkDataOut = std::move(linkData_);
+        *maybeLinkData = std::move(linkData_);
     }
 
     return module;
 }
 
 bool
 ModuleGenerator::finishTier2(const Module& module)
 {
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -228,17 +228,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool finishFuncDefs();
 
     // If env->mode is Once or Tier1, finishModule() must be called to generate
     // a new Module. Otherwise, if env->mode is Tier2, finishTier2() must be
     // called to augment the given Module with tier 2 code.
 
     SharedModule finishModule(const ShareableBytes& bytecode,
                               JS::OptimizedEncodingListener* maybeTier2Listener = nullptr,
-                              UniqueLinkData* maybeLinkDataOut = nullptr);
+                              UniqueLinkData* maybeLinkData = nullptr);
     MOZ_MUST_USE bool finishTier2(const Module& module);
 
     ExclusiveDeferredValidationState& deferredValidationState() {
         return deferredValidationState_;
     }
 };
 
 } // namespace wasm
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -380,17 +380,17 @@ DescribeScriptedCaller(JSContext* cx, Sc
             return false;
         }
     }
 
     return true;
 }
 
 // ============================================================================
-// Fuzzing support
+// Testing / Fuzzing support
 
 bool
 wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
            MutableHandleWasmInstanceObject instanceObj)
 {
     if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly)) {
         return false;
     }
@@ -437,16 +437,60 @@ wasm::Eval(JSContext* cx, Handle<TypedAr
     if (!GetImports(cx, *module, importObj, &funcs, &table, &memory, globalObjs.get(), &globals)) {
         return false;
     }
 
     return module->instantiate(cx, funcs, table, memory, globals, globalObjs.get(), nullptr,
                                instanceObj);
 }
 
+bool
+wasm::CompileAndSerialize(const ShareableBytes& bytecode, Bytes* serialized)
+{
+    MutableCompileArgs compileArgs = js_new<CompileArgs>(ScriptedCaller());
+    if (!compileArgs) {
+        return false;
+    }
+
+    // The caller has ensured HasCachingSupport().
+    compileArgs->ionEnabled = true;
+
+    UniqueChars error;
+    UniqueCharsVector warnings;
+    UniqueLinkData linkData;
+    SharedModule module = CompileBuffer(*compileArgs, bytecode, &error, &warnings, &linkData);
+    if (!module) {
+        fprintf(stderr, "Compilation error: %s\n", error ? error.get() : "oom");
+        return false;
+    }
+
+    MOZ_ASSERT(module->code().hasTier(Tier::Serialized));
+
+    size_t serializedSize = module->serializedSize(*linkData);
+    if (!serialized->resize(serializedSize)) {
+        return false;
+    }
+
+    module->serialize(*linkData, serialized->begin(), serialized->length());
+    return true;
+}
+
+bool
+wasm::DeserializeModule(JSContext* cx, const Bytes& serialized, MutableHandleObject moduleObj)
+{
+    MutableModule module = Module::deserialize(serialized.begin(), serialized.length());
+    if (!module) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
+    moduleObj.set(module->createObject(cx));
+    return !!moduleObj;
+}
+
 // ============================================================================
 // Common functions
 
 // '[EnforceRange] unsigned long' types are coerced with
 //    ConvertToInt(v, 32, 'unsigned')
 // defined in Web IDL Section 3.2.4.9.
 static bool
 EnforceRangeU32(JSContext* cx, HandleValue v, const char* kind, const char* noun, uint32_t* u32)
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -59,16 +59,28 @@ HasCachingSupport(JSContext* cx);
 
 // Compiles the given binary wasm module given the ArrayBufferObject
 // and links the module's imports with the given import object.
 
 MOZ_MUST_USE bool
 Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
      MutableHandleWasmInstanceObject instanceObj);
 
+// For testing cross-process (de)serialization, this pair of functions are
+// responsible for, in the child process, compiling the given wasm bytecode
+// to a wasm::Module that is serialized into the given byte array, and, in
+// the parent process, deserializing the given byte array into a
+// WebAssembly.Module object.
+
+MOZ_MUST_USE bool
+CompileAndSerialize(const ShareableBytes& bytecode, Bytes* serialized);
+
+MOZ_MUST_USE bool
+DeserializeModule(JSContext* cx, const Bytes& serialized, MutableHandleObject module);
+
 // These accessors can be used to probe JS values for being an exported wasm
 // function.
 
 extern bool
 IsExportedFunction(JSFunction* fun);
 
 extern bool
 IsExportedWasmFunction(JSFunction* fun);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1482403-1-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <title>Bug 1482403</title>
+    <style type="text/css">
+    #col2 {
+        display: inline-block;
+        height: 35px;
+        background: orange;
+        filter: sepia(0.2);
+    }
+
+    #subnav {
+        display: block;
+        position: absolute;
+        top: 25px;
+        left: 0;
+    }
+    </style>
+</head>
+
+<body>
+    <div>Column 1</div>
+    <div id="col2">Column 2
+        <div id="subnav" style="">
+            <ul>
+                <li>Item 1</li>
+                <li>Item 2</li>
+            </ul>
+        </div>
+    </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1482403-1.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <title>Bug 1482403</title>
+    <style type="text/css">
+    #col2 {
+        display: inline-block;
+        height: 35px;
+        background: orange;
+        filter: sepia(0.2);
+    }
+
+    #subnav {
+        display: none;
+        position: absolute;
+        top: 25px;
+        left: 0;
+    }
+    </style>
+    <script type="text/javascript">
+    function doTest() {
+      var col2 = document.getElementById('col2');
+      var subnav = document.getElementById('subnav');
+      subnav.style.display = 'block';
+      document.documentElement.className = "";
+    }
+
+    window.addEventListener("MozReftestInvalidate", doTest);
+    </script>
+</head>
+
+<body>
+    <div>Column 1</div>
+    <div id="col2">Column 2
+        <div id="subnav" style="">
+            <ul>
+                <li>Item 1</li>
+                <li>Item 2</li>
+            </ul>
+        </div>
+    </div>
+</body>
+</html>
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -30,8 +30,9 @@ skip-if(!asyncPan) == 1437374-1.html 143
 == 1443027-2.html 1443027-ref.html
 == 1443027-3.html 1443027-3-ref.html
 == 1451971-1.html 1451971-ref.html
 == 1453541-1.html 1453541-ref.html
 == 1453541-2.html 1453541-ref.html
 == 1452805-1.html 1452805-ref.html
 == 1461231-1.html about:blank
 fuzzy(0-2,0-40000) skip-if(!asyncPan) == 1464288-1.html 1464288-ref.html
+== 1482403-1.html 1482403-1-ref.html
--- a/layout/tools/reftest/reftest.jsm
+++ b/layout/tools/reftest/reftest.jsm
@@ -300,16 +300,20 @@ function InitAndStartRefTests()
         //g.browser.loadURI('data:text/plain,' + ex);
         ++g.testResults.Exception;
         logger.error("EXCEPTION: " + ex);
         DoneTests();
     }
 
     // Focus the content browser.
     if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
+        var fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+        if (fm.activeWindow != g.containingWindow) {
+            Focus();
+        }
         g.browser.addEventListener("focus", ReadTests, true);
         g.browser.focus();
     } else {
         ReadTests();
     }
 }
 
 function StartHTTPServer()
--- a/testing/web-platform/meta/hr-time/idlharness.any.js.ini
+++ b/testing/web-platform/meta/hr-time/idlharness.any.js.ini
@@ -1,46 +1,19 @@
 [idlharness.any.worker.html]
-  [Test default toJSON operation of Performance]
-    expected: FAIL
-
-  [Performance interface: operation toJSON()]
-    expected: FAIL
-
-  [Performance interface: performance must inherit property "toJSON()" with the proper type]
-    expected: FAIL
-
   [WorkerGlobalScope interface: attribute performance]
     expected: FAIL
 
 
 [idlharness.any.sharedworker.html]
-  [Test default toJSON operation of Performance]
-    expected: FAIL
-
-  [Performance interface: operation toJSON()]
-    expected: FAIL
-
-  [Performance interface: performance must inherit property "toJSON()" with the proper type]
-    expected: FAIL
-
   [WorkerGlobalScope interface: attribute performance]
     expected: FAIL
 
 
 [idlharness.any.html]
 
 [idlharness.https.any.serviceworker.html]
   expected: TIMEOUT
 
 [idlharness.any.serviceworker.html]
-  [Performance interface: operation toJSON()]
-    expected: FAIL
-
-  [Performance interface: performance must inherit property "toJSON()" with the proper type]
-    expected: FAIL
-
-  [Test default toJSON operation of Performance]
-    expected: FAIL
-
   [WorkerGlobalScope interface: attribute performance]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/workers/worker-performance.worker.js.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-prefs: [privacy.reduceTimerPrecision:false]
-[worker-performance.worker.html]
-  [performance.toJSON is available in workers]
-    expected: FAIL
-
--- a/toolkit/components/aboutperformance/content/aboutPerformance.js
+++ b/toolkit/components/aboutperformance/content/aboutPerformance.js
@@ -1092,17 +1092,17 @@ var View = {
 };
 
 var Control = {
   _openItems: new Set(),
   init() {
     this._initAutorefresh();
     this._initDisplayMode();
     let tbody = document.getElementById("dispatch-tbody");
-    tbody.addEventListener("click", () => {
+    tbody.addEventListener("click", event => {
       this._updateLastMouseEvent();
 
       // Handle showing or hiding subitems of a row.
       let target = event.target;
       if (target.classList.contains("twisty")) {
         let row = target.parentNode.parentNode;
         let id = row.windowId;
         if (target.classList.toggle("open")) {
@@ -1149,17 +1149,17 @@ var Control = {
         row.setAttribute("selected", "true");
         this.selectedRow = row;
       } else if (this.selectedRow) {
         this.selectedRow = null;
       }
     });
 
     // Select the tab of double clicked items.
-    tbody.addEventListener("dblclick", () => {
+    tbody.addEventListener("dblclick", event => {
       let id = parseInt(event.target.parentNode.windowId);
       if (isNaN(id))
         return;
       let found = tabFinder.get(id);
       if (!found || !found.tabbrowser)
         return;
       let {tabbrowser, tab} = found;
       tabbrowser.selectedTab = tab;
--- a/toolkit/themes/windows/global/toolbarbutton.css
+++ b/toolkit/themes/windows/global/toolbarbutton.css
@@ -50,20 +50,16 @@ toolbarbutton[disabled="true"] {
   }
 
   :root[lwtheme-image] toolbarbutton:not([disabled="true"]) {
     text-shadow: inherit;
   }
 }
 
 @media (-moz-windows-default-theme: 0) {
-  :root[lwtheme-image] toolbarbutton {
-    -moz-appearance: none;
-  }
-
   :root[lwtheme-image] toolbarbutton:not([disabled="true"]) {
     text-shadow: inherit;
   }
 }
 
 /* ::::: toolbarbutton menu ::::: */
 
 .toolbarbutton-menu-dropmarker {