Merge autoland to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 20 Sep 2017 14:07:40 -0700
changeset 431551 319a34bea9e4f3459886b5b9e835bd338320f1fd
parent 431457 469eb992a9d166004f2601ce725786f671219054 (current diff)
parent 431550 fc0e284fb21bbb2524a16f60a04a806d3b905d1f (diff)
child 431554 61340c7debf6dccec3b863d1bc00426feac42fe7
push id7784
push userryanvm@gmail.com
push dateThu, 21 Sep 2017 00:40:13 +0000
treeherdermozilla-beta@efff4f307675 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone57.0a1
first release with
nightly linux32
319a34bea9e4 / 57.0a1 / 20170920220431 / files
nightly linux64
319a34bea9e4 / 57.0a1 / 20170920220431 / files
nightly mac
319a34bea9e4 / 57.0a1 / 20170920220431 / files
nightly win32
319a34bea9e4 / 57.0a1 / 20170920220431 / files
nightly win64
319a34bea9e4 / 57.0a1 / 20170920220431 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to central, a=merge MozReview-Commit-ID: Ig0M9uJNdeM
browser/base/content/defaultthemes/compactdark.icon.svg
browser/base/content/defaultthemes/compactlight.icon.svg
browser/components/places/tests/chrome/test_RecentBookmarksMenuUI.xul
browser/themes/shared/aboutRights.css
taskcluster/taskgraph/transforms/toolchain.py
testing/talos/talos/tests/perf-reftest/bloom_basic.manifest
testing/talos/talos/tests/perf-reftest/bloom_basic_ref.manifest
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -216,19 +216,16 @@ pref("browser.eme.ui.enabled", false);
 pref("browser.uitour.enabled", true);
 pref("browser.uitour.loglevel", "Error");
 pref("browser.uitour.requireSecure", true);
 pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
 pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
 // How long to show a Hearbeat survey (two hours, in seconds)
 pref("browser.uitour.surveyDuration", 7200);
 
-pref("browser.customizemode.tip0.shown", false);
-pref("browser.customizemode.tip0.learnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/customize");
-
 pref("keyword.enabled", true);
 pref("browser.fixup.domainwhitelist.localhost", true);
 
 pref("general.useragent.locale", "@AB_CD@");
 pref("general.skins.selectedSkin", "classic/1.0");
 
 pref("general.smoothScroll", true);
 #ifdef UNIX_BUT_NOT_MAC
@@ -494,18 +491,16 @@ pref("browser.ctrlTab.previews", false);
 pref("browser.bookmarks.autoExportHTML",          false);
 
 // The maximum number of daily bookmark backups to
 // keep in {PROFILEDIR}/bookmarkbackups. Special values:
 // -1: unlimited
 //  0: no backups created (and deletes all existing backups)
 pref("browser.bookmarks.max_backups",             15);
 
-pref("browser.bookmarks.showRecentlyBookmarked",  true);
-
 // Whether menu should close after Ctrl-click, middle-click, etc.
 pref("browser.bookmarks.openInTabClosesMenu", true);
 
 // Scripts & Windows prefs
 pref("dom.disable_open_during_load",              true);
 pref("javascript.options.showInConsole",          true);
 #ifdef DEBUG
 pref("general.warnOnAboutConfig",                 false);
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -157,17 +157,20 @@
         if (cssClass == "badStsCert") {
           document.getElementById("badStsCertExplanation").removeAttribute("hidden");
         }
       }
 
       function initPage() {
         var err = getErrorCode();
         // List of error pages with an illustration.
-        let illustratedErrors = ["malformedURI", "dnsNotFound"];
+        let illustratedErrors = [
+          "malformedURI", "dnsNotFound", "connectionFailure", "netInterrupt",
+          "netTimeout", "netReset", "netOffline",
+        ];
         if (illustratedErrors.includes(err)) {
           document.body.classList.add("illustrated", err);
         }
 
         gIsCertError = (err == "nssBadCert");
         // Only worry about captive portals if this is a cert error.
         let showCaptivePortalUI = isCaptive() && gIsCertError;
         if (showCaptivePortalUI) {
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -420,20 +420,16 @@
                    oncommand="return FeedHandler.subscribeToFeed(null, event);"
                    onclick="checkForMiddleClick(this, event);"/>
       </menu>
       <menuitem id="menu_bookmarkAllTabs"
                 label="&addCurPagesCmd.label;"
                 class="show-only-for-keyboard"
                 command="Browser:BookmarkAllTabs"
                 key="bookmarkAllTabsKb"/>
-      <menuseparator/>
-      <menuitem label="&recentBookmarks.label;"
-                id="menu_recentBookmarks"
-                disabled="true"/>
       <menuseparator id="bookmarksToolbarSeparator"/>
       <menu id="bookmarksToolbarFolderMenu"
             class="menu-iconic bookmark-item"
             label="&personalbarCmd.label;"
             container="true">
         <menupopup id="bookmarksToolbarFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1276,267 +1276,16 @@ var PlacesToolbarHelper = {
       if (this._viewElt._placesView) {
         this._viewElt._placesView.uninit();
       }
       this.init();
     }
   },
 };
 
-var RecentBookmarksMenuUI = {
-  RECENTLY_BOOKMARKED_PREF: "browser.bookmarks.showRecentlyBookmarked",
-  MAX_RESULTS: 5,
-  // This timeout affects how soon the recent menu items are updated when
-  // an onItemRemoved notification is received - when we receive a notification,
-  // we delay updating the UI in case another is received. If one is, then we
-  // we'll restart the wait again. It wants to be more than 16ms (60fps) but
-  // probably less than 100ms.
-  ITEM_REMOVED_TIMEOUT: 40,
-
-  _recentGuids: undefined,
-  _visible: undefined,
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsINavBookmarkObserver,
-    Ci.nsIObserver,
-    Ci.nsISupportsWeakReference
-  ]),
-
-  get visible() {
-    return this._visible;
-  },
-
-  /**
-   * Set the visibility of the recently bookmarked menu items.
-   *
-   * @param {Boolean} show Set to true to show the menu items, false otherwise.
-   */
-  set visible(visible) {
-    // If we're not changing anything, bail early so that we're not unnecessarily
-    // doing things we don't need to.
-    if (visible == this._visible) {
-      return;
-    }
-
-    this._visible = visible;
-    Services.prefs.setBoolPref(this.RECENTLY_BOOKMARKED_PREF, visible);
-    this._clearExistingItems();
-
-    if (visible) {
-      this._insertRecentMenuItems();
-    }
-  },
-
-  /**
-   * Observer for observing pref changes.
-   */
-  observe(subject, topic, data) {
-    if (topic == "nsPref:changed" && data == this.RECENTLY_BOOKMARKED_PREF) {
-      this.visible = Services.prefs.getBoolPref(this.RECENTLY_BOOKMARKED_PREF, true);
-    }
-  },
-
-  /**
-   * Initializes the recent bookmarks menu items into a menu.
-   *
-   * @param {menuitem} aHeaderItem A DOM menuitem to insert the recent bookmarks
-   *                               into.
-   * @param {String} aExtraCSSClass Any extra CSS classes to insert onto the recent
-   *                                bookmark menuitems.
-   */
-  init(aHeaderItem, aExtraCSSClass = "") {
-    this.headerItem = aHeaderItem;
-    this.extraCSSClass = aExtraCSSClass;
-    this._recentGuids = new Set();
-
-    // This also displays the initial list if necessary.
-    this.visible = Services.prefs.getBoolPref(this.RECENTLY_BOOKMARKED_PREF, true);
-
-    // Add observers and listeners and remove them again when the menupopup closes.
-
-    let bookmarksMenu = aHeaderItem.parentNode;
-    let placesContextMenu = document.getElementById("placesContext");
-
-    let onPlacesContextMenuShowing = event => {
-      if (event.target == event.currentTarget) {
-        let triggerPopup = event.target.triggerNode;
-        while (triggerPopup && triggerPopup.localName != "menupopup") {
-          triggerPopup = triggerPopup.parentNode;
-        }
-        let shouldHidePrefUI = triggerPopup != bookmarksMenu;
-        this._updatePlacesContextMenu(shouldHidePrefUI);
-      }
-    };
-
-    let onBookmarksMenuHidden = event => {
-      // If hide event is not targeted to the main menu (e.g. hiding a sub-menu),
-      // nothing to do.
-      if (event.target != event.currentTarget) {
-        return;
-      }
-
-      // Cancel any item removed timers.
-      if (this._itemRemovedTimer) {
-        clearTimeout(this._itemRemovedTimer);
-      }
-
-      this._updatePlacesContextMenu(true);
-
-      Services.prefs.removeObserver(this.RECENTLY_BOOKMARKED_PREF, this);
-      PlacesUtils.bookmarks.removeObserver(this);
-      this._recentlyBookmarkedObserver = null;
-      if (placesContextMenu) {
-        placesContextMenu.removeEventListener("popupshowing", onPlacesContextMenuShowing);
-      }
-      bookmarksMenu.removeEventListener("popuphidden", onBookmarksMenuHidden);
-
-      this._visible = undefined;
-      delete this.headerItem;
-      delete this.extraCSSClass;
-    };
-
-    Services.prefs.addObserver(this.RECENTLY_BOOKMARKED_PREF, this, true);
-    PlacesUtils.bookmarks.addObserver(this, true);
-
-    // The context menu doesn't exist in non-browser windows on Mac
-    if (placesContextMenu) {
-      placesContextMenu.addEventListener("popupshowing", onPlacesContextMenuShowing);
-    }
-
-    bookmarksMenu.addEventListener("popuphidden", onBookmarksMenuHidden);
-  },
-
-  /**
-   * Clears existing recent items from the menu and updates the separators
-   * according to this.visible.
-   */
-  _clearExistingItems() {
-    this._recentGuids.clear();
-
-    while (this.headerItem.nextSibling &&
-           this.headerItem.nextSibling.localName == "menuitem") {
-      this.headerItem.nextSibling.remove();
-    }
-
-    let separator = this.headerItem.previousSibling;
-    this.headerItem.hidden = !this.visible;
-    separator.hidden = !this.visible;
-  },
-
-  /**
-   * Inserts recent bookmark items into the menu.
-   */
-  _insertRecentMenuItems() {
-    let separator = this.headerItem.previousSibling;
-    this.headerItem.hidden = !this.visible;
-    separator.hidden = !this.visible;
-
-    let options = PlacesUtils.history.getNewQueryOptions();
-    options.excludeQueries = true;
-    options.queryType = options.QUERY_TYPE_BOOKMARKS;
-    options.sortingMode = options.SORT_BY_DATEADDED_DESCENDING;
-    options.maxResults = this.MAX_RESULTS;
-    let query = PlacesUtils.history.getNewQuery();
-
-    let sh = Cc["@mozilla.org/network/serialization-helper;1"]
-               .getService(Ci.nsISerializationHelper);
-    let loadingPrincipal = sh.serializeToString(document.nodePrincipal);
-
-    let fragment = document.createDocumentFragment();
-    let root = PlacesUtils.history.executeQuery(query, options).root;
-    root.containerOpen = true;
-    for (let i = 0; i < root.childCount; i++) {
-      let node = root.getChild(i);
-      let uri = node.uri;
-      let title = node.title;
-      let icon = node.icon;
-
-      let item =
-        document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
-                                 "menuitem");
-      item.setAttribute("label", title || uri);
-      item.setAttribute("targetURI", uri);
-      item.setAttribute("simulated-places-node", true);
-      item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
-                                 this.extraCSSClass);
-      if (icon) {
-        item.setAttribute("image", icon);
-        item.setAttribute("loadingprincipal", loadingPrincipal);
-      }
-      item._placesNode = node;
-      fragment.appendChild(item);
-      this._recentGuids.add(node.bookmarkGuid);
-    }
-    root.containerOpen = false;
-    this.headerItem.parentNode.insertBefore(fragment, this.headerItem.nextSibling);
-  },
-
-  /**
-   * Show the places related context menu for the bookmark items.
-   *
-   * @param {Boolean} shouldHidePrefUI Set to true to hide the UI for switching
-   *                                   the showRecentlyBookmarked pref.
-   */
-  _updatePlacesContextMenu(shouldHidePrefUI = false) {
-    let showItem = document.getElementById("placesContext_showRecentlyBookmarked");
-    // On Mac the menuitem doesn't exist when we're in the Library window context.
-    if (!showItem) {
-      return;
-    }
-    let hideItem = document.getElementById("placesContext_hideRecentlyBookmarked");
-    let separator = document.getElementById("placesContext_recentlyBookmarkedSeparator");
-    let prefEnabled = !shouldHidePrefUI && Services.prefs.getBoolPref(this.RECENTLY_BOOKMARKED_PREF);
-    showItem.hidden = shouldHidePrefUI || prefEnabled;
-    hideItem.hidden = shouldHidePrefUI || !prefEnabled;
-    separator.hidden = shouldHidePrefUI;
-    if (!shouldHidePrefUI) {
-      // Move to the bottom of the menu.
-      separator.parentNode.appendChild(separator);
-      showItem.parentNode.appendChild(showItem);
-      hideItem.parentNode.appendChild(hideItem);
-    }
-  },
-
-  /**
-   * nsINavBookmarkObserver methods.
-   */
-
-  /*
-   * Handles onItemRemoved notifications from the bookmarks service.
-   */
-  onItemRemoved(itemId, parentId, index, itemType, uri, guid) {
-    if (!this.visible) {
-      return;
-    }
-    // Update the menu when a bookmark has been removed.
-    // The native menubar on Mac doesn't support live update, so this is
-    // unlikely to be called there.
-    if (guid && this._recentGuids.has(guid)) {
-      if (this._itemRemovedTimer) {
-        clearTimeout(this._itemRemovedTimer);
-      }
-
-      this._itemRemovedTimer = setTimeout(() => {
-        this._clearExistingItems();
-        this._insertRecentMenuItems();
-      }, this.ITEM_REMOVED_TIMEOUT);
-    }
-  },
-
-  skipTags: true,
-  skipDescendantsOnItemRemoval: false,
-
-  onBeginUpdateBatch() {},
-  onEndUpdateBatch() {},
-  onItemAdded() {},
-  onItemChanged() {},
-  onItemVisited() {},
-  onItemMoved() {},
-}
-
 /**
  * Handles the Library button in the toolbar.
  */
 var LibraryUI = {
   triggerLibraryAnimation(animation) {
     if (!this.hasOwnProperty("COSMETIC_ANIMATIONS_ENABLED")) {
       XPCOMUtils.defineLazyPreferenceGetter(this, "COSMETIC_ANIMATIONS_ENABLED",
         "toolkit.cosmeticAnimations.enabled", true);
@@ -1718,18 +1467,16 @@ var BookmarkingUI = {
       // Don't open a popup in the overflow popup, rather just open the Library.
       event.preventDefault();
       widget.node.removeAttribute("closemenu");
       PlacesCommandHook.showPlacesOrganizer("BookmarksMenu");
       return;
     }
 
     this._initMobileBookmarks(document.getElementById("BMB_mobileBookmarks"));
-    RecentBookmarksMenuUI.init(document.getElementById("BMB_recentBookmarks"),
-                               "subviewbutton");
 
     if (!this._popupNeedsUpdate)
       return;
     this._popupNeedsUpdate = false;
 
     let popup = event.target;
     let getPlacesAnonymousElement =
       aAnonId => document.getAnonymousElementByAttribute(popup.parentNode,
@@ -1955,17 +1702,16 @@ var BookmarkingUI = {
   onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
     // Don't handle events for submenus.
     if (event.target != event.currentTarget)
       return;
 
     this.updateBookmarkPageMenuItem();
     PlacesCommandHook.updateBookmarkAllTabsCommand();
     this._initMobileBookmarks(document.getElementById("menu_mobileBookmarks"));
-    RecentBookmarksMenuUI.init(document.getElementById("menu_recentBookmarks"));
   },
 
   _showBookmarkedNotification: function BUI_showBookmarkedNotification() {
     function getCenteringTransformForRects(rectToPosition, referenceRect) {
       let topDiff = referenceRect.top - rectToPosition.top;
       let leftDiff = referenceRect.left - rectToPosition.left;
       let heightDiff = referenceRect.height - rectToPosition.height;
       let widthDiff = referenceRect.width - rectToPosition.width;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -388,35 +388,17 @@
                onpopuphiding="if (event.target != this)
                                 return;
                               gContextMenu.hiding();
                               gContextMenu = null;
                               updateEditUIVisibility();">
 #include browser-context.inc
     </menupopup>
 
-    <menupopup id="placesContext">
-      <menuseparator id="placesContext_recentlyBookmarkedSeparator"
-                     ignoreitem="true"
-                     hidden="true"/>
-      <menuitem id="placesContext_hideRecentlyBookmarked"
-                label="&hideRecentlyBookmarked.label;"
-                accesskey="&hideRecentlyBookmarked.accesskey;"
-                oncommand="RecentBookmarksMenuUI.visible = false;"
-                closemenu="single"
-                ignoreitem="true"
-                hidden="true"/>
-      <menuitem id="placesContext_showRecentlyBookmarked"
-                label="&showRecentlyBookmarked.label;"
-                accesskey="&showRecentlyBookmarked.accesskey;"
-                oncommand="RecentBookmarksMenuUI.visible = true;"
-                closemenu="single"
-                ignoreitem="true"
-                hidden="true"/>
-    </menupopup>
+    <menupopup id="placesContext"/>
 
     <panel id="ctrlTab-panel" hidden="true" norestorefocus="true" level="top">
       <hbox>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
@@ -1110,21 +1092,16 @@
           </menuitem>
           <!-- NB: temporary solution for bug 985024, this should go away soon. -->
           <menuitem id="BMB_bookmarksShowAllTop"
                     class="menuitem-iconic subviewbutton"
                     label="&showAllBookmarks2.label;"
                     command="Browser:ShowAllBookmarks"
                     key="manBookmarkKb"/>
           <menuseparator/>
-          <menuitem label="&recentBookmarks.label;"
-                    id="BMB_recentBookmarks"
-                    disabled="true"
-                    class="menuitem-iconic subviewbutton"/>
-          <menuseparator/>
           <menu id="BMB_bookmarksToolbar"
                 class="menu-iconic bookmark-item subviewbutton"
                 label="&personalbarCmd.label;"
                 container="true">
             <menupopup id="BMB_bookmarksToolbarPopup"
                        placespopup="true"
                        context="placesContext"
                        onpopupshowing="if (!this.parentNode._placesView)
--- a/browser/base/content/default-theme-icon.svg
+++ b/browser/base/content/default-theme-icon.svg
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
-    <rect fill="#fff" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-    <path fill="#e3e3e3" d="M3 1h26a2 2 0 0 1 2 2v18H1V3a2 2 0 0 1 2-2z"/>
-    <rect stroke="gray" fill="#fff" x="10.5" y="5.5" width="18" height="11" rx="1" ry="1"/>
-    <circle fill="#fcfcfc" stroke="gray" stroke-width="1.2px" cx="11" cy="11" r="7.5"/>
-    <path fill="#595959" d="M14 10h-3.6l1.3-1.3a1 1 0 0 0-1.4-1.4l-3 3a1 1 0 0 0 0 1.4l3 3a1 1 0 0 0 1.4-1.4L10.4 12H14a1 1 0 0 0 0-2z"/>
-    <path fill="none" stroke="#999" d="M1.5 20.5h29"/>
-    <rect fill="none" stroke="#999" stroke-width="2" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
+  <path fill="#202340" d="M2 2h14v13H2z"/>
+  <path fill="#f9f9fa" d="M16 2v13H2v15h28V2H16z"/>
+  <rect x="1" y="1" width="30" height="30" rx="2" ry="2" fill="none" stroke="#08091a" stroke-opacity=".35" stroke-width="2"/>
+  <circle cx="9.5" cy="22.5" r="6" fill="#fff" stroke="#adadb3"/>
+  <path d="M12.5 22H7.707l2.146-2.146a.5.5 0 0 0-.707-.707l-3 3a.5.5 0 0 0 0 .708l3 3a.5.5 0 1 0 .707-.707L7.707 23H12.5a.5.5 0 0 0 0-1z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path d="M20.5 20h4a.5.5 0 0 0 0-1h-4a.5.5 0 0 0 0 1zm4 2h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1zm0 3h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path fill="#0a84ff" d="M16 2h14v1H16z"/>
+  <path d="M26.354 8.646l-3.5-3.5a.5.5 0 0 0-.707 0l-3.5 3.5a.5.5 0 0 0 .707.707L20 8.707V11.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V8.707l.646.646a.5.5 0 1 0 .707-.707zM24 11h-1V9h-1v2h-1V7.707l1.5-1.5 1.5 1.5z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path fill="#08091a" d="M15 2v12H2v1h14V2h-1z"/>
+</svg>
\ No newline at end of file
rename from browser/base/content/defaultthemes/compactdark.icon.svg
rename to browser/base/content/defaultthemes/dark.icon.svg
--- a/browser/base/content/defaultthemes/compactdark.icon.svg
+++ b/browser/base/content/defaultthemes/dark.icon.svg
@@ -1,16 +1,11 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
-    <rect fill="#727780" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-    <path fill="#393f4c" d="M3 1h26a2 2 0 0 1 2 2v14H1V3a2 2 0 0 1 2-2z"/>
-    <rect fill="#171b1f" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
-    <path fill="#252c33" d="M4.5 3.5h12v11h-12a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1z"/>
-    <rect stroke="#1d2328" fill="none" stroke-width="2" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-    <path class="icon-line-2px" d="M10 6L7 9l3 3M7.5 9H13"/>
-    <path stroke="#1d2328" d="M1.5 16.5h29"/>
-    <path class="separator-toolbar-items" d="M16.5 3.5v11"/>
-    <rect fill="none" stroke="#171b1f" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
-    <path fill="#f0f1f2" d="M13 8H9.4l1.3-1.3a1 1 0 0 0-1.4-1.4l-3 3a1 1 0 0 0 0 1.4l3 3a1 1 0 0 0 1.4-1.4L9.4 10H13a1 1 0 0 0 0-2z"/>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
+  <path fill="#0c0c0d" d="M2 2h14v13H2z"/>
+  <path fill="#323234" d="M16 2v13H2v15h28V2H16z"/>
+  <rect x="1" y="1" width="30" height="30" rx="2" ry="2" fill="none" stroke="#08091a" stroke-opacity=".35" stroke-width="2"/>
+  <circle cx="9.5" cy="22.5" r="6" fill="#474749" stroke="#08091a"/>
+  <path d="M12.5 22H7.707l2.146-2.146a.5.5 0 0 0-.707-.707l-3 3a.5.5 0 0 0 0 .708l3 3a.5.5 0 1 0 .707-.707L7.707 23H12.5a.5.5 0 0 0 0-1z" fill="#f9f9fa" fill-opacity=".8"/>
+  <path d="M20.5 20h4a.5.5 0 0 0 0-1h-4a.5.5 0 0 0 0 1zm4 2h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1zm0 3h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1z" fill="#f9f9fa" fill-opacity=".8"/>
+  <path fill="#0a84ff" d="M16 2h14v1H16z"/>
+  <path d="M26.354 8.646l-3.5-3.5a.5.5 0 0 0-.707 0l-3.5 3.5a.5.5 0 0 0 .707.707L20 8.707V11.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V8.707l.646.646a.5.5 0 1 0 .707-.707zM24 11h-1V9h-1v2h-1V7.707l1.5-1.5 1.5 1.5z" fill="#f9f9fa" fill-opacity=".8"/>
+  <path fill="#08091a" d="M15 2v12H2v1h14V2h-1z"/>
+</svg>
\ No newline at end of file
rename from browser/base/content/defaultthemes/compactlight.icon.svg
rename to browser/base/content/defaultthemes/light.icon.svg
--- a/browser/base/content/defaultthemes/compactlight.icon.svg
+++ b/browser/base/content/defaultthemes/light.icon.svg
@@ -1,15 +1,11 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
-    <rect fill="#fff" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-    <path fill="#e3e3e3" d="M3 1h26a2 2 0 0 1 2 2v14H1V3a2 2 0 0 1 2-2z"/>
-    <rect fill="#fff" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
-    <path fill="#fcfcfc" d="M4.5 3.5h12v11h-12a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1z"/>
-    <rect fill="none" stroke="#999" stroke-width="2" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
-    <path stroke="#999" d="M1.5 16.5h29"/>
-    <path stroke="#b3b3b3" d="M16.5 3.5v11"/>
-    <rect fill="none" stroke="#b3b3b3" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
-    <path fill="#595959" d="M13 8H9.4l1.3-1.3a1 1 0 0 0-1.4-1.4l-3 3a1 1 0 0 0 0 1.4l3 3a1 1 0 0 0 1.4-1.4L9.4 10H13a1 1 0 0 0 0-2z"/>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
+  <path fill="#e1e1e5" d="M2 2h14v13H2z"/>
+  <path fill="#f9f9fa" d="M16 2v13H2v15h28V2H16z"/>
+  <rect x="1" y="1" width="30" height="30" rx="2" ry="2" fill="none" stroke="#08091a" stroke-opacity=".35" stroke-width="2"/>
+  <circle cx="9.5" cy="22.5" r="6" fill="#fff" stroke="#adadb3"/>
+  <path d="M12.5 22H7.707l2.146-2.146a.5.5 0 0 0-.707-.707l-3 3a.5.5 0 0 0 0 .708l3 3a.5.5 0 1 0 .707-.707L7.707 23H12.5a.5.5 0 0 0 0-1z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path d="M20.5 20h4a.5.5 0 0 0 0-1h-4a.5.5 0 0 0 0 1zm4 2h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1zm0 3h-4a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path fill="#0a84ff" d="M16 2h14v1H16z"/>
+  <path d="M26.354 8.646l-3.5-3.5a.5.5 0 0 0-.707 0l-3.5 3.5a.5.5 0 0 0 .707.707L20 8.707V11.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V8.707l.646.646a.5.5 0 1 0 .707-.707zM24 11h-1V9h-1v2h-1V7.707l1.5-1.5 1.5 1.5z" fill="#0c0c0d" fill-opacity=".8"/>
+  <path fill="#08091a" fill-opacity=".25" d="M15 2v12H2v1h14V2h-1z"/>
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/base/content/illustrations/error-connection-failure.svg
@@ -0,0 +1,49 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" viewBox="0 0 300 300">
+  <defs>
+    <linearGradient id="a" x1="-300.021" y1="-272.736" x2="547.138" y2="574.423" gradientUnits="userSpaceOnUse">
+      <stop offset="0" stop-color="#ccfbff"/>
+      <stop offset="1" stop-color="#c9e4ff"/>
+    </linearGradient>
+    <linearGradient id="b" x1="-18.672" y1="23.78" x2="279.805" y2="322.256" gradientUnits="userSpaceOnUse">
+      <stop offset="0" stop-color="#00c8d7"/>
+      <stop offset="1" stop-color="#0a84ff"/>
+    </linearGradient>
+  </defs>
+  <path d="M224.245 144.067h-10.733c.136.343.274.674.41 1h10.323a.5.5 0 0 0 0-1zm2.454-11.821a.5.5 0 0 0-.5-.5h-20.26c.373.357.727.688 1.065 1h19.2a.5.5 0 0 0 .496-.5zm8.546 11.821h-3a.5.5 0 1 0 0 1h3a.5.5 0 0 0 0-1zm5 0h-1a.5.5 0 1 0 0 1h1a.5.5 0 0 0 0-1zm-3.3-6.66h-25.78a12.767 12.767 0 0 1 .862 2h24.918a1 1 0 0 0 0-2zm20.422 6.66h-8.122a.5.5 0 1 0 0 1h8.122a.5.5 0 0 0 0-1z" fill="#eaeaee"/>
+  <path d="M269.53 87.757h-24.236c-2.108-3.9-7.559-12.718-14.4-14.023-8.952-1.707-10.737 7.217-10.737 7.217s-5.949-15.468-21-13.419c-16.878 2.3-8.928 20.065-8.928 20.065h-25.408l8.181.159h-8.184a1 1 0 0 0 0 2H269.53a1 1 0 0 0 0-2z" fill="#fff"/>
+  <path d="M118.373 63.908h-13.69c-1.129-2.112-4.19-7.156-8.057-7.894-4.978-.949-5.971 4.013-5.971 4.013s-3.309-8.6-11.68-7.462c-9.386 1.278-4.965 11.158-4.965 11.158H59.88l9.471.185h-9.212a1 1 0 0 0 0 2h58.233a1 1 0 1 0 0-2z" fill="#fff"/>
+  <ellipse cx="143.566" cy="245.472" rx="55.042" ry="8.362" fill="#eaeaee"/>
+  <path d="M102.31 121.507H60.818a1 1 0 0 0 0 2h41.492a1 1 0 1 0 0-2zM70.336 117.6H82.1a.5.5 0 0 0 0-1H70.336a.5.5 0 0 0 0 1z" fill="#eaeaee"/>
+  <path d="M111.457 174.8h-78.3a1 1 0 0 0 0 2h78.3a1 1 0 1 0 0-2zm-26.742-3.793h1a.5.5 0 0 0 0-1h-1a.5.5 0 0 0 0 1zm10 0h3.1a.5.5 0 0 0 0-1h-3.1a.5.5 0 0 0 0 1zm-17 0h3a.5.5 0 0 0 0-1h-3a.5.5 0 0 0 0 1zm-20 0h12a.5.5 0 0 0 0-1h-12a.5.5 0 0 0 0 1z" fill="#eaeaee"/>
+  <path d="M206.885 62.973l.045-.1c-.058.027-.063.059-.045.1z" fill="#fff"/>
+  <path d="M77.937 214.941H39.95a1 1 0 1 1 0-2h37.987a1 1 0 1 1 0 2z" fill="#eaeaee"/>
+  <path d="M258.931 214.941h-61.813a1 1 0 0 1 0-2h61.813a1 1 0 0 1 0 2z" fill="#eaeaee"/>
+  <path d="M265.745 85.333h-3a.5.5 0 0 1 0-1h3a.5.5 0 0 1 0 1zm-11 0h-8.07a.5.5 0 0 1-.447-.277c-.007-.014-.724-1.425-1.979-3.342a.5.5 0 1 1 .837-.548c.393.6 1.444 2.293 1.888 3.167h7.772a.5.5 0 0 1 0 1zm-66.489-.712h-3a.5.5 0 0 1 0-1h3a.5.5 0 0 1 0 1zm-11 0h-12a.5.5 0 0 1 0-1h12a.5.5 0 0 1 0 1zM190.1 83.13a.5.5 0 0 1-.474-.339c-.1-.29-.2-.615-.31-.971a.5.5 0 1 1 .958-.287c.1.343.2.657.3.937a.5.5 0 0 1-.474.661zm30.5-5.156a.5.5 0 0 1-.467-.32 23.7 23.7 0 0 0-2.182-4.039.5.5 0 0 1 .834-.552 27.291 27.291 0 0 1 1.719 2.982 10.522 10.522 0 0 1 3.679-5.015.5.5 0 0 1 .571.82 10.181 10.181 0 0 0-3.665 5.721.5.5 0 0 1-.448.4zm18.345-2.964a.5.5 0 0 1-.339-.132q-.361-.333-.735-.651a.5.5 0 0 1 .647-.762q.39.331.765.678a.5.5 0 0 1-.339.868zm-49.923-1.725a.47.47 0 0 1-.09-.008.5.5 0 0 1-.4-.581c.792-4.351 3.544-7.229 8.18-8.556a.5.5 0 0 1 .275.962c-4.24 1.212-6.753 3.828-7.472 7.773a.5.5 0 0 1-.499.411zm45.893-1.218a.5.5 0 0 1-.237-.06 12.545 12.545 0 0 0-2.666-1.081.5.5 0 1 1 .261-.966 13.559 13.559 0 0 1 2.88 1.167.5.5 0 0 1-.238.94zM212.146 67.4a.5.5 0 0 1-.28-.086q-.4-.27-.82-.524a.5.5 0 1 1 .516-.856q.444.267.865.552a.5.5 0 0 1-.281.914zm-4.47-2.2a.5.5 0 0 1-.154-.024 16.724 16.724 0 0 0-2.832-.647.5.5 0 0 1 .137-.99 17.6 17.6 0 0 1 3 .686.5.5 0 0 1-.154.976z" fill="#eaeaee"/>
+  <path d="M72.315 62.052h-12a.5.5 0 0 1 0-1h12a.5.5 0 0 1 0 1zm45.582-.184h-1.8a.5.5 0 0 1 0-1h1.8a.5.5 0 0 1 0 1zm-10.8 0h-1a.5.5 0 0 1 0-1h1a.5.5 0 0 1 0 1zm-3.491-2.881a.5.5 0 0 1-.39-.186 18.484 18.484 0 0 0-2-2.129.5.5 0 0 1 .668-.744A19.433 19.433 0 0 1 104 58.174a.5.5 0 0 1-.389.814zm-12.521-.631a.5.5 0 0 1-.466-.319 13.8 13.8 0 0 0-3.857-5.165.5.5 0 0 1 .623-.782 14.47 14.47 0 0 1 3.624 4.438A5.414 5.414 0 0 1 94.12 53.5a.5.5 0 1 1 .326.945 4.994 4.994 0 0 0-2.867 3.51.5.5 0 0 1-.49.401zm-17.637-2.037h-.051a.5.5 0 0 1-.447-.548 6.454 6.454 0 0 1 1.057-3.036.5.5 0 1 1 .824.566 5.46 5.46 0 0 0-.886 2.571.5.5 0 0 1-.497.447zm4.193-5.039a.5.5 0 0 1-.151-.977 10.27 10.27 0 0 1 1.017-.264.5.5 0 0 1 .2.979 9.033 9.033 0 0 0-.917.237.5.5 0 0 1-.148.025z" fill="#eaeaee"/>
+  <path d="M216.326 144.72c-1.079-4.2-3.73-8.616-7.88-13.117a84.471 84.471 0 0 0-8.921-9.988 5.558 5.558 0 0 0-2.261-1.3c-7.177-6.885-21.972-19.819-32.5-20.546a27.625 27.625 0 0 0-1.889-.063 47.155 47.155 0 0 0-15.147 2.913l-5.114-1.4a5 5 0 0 0-6.142 3.5l-.969 3.545a68.668 68.668 0 0 0-7.844 5.3l-2.052-.048h-.116a5 5 0 0 0-5 4.884l-.042 1.829a45.575 45.575 0 0 0-5.648 7.656 5 5 0 0 0-2.515 5.326c-1.882 5.474-2.848 13.743-2.875 24.633a100.416 100.416 0 0 1-1.646 7.791l-4.279 2.594a6.312 6.312 0 0 0-2.125 8.657l1.516 2.5q-.375.778-.761 1.518l-4.037 1.24a6.312 6.312 0 0 0-4.176 7.877l.6 1.953q-.516.587-1.038 1.143l-1.616-.127a5.926 5.926 0 0 0-.5-.02 6.334 6.334 0 0 0-6.277 5.8l-.115 1.456c-2.741 2.043-5.415 4.547-5.415 9.117 0 6.528 10.272 10.568 13.648 11.9a68.955 68.955 0 0 0 24.224 4.781q.566 0 1.127-.012c.607 2.411 1.208 4.468 1.8 6.144a54.956 54.956 0 0 0 4.745 10.264c1.748 2.839 4.22 6.1 7.845 6.1a5.673 5.673 0 0 0 3.572-1.268c1.746-1.421 2.429-3.072 2.482-10.087a86.865 86.865 0 0 0 16.862 1.533 80.987 80.987 0 0 0 14.53-1.463c-.215 6.82.472 8.55 2.275 10.017a5.672 5.672 0 0 0 3.571 1.268c5.645 0 9.953-8.9 12.573-16.361a52.867 52.867 0 0 0 1.069-3.467c1.432-3.724 4.539-13.353 4.892-27.476.161-6.428 0-12.95-.488-19.419a7.56 7.56 0 0 0 1.131-4.949c6.461-1.2 10.808-3.919 15.1-9.34 3.4-4.308 8-14.308 5.826-22.788z" fill="#fff"/>
+  <path d="M211.476 145.947c-1.092-4.252-4.261-8.341-6.9-11.168a78.846 78.846 0 0 0-8.482-9.533.649.649 0 0 0-.907.018c-10.173-10.009-23.029-19.987-30.783-20.521-4.534-.313-10.392.808-16.48 3.1l-6.645-1.817-1.521 5.561a63.823 63.823 0 0 0-10.4 7l-3.884-.09-.087 3.744a40.534 40.534 0 0 0-7.123 9.675l-1.083.338.36 1.153c-2.227 5.146-3.144 14.255-3.147 24.842a104.047 104.047 0 0 1-2.33 10.6l-6 3.638a1.452 1.452 0 0 0-.685 1.835l3.021 4.978a54.736 54.736 0 0 1-2.883 5.777l-5.979 1.836a1.305 1.305 0 0 0-.864 1.63l1.394 4.541a51.394 51.394 0 0 1-4.691 5.189l-3.93-.31a1.3 1.3 0 0 0-1.4 1.2l-.3 3.752c-3.258 2.357-5.218 3.541-5.218 6.422 0 4.144 20.8 13.416 37.9 11.39a88.878 88.878 0 0 0 2.615 9.761c2.852 8.125 6.861 14.032 8.287 12.871.675-.549.711-6.554.562-12.73.446.174 8.025 3.054 21.939 3.054a88.332 88.332 0 0 0 19.876-2.718c-.4 5.844-.626 11.816.085 12.394 1.426 1.161 5.418-4.745 8.269-12.871.357-1.018.7-2.159 1.031-3.377 1.276-3.253 4.307-12.338 4.649-26.035a191.885 191.885 0 0 0-.651-21.1 2.592 2.592 0 0 0-.475-4.743 128.961 128.961 0 0 0-.36-2.871 28.465 28.465 0 0 0 4.578-.19c6.147-.82 9.835-2.869 13.728-7.786 2.797-3.536 6.551-12.06 4.914-18.439z" fill="url(#a)"/>
+  <path d="M193.99 124.155c.033.013.067.031.1.045-9.986-9.641-22.2-18.942-29.683-19.457-4.534-.313-10.392.808-16.48 3.1l-6.645-1.817-1.521 5.561a63.823 63.823 0 0 0-10.4 7l-3.884-.09-.087 3.744a40.534 40.534 0 0 0-7.123 9.675l-1.083.338.36 1.153c-2.227 5.146-3.144 14.255-3.147 24.842a109.944 109.944 0 0 1-.921 4.824c.168-.72.327-1.43.475-2.127.061 3.039.177 6.023.332 8.836-1.014 1.2-4.408 5.548-2.546 8.155a10.876 10.876 0 0 0 3.445 2.858c.069.589.138 1.155.209 1.681 1.015 7.544 4.11 29 6.408 38.3.207-.021.417-.036.623-.061a88.878 88.878 0 0 0 2.615 9.761c2.852 8.125 6.861 14.032 8.287 12.871.675-.549.711-6.554.562-12.73.038.015.145.054.283.1V222.3a46 46 0 0 0 27.634 3.451c15.651-3.043 21.467-14.705 22.172-22.607 1.194-13.372-1.415-19.893-1.415-19.893l6.558-2.852c-.011-.135-.022-.284-.034-.417a2.592 2.592 0 0 0-.475-4.743l-11.158 4.316s-.109-1.739-2.5-4.348c-3.174-3.462-10.521-6.355-11.428-6.7a84.091 84.091 0 0 0 24.884 5.065l-.109-.839c-10.706-.609-24.216-5.348-24.216-5.348s23.783 4.316 33.476-.761c6.847-3.587 11.086-13.369 9.456-21.846-1.731-9.023-13.024-20.623-13.024-20.623z" fill="#f9f9fa"/>
+  <path d="M149.523 146.54l-5.537-1.957a1 1 0 0 0-1.219 1.406l1.99 3.81a1 1 0 0 0 1.349.423l3.547-1.853a1 1 0 0 0-.13-1.829z" fill="#fff"/>
+  <g fill="url(#b)">
+    <path d="M268.754 200.7h-.768c-17.152 0-33.29 0-42.937.322-8.333.277-16.774 1.994-16.787 4.736-.008 1.811 4.646 3.3 13.565 5.982 7.387 2.225 17.5 5.271 17.736 7.75a2.9 2.9 0 0 1-1.2 2.046c-2.984 2.772-11.281 5.909-19.089 4.588a25.1 25.1 0 0 1-12.468-6.4c-4.383-3.888-6.191-7.86-7.786-11.364-.619-1.359-1.2-2.643-1.9-3.837a22.145 22.145 0 0 0-5.357-6.126 194.068 194.068 0 0 0-.6-17.308 4.6 4.6 0 0 0-.2-6.523c.75-.036 1.463-.1 2.13-.188 6.749-.9 10.823-3.211 15.032-8.527 3.282-4.146 7.092-13.147 5.287-20.18-1.2-4.662-4.606-9.055-7.29-11.947a80.769 80.769 0 0 0-8.657-9.724 2.62 2.62 0 0 0-1.653-.713 133.306 133.306 0 0 0-15.775-13.264c-6.315-4.414-11.527-6.79-15.492-7.064a24.782 24.782 0 0 0-1.683-.056 45.119 45.119 0 0 0-15.027 3.055l-6.025-1.648a2 2 0 0 0-2.457 1.4l-1.3 4.745a65.633 65.633 0 0 0-9.391 6.332l-3.141-.073h-.047a2 2 0 0 0-2 1.953l-.069 2.965a42.572 42.572 0 0 0-6.522 8.837l-.3.093a2 2 0 0 0-1.312 2.506l.145.465c-1.993 5.12-3.01 13.443-3.023 24.766a102.594 102.594 0 0 1-2.05 9.47L105.03 171a3.309 3.309 0 0 0-1.114 4.538l2.345 3.87a56.333 56.333 0 0 1-2.1 4.209l-5.216 1.6a3.309 3.309 0 0 0-2.189 4.129l1.082 3.524a49.795 49.795 0 0 1-3.217 3.554l-3.023-.238a3.177 3.177 0 0 0-.267-.011 3.318 3.318 0 0 0-3.287 3.043l-.223 2.83c-2.965 2.13-5.3 3.833-5.3 7.5 0 2.65 3.4 5.1 6.95 6.946a89.372 89.372 0 0 0-1.57 3.365c-1.866 4.156-3.1 6.9-7.448 8.232-8.459 2.584-20.437.244-26.315-3.564-1.825-1.182-2.9-2.432-3.041-3.519-.264-2.111 5.188-4.187 9.167-5.7 3.919-1.492 6.152-2.394 6.47-3.56a1.66 1.66 0 0 0-.295-1.493C64.48 207.69 53.977 207.22 34 207.22a.5.5 0 0 0 0 1c12.5 0 29.627 0 31.645 2.642a.661.661 0 0 1 .125.623c-.2.732-3.339 1.928-5.861 2.888-5 1.9-10.165 3.871-9.8 6.761.176 1.405 1.382 2.869 3.489 4.234 4.275 2.77 11.581 4.841 18.68 4.841a29.2 29.2 0 0 0 8.471-1.16c4.784-1.462 6.161-4.531 8.068-8.778a89.007 89.007 0 0 1 1.552-3.326 54.676 54.676 0 0 0 3.9 1.709 65.842 65.842 0 0 0 23.126 4.572c1.177 0 2.336-.042 3.462-.126a80.823 80.823 0 0 0 2.292 8.265c.516 1.469 5.171 14.354 9.759 14.354a2.629 2.629 0 0 0 1.678-.595c.831-.677 1.5-1.223 1.353-11.536a76.69 76.69 0 0 0 19.885 2.308 86.392 86.392 0 0 0 17.71-2.167c-.585 10.114.149 10.711.989 11.395a2.628 2.628 0 0 0 1.677.595c4.572 0 9.226-12.885 9.742-14.354.347-.989.7-2.137 1.046-3.412 1.345-3.458 4.4-12.766 4.747-26.612.014-.552.01-1.108.019-1.662a20.857 20.857 0 0 1 4.507 5.34c.668 1.152 1.242 2.415 1.851 3.751 1.636 3.595 3.491 7.669 8.032 11.7a26.054 26.054 0 0 0 12.965 6.641 24.08 24.08 0 0 0 4.006.325c6.5 0 12.949-2.4 15.93-5.166a3.735 3.735 0 0 0 1.514-2.872c-.274-2.93-7.481-5.313-18.444-8.614-5.427-1.634-12.859-3.872-12.854-5.02.006-1.314 5.643-3.4 15.82-3.742 9.631-.321 25.785-.326 42.9-.321h.768a.5.5 0 0 0 0-1zM204.579 135c2.636 2.827 5.805 6.916 6.9 11.168 1.637 6.379-2.117 14.9-4.918 18.441-3.893 4.918-7.581 6.967-13.728 7.786-.7.093-1.432.142-2.179.172a.988.988 0 0 0-.354-.077 73.652 73.652 0 0 1-26.1-5.54 1 1 0 0 0-.826 1.821 74.46 74.46 0 0 0 25.115 5.664c.039.323.08.659.121 1.021a2.579 2.579 0 0 1 1.39 3.874.484.484 0 0 0-.243.11c-1.838 1.634-8.407 3.132-8.474 3.146a.5.5 0 0 0-.113.041l-2.2 1.1a.5.5 0 0 0-.274.5c.006.061.561 6.134-2.275 8.973a5.1 5.1 0 0 1-3.97 1.438l.82-4.449a.5.5 0 0 0-.383-.579l-2.605-.579c-.139-1-.37-4.182 1.943-5.917.976-.731 8.157-3.579 10.842-4.614a.5.5 0 0 0-.359-.933c-1 .386-9.818 3.8-11.082 4.747-3.262 2.447-2.312 7.043-2.27 7.237a.492.492 0 0 0 .107.2q-1.276-.217-2.6-.406c-.048-1.62-.626-3.782-2.151-4.88a3.922 3.922 0 0 0-3.715-.379.507.507 0 0 0-.086.039 5.413 5.413 0 0 0-2.65 4.454c0 2.46 1.4 5.3 3.473 5.614a5.187 5.187 0 0 0 .772.059 4.147 4.147 0 0 0 2.763-1 4.691 4.691 0 0 0 1.526-2.9q2.748.39 5.267.9l-.694 3.765a.5.5 0 0 0 .444.588q.446.043.87.043a6.04 6.04 0 0 0 4.449-1.735 6.78 6.78 0 0 0 .928-1.172 40.237 40.237 0 0 1 11.732 5.419q-.012 1.546-.051 3.143c-.342 13.7-3.374 22.782-4.649 26.035a48.73 48.73 0 0 1-1.031 3.377c-2.611 7.438-6.177 13.017-7.855 13.017a.639.639 0 0 1-.415-.146c-.669-.545-.51-5.868-.153-11.366a19.327 19.327 0 0 0 5.9-3.617.5.5 0 0 0-.717-.7 18.885 18.885 0 0 1-5.594 3.4 87.371 87.371 0 0 1-19.4 2.607c-11.281 0-18.4-1.892-20.923-2.7l-.26-6.109a.5.5 0 1 0-1 .043l.243 5.714c.149 6.176.113 12.181-.562 12.73a.639.639 0 0 1-.415.146c-1.681 0-5.261-5.579-7.872-13.017a88.882 88.882 0 0 1-2.615-9.761h-.005c-2.551-10.248-4.636-21.971-4.657-22.089a.5.5 0 1 0-.984.175c.021.118 2.091 11.756 4.633 22-1.324.122-2.662.2-4.013.2a63.607 63.607 0 0 1-26.1-6.059 44.608 44.608 0 0 1 6.949-9.4c9.072-9.555 18.343-13.569 25.331-15.21a6.619 6.619 0 0 0 2.526 3.172 5.232 5.232 0 0 0 2.774.9 4.77 4.77 0 0 0 3.579-1.983.5.5 0 0 0 .052-.57l-1.467-2.574q2.151-.118 4.317-.032c1.077 3.689 5.807 4.056 5.858 4.06h.033a.5.5 0 0 0 .464-.314 8.392 8.392 0 0 0 .432-1.968h2.691a.5.5 0 1 0 0-1h-2.606a18.073 18.073 0 0 0-.152-3.239h2.437a.5.5 0 0 0 0-1h-2.593a24.74 24.74 0 0 0-.512-2.243.5.5 0 0 0-.564-.359 11.053 11.053 0 0 0-3 1.03c-1.867.989-2.77 2.376-2.658 4.025a46.151 46.151 0 0 0-4.689.068l-.048-.084 2.933-.3a.5.5 0 0 0 .449-.484c.005-.2.1-4.931-2.952-6.689-1.677-.968-11.4-4.872-11.818-5.037a.5.5 0 0 0-.372.928c.1.041 10.074 4.043 11.69 4.976 2.05 1.183 2.388 4.223 2.442 5.359l-3.237.333a.5.5 0 0 0-.383.745l2.271 3.988c-1.076 1.186-2.506 2.067-4.831.615-3.425-2.138-3.069-8.563-3.019-9.262 0-.022.005-.044 0-.066v-.007a.5.5 0 0 0-.052-.266.985.985 0 0 0-.548-.63c-.037-.016-3.859-1.7-7.521-3.205-3.062-1.261-3.5-3.464-3.524-3.584a1 1 0 0 0-1.975.313c.021.138.568 3.4 4.738 5.121 3.645 1.5 7.452 3.176 7.488 3.191.056.024.2.091.35.158a17.069 17.069 0 0 0 .664 4.966c-7.122 1.693-16.53 5.791-25.719 15.47a45.518 45.518 0 0 0-7.118 9.64c-3.625-1.887-5.88-3.8-5.88-5.166 0-2.882 1.96-4.065 5.218-6.422l.3-3.752a1.306 1.306 0 0 1 1.293-1.2h.11l2.534.2a15.544 15.544 0 0 1-1.922 1.463.5.5 0 0 0 .545.839 15.693 15.693 0 0 0 2.715-2.2h.058a51.394 51.394 0 0 0 4.691-5.189l-1.394-4.541a1.305 1.305 0 0 1 .864-1.63l4.352-1.336-1.57 2.34a.5.5 0 1 0 .83.558l2.256-3.363.111-.034a59.576 59.576 0 0 0 3-6.032l-2.884-4.76a1.305 1.305 0 0 1 .439-1.792l4.593-2.784-.9 2.5a.5.5 0 0 0 .941.338l1.316-3.665.051-.031c.038-.137.069-.27.106-.406l.078-.218a.5.5 0 0 0 .027-.185 105.18 105.18 0 0 0 2.119-9.789c0-9.717.779-18.179 2.627-23.484l.683 1.709a.5.5 0 0 0 .929-.371l-1.144-2.862-.308-.986 1.083-.338a39.766 39.766 0 0 1 6.223-8.725 12.852 12.852 0 0 0 .241 1.72.5.5 0 0 0 .629.315.5.5 0 0 0 .32-.631 24.71 24.71 0 0 1-.287-2.484l.084-3.613 3.884.09a63.833 63.833 0 0 1 10.4-7l1.521-5.561 5.138 1.405-2.527 1.118a.5.5 0 1 0 .409.912l3.7-1.659a44.04 44.04 0 0 1 14.851-3.124q.8 0 1.545.052c7.754.535 20.609 10.512 30.783 20.521a.655.655 0 0 1 .465-.193.639.639 0 0 1 .442.176m0 0a78.848 78.848 0 0 1 8.484 9.535m-14.79 61.935a42.035 42.035 0 0 0-11.248-5.1 15.357 15.357 0 0 0 1.207-6.3.955.955 0 0 0 .1.016.989.989 0 0 0 .292-.044l9.149-2.784c.288 4.005.511 8.839.5 14.208z"/>
+    <path d="M193.225 139.669a1.412 1.412 0 0 0 1.41-1.41V135.1a1.41 1.41 0 0 0-2.821 0v3.162a1.412 1.412 0 0 0 1.411 1.407z"/>
+    <path d="M193.225 144.475a5.736 5.736 0 0 0 4.644-2.413 1 1 0 1 0-1.679-1.088 3.76 3.76 0 0 1-2.965 1.5 3.71 3.71 0 0 1-2.969-1.506 1 1 0 0 0-1.675 1.094 5.736 5.736 0 0 0 4.644 2.413z"/>
+    <path d="M163.852 142.719a1 1 0 0 0 1.674-1.094 5.674 5.674 0 0 0-9.286 0 1 1 0 0 0 1.674 1.095 3.679 3.679 0 0 1 5.938 0z"/>
+    <path d="M159.473 135.1v3.162c0 .036.008.07.011.106a6.569 6.569 0 0 1 2.8 0c0-.036.011-.07.011-.106V135.1a1.41 1.41 0 1 0-2.821 0z"/>
+    <path d="M160.912 130.086a5.733 5.733 0 0 0 4.643-2.412 1 1 0 0 0-1.674-1.095 3.679 3.679 0 0 1-5.937 0 1 1 0 0 0-1.674 1.094 5.733 5.733 0 0 0 4.642 2.413z"/>
+    <path d="M155.934 155.646a18.515 18.515 0 0 0-4.51-8.323c-5.144-5.145-12.507-4.867-12.817-4.857a1 1 0 0 0 .089 2 16.68 16.68 0 0 1 3.159.279 18.431 18.431 0 0 0 1.1 3.47 6.118 6.118 0 0 0-1.562.513 7.174 7.174 0 0 0-2.41 2.27.5.5 0 1 0 .84.542 6.254 6.254 0 0 1 2.014-1.917 5.319 5.319 0 0 1 1.6-.478 4.113 4.113 0 0 0 .928 1.091 6.669 6.669 0 0 0-.955 2.347 7.171 7.171 0 0 0 .372 3.29.5.5 0 0 0 .469.326.494.494 0 0 0 .174-.031.5.5 0 0 0 .295-.643 6.214 6.214 0 0 1-.326-2.76 5.734 5.734 0 0 1 .894-2.1 2.673 2.673 0 0 0 .474.054 9.686 9.686 0 0 0 4.458-1.746 16.947 16.947 0 0 1 3.75 7.1 1 1 0 0 0 1.956-.42zm-10.821-6.082c-1.027-.642-1.8-3.029-2.178-4.592a15.045 15.045 0 0 1 6.547 3.285c-1.517.943-3.507 1.843-4.37 1.307z"/>
+    <path d="M193.839 116.06a1 1 0 0 0 .71-.3l2.533-2.554a1 1 0 1 0-1.42-1.408l-2.533 2.554a1 1 0 0 0 .71 1.7z"/>
+    <path d="M199.708 117.691a1 1 0 0 0 .409-.088l3.512-1.576a1 1 0 0 0-.818-1.825l-3.512 1.576a1 1 0 0 0 .41 1.913z"/>
+    <path d="M193.882 183.558a.5.5 0 0 0 .106.988.487.487 0 0 0 .105-.011 5.176 5.176 0 0 0 3-7.9.5.5 0 0 0-.807.591 4.178 4.178 0 0 1-2.41 6.327z"/>
+    <path d="M195.435 187.387a.487.487 0 0 0 .105-.011 7.781 7.781 0 0 0 4.512-11.856.5.5 0 1 0-.807.591 6.884 6.884 0 0 1 .676 6.146 6.8 6.8 0 0 1-4.593 4.142.5.5 0 0 0 .105.989z"/>
+    <path d="M127.087 198.745a5.134 5.134 0 0 0 1.54.239 5.254 5.254 0 0 0 3.143-1.063.5.5 0 0 0-.637-.771 4.178 4.178 0 0 1-6.463-2.021.5.5 0 0 0-.962.271 5.206 5.206 0 0 0 3.379 3.345z"/>
+    <path d="M132.43 200.03a6.783 6.783 0 0 1-10.508-3.284.5.5 0 0 0-.963.27 7.773 7.773 0 0 0 12.108 3.785.5.5 0 0 0-.638-.771z"/>
+  </g>
+  <g fill="#f9f9fa">
+    <path d="M160.366 188.859a.5.5 0 0 1-.43-.754l1.345-2.283a.5.5 0 1 1 .861.508l-1.345 2.283a.5.5 0 0 1-.431.246z"/>
+    <path d="M161.086 192.527a.5.5 0 0 1-.43-.754l1.344-2.282a.5.5 0 1 1 .861.508l-1.345 2.282a.5.5 0 0 1-.43.246z"/>
+  </g>
+</svg>
--- a/browser/base/content/test/general/browser_compacttheme.js
+++ b/browser/base/content/test/general/browser_compacttheme.js
@@ -48,17 +48,17 @@ add_task(async function startTests() {
   ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
 });
 
 function dummyLightweightTheme(id) {
   return {
     id,
     name: id,
     headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
-    iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactlight.icon.svg",
+    iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
     textcolor: "red",
     accentcolor: "blue"
   };
 }
 
 add_task(async function testLightweightThemePreview() {
   if (SKIP_TEST) {
     ok(true, "No need to run this test since themes aren't installed");
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -34,16 +34,17 @@ browser.jar:
         content/browser/abouthome/bookmarks@2x.png     (content/abouthome/bookmarks@2x.png)
         content/browser/abouthome/history@2x.png       (content/abouthome/history@2x.png)
         content/browser/abouthome/addons@2x.png        (content/abouthome/addons@2x.png)
         content/browser/abouthome/sync@2x.png          (content/abouthome/sync@2x.png)
         content/browser/abouthome/settings@2x.png      (content/abouthome/settings@2x.png)
         content/browser/abouthome/restore@2x.png       (content/abouthome/restore@2x.png)
         content/browser/abouthome/restore-large@2x.png (content/abouthome/restore-large@2x.png)
 
+        content/browser/illustrations/error-connection-failure.svg (content/illustrations/error-connection-failure.svg)
         content/browser/illustrations/error-server-not-found.svg (content/illustrations/error-server-not-found.svg)
         content/browser/illustrations/error-malformed-url.svg (content/illustrations/error-malformed-url.svg)
         content/browser/aboutNetError.xhtml            (content/aboutNetError.xhtml)
 
 #ifdef MOZ_SERVICES_HEALTHREPORT
         content/browser/abouthealthreport/abouthealth.xhtml   (content/abouthealthreport/abouthealth.xhtml)
         content/browser/abouthealthreport/abouthealth.js      (content/abouthealthreport/abouthealth.js)
         content/browser/abouthealthreport/abouthealth.css     (content/abouthealthreport/abouthealth.css)
@@ -105,18 +106,18 @@ browser.jar:
         content/browser/defaultthemes/3.preview.png   (content/defaultthemes/3.preview.png)
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
         content/browser/defaultthemes/compact.header.png    (content/defaultthemes/compact.header.png)
-        content/browser/defaultthemes/compactdark.icon.svg  (content/defaultthemes/compactdark.icon.svg)
-        content/browser/defaultthemes/compactlight.icon.svg (content/defaultthemes/compactlight.icon.svg)
+        content/browser/defaultthemes/dark.icon.svg  (content/defaultthemes/dark.icon.svg)
+        content/browser/defaultthemes/light.icon.svg (content/defaultthemes/light.icon.svg)
         content/browser/newtab/newTab.xhtml           (content/newtab/newTab.xhtml)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/alternativeDefaultSites.json   (content/newtab/alternativeDefaultSites.json)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -4,17 +4,16 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["CustomizeMode"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 const kPrefCustomizationDebug = "browser.uiCustomization.debug";
-const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
 const kPaletteId = "customization-palette";
 const kDragDataTypePrefix = "text/toolbarwrapper-id/";
 const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
 const kToolbarVisibilityBtn = "customization-toolbar-visibility-button";
 const kDrawInTitlebarPref = "browser.tabs.drawInTitlebar";
 const kExtraDragSpacePref = "browser.tabs.extraDragSpace";
 const kMaxTransitionDurationMs = 2000;
 const kKeepBroadcastAttributes = "keepbroadcastattributeswhencustomizing";
@@ -54,18 +53,16 @@ XPCOMUtils.defineLazyGetter(this, "log",
   gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false);
   let consoleOptions = {
     maxLogLevel: gDebug ? "all" : "log",
     prefix: "CustomizeMode",
   };
   return new scope.ConsoleAPI(consoleOptions);
 });
 
-var gDisableAnimation = null;
-
 var gDraggingInToolbars;
 
 var gTab;
 
 function closeGlobalTab() {
   let win = gTab.ownerGlobal;
   if (win.gBrowser.browsers.length == 1) {
     win.BrowserOpenTab();
@@ -91,32 +88,27 @@ function unregisterGlobalTab() {
   win.gBrowser.removeTabsProgressListener(gTabsProgressListener);
 
   gTab.removeAttribute("customizemode");
 
   gTab = null;
 }
 
 function CustomizeMode(aWindow) {
-  if (gDisableAnimation === null) {
-    gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
-                        Services.prefs.getBoolPref(kPrefCustomizationAnimation);
-  }
   this.window = aWindow;
   this.document = aWindow.document;
   this.browser = aWindow.gBrowser;
   this.areas = new Set();
 
   // There are two palettes - there's the palette that can be overlayed with
   // toolbar items in browser.xul. This is invisible, and never seen by the
   // user. Then there's the visible palette, which gets populated and displayed
   // to the user when in customizing mode.
   this.visiblePalette = this.document.getElementById(kPaletteId);
   this.paletteEmptyNotice = this.document.getElementById("customization-empty");
-  this.tipPanel = this.document.getElementById("customization-tipPanel");
   if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
     let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
     lwthemeButton.setAttribute("hidden", "true");
   }
   if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
     this._updateTitlebarCheckbox();
     this._updateDragSpaceCheckbox();
     Services.prefs.addObserver(kDrawInTitlebarPref, this);
@@ -394,18 +386,16 @@ CustomizeMode.prototype = {
     }
 
     if (this.resetting) {
       log.debug("Attempted to exit while we're resetting. " +
                 "We'll exit after resetting has finished.");
       return;
     }
 
-    this.hideTip();
-
     this._handler.isExitingCustomizeMode = true;
 
     this._removeExtraToolbarsIfEmpty();
 
     this._teardownDownloadAutoHideToggle();
 
     CustomizableUI.removeListener(this);
 
@@ -551,54 +541,16 @@ CustomizeMode.prototype = {
 
     let deck = this.document.getElementById("tab-view-deck");
     let toolboxRect = this.window.gNavToolbox.getBoundingClientRect();
     let height = toolboxRect.bottom;
     deck.style.setProperty("--toolbox-rect-height", `${height}`);
     deck.style.setProperty("--toolbox-rect-height-with-unit", `${height}px`);
   },
 
-  maybeShowTip(aAnchor) {
-    const kShownPref = "browser.customizemode.tip0.shown";
-    let shown = Services.prefs.getBoolPref(kShownPref, false);
-    if (shown)
-      return;
-
-    let anchorNode = aAnchor || this.document.getElementById("customization-panelHolder");
-    let messageNode = this.tipPanel.querySelector(".customization-tipPanel-contentMessage");
-    if (!messageNode.childElementCount) {
-      // Put the tip contents in the popup.
-      let bundle = this.document.getElementById("bundle_browser");
-      const kLabelClass = "customization-tipPanel-link";
-      // eslint-disable-next-line no-unsanitized/property
-      messageNode.innerHTML = bundle.getFormattedString("customizeTips.tip0", [
-        "<label class=\"customization-tipPanel-em\" value=\"" +
-          bundle.getString("customizeTips.tip0.hint") + "\"/>",
-        this.document.getElementById("bundle_brand").getString("brandShortName"),
-        "<label class=\"" + kLabelClass + " text-link\" value=\"" +
-        bundle.getString("customizeTips.tip0.learnMore") + "\"/>"
-      ]);
-
-      messageNode.querySelector("." + kLabelClass).addEventListener("click", () => {
-        let url = Services.urlFormatter.formatURLPref("browser.customizemode.tip0.learnMoreUrl");
-        let browser = this.browser;
-        browser.selectedTab = browser.addTab(url);
-        this.hideTip();
-      });
-    }
-
-    this.tipPanel.hidden = false;
-    this.tipPanel.openPopup(anchorNode);
-    Services.prefs.setBoolPref(kShownPref, true);
-  },
-
-  hideTip() {
-    this.tipPanel.hidePopup();
-  },
-
   _getCustomizableChildForNode(aNode) {
     // NB: adjusted from _getCustomizableParent to keep that method fast
     // (it's used during drags), and avoid multiple DOM loops
     let areas = CustomizableUI.areas;
     // Caching this length is important because otherwise we'll also iterate
     // over items we add to the end from within the loop.
     let numberOfAreas = areas.length;
     for (let i = 0; i < numberOfAreas; i++) {
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -374,35 +374,16 @@
     <menuseparator/>
     <menuitem command="cmd_CustomizeToolbars"
               class="viewCustomizeToolbar"
               accesskey="&viewCustomizeToolbar.accesskey;"
               label="&viewCustomizeToolbar.label;"/>
   </menupopup>
 </panel>
 
-<panel id="customization-tipPanel"
-       type="arrow"
-       flip="none"
-       side="left"
-       position="leftcenter topright"
-       noautohide="true"
-       hidden="true">
-  <hbox class="customization-tipPanel-wrapper">
-    <vbox class="customization-tipPanel-infoBox"/>
-    <vbox class="customization-tipPanel-content" flex="1">
-      <description class="customization-tipPanel-contentMessage"/>
-      <image class="customization-tipPanel-contentImage"/>
-    </vbox>
-    <vbox pack="start" align="end" class="customization-tipPanel-closeBox">
-      <toolbarbutton oncommand="gCustomizeMode.hideTip()" class="close-icon"/>
-    </vbox>
-  </hbox>
-</panel>
-
 <panel id="panic-button-success-notification"
        type="arrow"
        position="bottomcenter topright"
        hidden="true"
        role="alert"
        orient="vertical">
   <hbox id="panic-button-success-header">
     <image id="panic-button-success-icon" alt=""/>
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -185,38 +185,34 @@ function getAreaWidgetIds(areaId) {
 function simulateItemDrag(aToDrag, aTarget) {
   synthesizeDrop(aToDrag.parentNode, aTarget);
 }
 
 function endCustomizing(aWindow = window) {
   if (aWindow.document.documentElement.getAttribute("customizing") != "true") {
     return true;
   }
-  Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
   return new Promise(resolve => {
     function onCustomizationEnds() {
-      Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", false);
       aWindow.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds);
       resolve();
     }
     aWindow.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds);
     aWindow.gCustomizeMode.exit();
 
   });
 }
 
 function startCustomizing(aWindow = window) {
   if (aWindow.document.documentElement.getAttribute("customizing") == "true") {
     return null;
   }
-  Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
   return new Promise(resolve => {
     function onCustomizing() {
       aWindow.gNavToolbox.removeEventListener("customizationready", onCustomizing);
-      Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", false);
       resolve();
     }
     aWindow.gNavToolbox.addEventListener("customizationready", onCustomizing);
     aWindow.gCustomizeMode.enter();
   });
 }
 
 function promiseObserverNotified(aTopic) {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -608,27 +608,27 @@ BrowserGlue.prototype = {
     if (AppConstants.INSTALL_COMPACT_THEMES) {
       let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
       LightweightThemeManager.addBuiltInTheme({
         id: "firefox-compact-light@mozilla.org",
         name: gBrowserBundle.GetStringFromName("lightTheme.name"),
         description: gBrowserBundle.GetStringFromName("lightTheme.description"),
         headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
-        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactlight.icon.svg",
+        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
         textcolor: "black",
         accentcolor: "white",
         author: vendorShortName,
       });
       LightweightThemeManager.addBuiltInTheme({
         id: "firefox-compact-dark@mozilla.org",
         name: gBrowserBundle.GetStringFromName("darkTheme.name"),
         description: gBrowserBundle.GetStringFromName("darkTheme.description"),
         headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
-        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactdark.icon.svg",
+        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
         textcolor: "white",
         accentcolor: "black",
         author: vendorShortName,
       });
     }
 
     Services.obs.notifyObservers(null, "browser-ui-startup-complete");
   },
@@ -1682,17 +1682,17 @@ BrowserGlue.prototype = {
         return;
       this._openPreferences("sync", { origin: "doorhanger" });
     }
     this.AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
   },
 
   // eslint-disable-next-line complexity
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 54;
+    const UI_VERSION = 56;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
 
     let currentUIVersion;
     if (Services.prefs.prefHasUserValue("browser.migration.version")) {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } else {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
@@ -2012,24 +2012,16 @@ BrowserGlue.prototype = {
           // In this case just fallback to the safest side and disable suggestions.
           Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
         }
       } catch (ex) {
         // A missing pref is not a fatal error.
       }
     }
 
-    if (currentUIVersion < 48) {
-      // Bug 1372954 - the checked value was persisted but the attribute removal wouldn't
-      // be persisted (Bug 15232). Turns out we can just not persist the value in this case.
-      // The situation was only happening for a few nightlies in 56, so this migration can
-      // be removed in version 58.
-      xulStore.removeValue(BROWSER_DOCURL, "sidebar-box", "checked");
-    }
-
     if (currentUIVersion < 49) {
       // Annotate that a user haven't seen any onboarding tour
       Services.prefs.setIntPref("browser.onboarding.seen-tourset-version", 0);
     }
 
     if (currentUIVersion < 50) {
       try {
         // Transform prefs related to old DevTools Console.
@@ -2082,16 +2074,31 @@ BrowserGlue.prototype = {
       // Migrate browser.onboarding.hidden to browser.onboarding.state.
       if (Services.prefs.prefHasUserValue("browser.onboarding.hidden")) {
         let state = Services.prefs.getBoolPref("browser.onboarding.hidden") ? "watermark" : "default";
         Services.prefs.setStringPref("browser.onboarding.state", state);
         Services.prefs.clearUserPref("browser.onboarding.hidden");
       }
     }
 
+    if (currentUIVersion < 55) {
+      Services.prefs.clearUserPref("browser.customizemode.tip0.shown");
+    }
+
+    if (currentUIVersion < 56) {
+      // Prior to the end of the Firefox 57 cycle, the sidebarcommand being present
+      // or not was the only thing that distinguished whether the sidebar was open.
+      // Now, the sidebarcommand always indicates the last opened sidebar, and we
+      // correctly persist the checked attribute to indicate whether or not the
+      // sidebar was open. We should set the checked attribute in case it wasn't:
+      if (xulStore.getValue(BROWSER_DOCURL, "sidebar-box", "sidebarcommand")) {
+        xulStore.setValue(BROWSER_DOCURL, "sidebar-box", "checked", "true");
+      }
+    }
+
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
   },
 
   _checkForDefaultBrowser() {
     // Perform default browser checking.
     if (!ShellService) {
       return;
--- a/browser/components/places/content/bookmarksPanel.xul
+++ b/browser/components/places/content/bookmarksPanel.xul
@@ -26,17 +26,17 @@
   <commandset id="editMenuCommands"/>
   <menupopup id="placesContext"/>
 
   <!-- Bookmarks and history tooltip -->
   <tooltip id="bhTooltip"/>
 
   <hbox id="sidebar-search-container" align="center">
     <textbox id="search-box" flex="1" type="search"
-             placeholder="&search.placeholder;"
+             placeholder="&bookmarksSearch.placeholder;"
              aria-controls="bookmarks-view"
              oncommand="searchBookmarks(this.value);"/>
   </hbox>
 
   <tree id="bookmarks-view" class="sidebar-placesTree" type="places"
         flex="1"
         hidecolumnpicker="true"
         context="placesContext"
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -885,20 +885,20 @@ PlacesController.prototype = {
       if (PlacesUtils.nodeIsTagQuery(node.parent)) {
         // This is a uri node inside a tag container.  It needs a special
         // untag transaction.
         var tagItemId = PlacesUtils.getConcreteItemId(node.parent);
         var uri = NetUtil.newURI(node.uri);
         if (PlacesUIUtils.useAsyncTransactions) {
           let tag = node.parent.title;
           if (!tag) {
-            let tagGuid = PlacesUtils.getConcreteItemGuid(node.parent);
+            let tagGuid = await PlacesUtils.promiseItemGuid(tagItemId);
             tag = (await PlacesUtils.bookmarks.fetch(tagGuid)).title;
           }
-          transactions.push(PlacesTransactions.Untag({ uri, tag }));
+          transactions.push(PlacesTransactions.Untag({ urls: [uri], tag }));
         } else {
           let txn = new PlacesUntagURITransaction(uri, [tagItemId]);
           transactions.push(txn);
         }
       } else if (PlacesUtils.nodeIsTagQuery(node) && node.parent &&
                PlacesUtils.nodeIsQuery(node.parent) &&
                PlacesUtils.asQuery(node.parent).queryOptions.resultType ==
                  Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY) {
--- a/browser/components/places/content/history-panel.xul
+++ b/browser/components/places/content/history-panel.xul
@@ -41,17 +41,17 @@
   <!-- required to overlay the context menu -->
   <menupopup id="placesContext"/>
 
   <!-- Bookmarks and history tooltip -->
   <tooltip id="bhTooltip"/>
 
   <hbox id="sidebar-search-container">
     <textbox id="search-box" flex="1" type="search"
-             placeholder="&search.placeholder;"
+             placeholder="&historySearch.placeholder;"
              aria-controls="historyTree"
              oncommand="searchHistory(this.value);"/>
     <button id="viewButton" style="min-width:0px !important;" type="menu"
             label="&view.label;" accesskey="&view.accesskey;" selectedsort="day"
             persist="selectedsort">
       <menupopup>
         <menuitem id="bydayandsite" label="&byDayAndSite.label;"
                   accesskey="&byDayAndSite.accesskey;" type="radio"
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -33,16 +33,17 @@ subsuite = clipboard
 [browser_copy_folder_tree.js]
 [browser_copy_query_without_tree.js]
 subsuite = clipboard
 [browser_drag_bookmarks_on_toolbar.js]
 [browser_forgetthissite_single.js]
 [browser_history_sidebar_search.js]
 [browser_library_batch_delete.js]
 [browser_library_commands.js]
+[browser_library_delete_bookmarks_in_tags.js]
 [browser_library_delete_tags.js]
 [browser_library_downloads.js]
 [browser_library_infoBox.js]
 [browser_library_left_pane_fixnames.js]
 [browser_library_left_pane_middleclick.js]
 [browser_library_left_pane_select_hierarchy.js]
 [browser_library_middleclick.js]
 [browser_library_move_bookmarks.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_library_delete_bookmarks_in_tags.js
@@ -0,0 +1,96 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+/**
+ *  Test deleting bookmarks from within tags.
+ */
+
+registerCleanupFunction(async function() {
+  await PlacesUtils.bookmarks.eraseEverything();
+  await PlacesTestUtils.clearHistory();
+});
+
+add_task(async function test_tags() {
+  const uris = [
+    Services.io.newURI("http://example.com/1"),
+    Services.io.newURI("http://example.com/2"),
+    Services.io.newURI("http://example.com/3"),
+  ];
+
+  let children = uris.map((uri, index, arr) => {
+    return {
+      title: `bm${index}`,
+      url: uri,
+    }
+  })
+
+  // Note: we insert the uris in reverse order, so that we end up with the
+  // display in "logical" order of bm0 at the top, and bm2 at the bottom.
+  children = children.reverse();
+
+  await PlacesUtils.bookmarks.insertTree({
+    guid: PlacesUtils.bookmarks.unfiledGuid,
+    children,
+  });
+
+  for (let i = 0; i < uris.length; i++) {
+    PlacesUtils.tagging.tagURI(uris[i], ["test"]);
+  }
+
+  let library = await promiseLibrary();
+
+  // Select and open the left pane "Bookmarks Toolbar" folder.
+  let PO = library.PlacesOrganizer;
+
+  PO.selectLeftPaneQuery("Tags");
+  let tagsNode = PO._places.selectedNode;
+  Assert.notEqual(tagsNode, null, "Should have a valid selection");
+  let tagsTitle = PlacesUtils.getString("TagsFolderTitle");
+  Assert.equal(tagsNode.title, tagsTitle,
+               "Should have selected the Tags node");
+
+  // Now select the tag.
+  PlacesUtils.asContainer(tagsNode).containerOpen = true;
+  let tag = tagsNode.getChild(0);
+  PO._places.selectNode(tag);
+  Assert.equal(PO._places.selectedNode.title, "test",
+               "Should have selected the created tag");
+
+  let ContentTree = library.ContentTree;
+
+  for (let i = 0; i < uris.length; i++) {
+    ContentTree.view.selectNode(ContentTree.view.result.root.getChild(0));
+
+    Assert.equal(ContentTree.view.selectedNode.title, `bm${i}`,
+                 `Should have selected bm${i}`);
+
+    let promiseNotification = PlacesTestUtils.waitForNotification("onItemChanged",
+      (id, property) => property == "tags");
+
+    ContentTree.view.controller.doCommand("cmd_delete");
+
+    await promiseNotification;
+
+    for (let j = 0; j < uris.length; j++) {
+      let tags = PlacesUtils.tagging.getTagsForURI(uris[j]);
+      if (j <= i) {
+        Assert.equal(tags.length, 0,
+                     `There should be no tags for the URI: ${uris[j].spec}`);
+      } else {
+        Assert.equal(tags.length, 1,
+                     `There should be one tag for the URI: ${uris[j].spec}`);
+      }
+    }
+  }
+
+  // The tag should now not exist.
+  Assert.deepEqual(PlacesUtils.tagging.getURIsForTag("test"), [],
+                   "There should be no URIs remaining for the tag");
+
+  tagsNode.containerOpen = false;
+
+  library.close();
+});
--- a/browser/components/places/tests/chrome/chrome.ini
+++ b/browser/components/places/tests/chrome/chrome.ini
@@ -6,11 +6,10 @@ support-files = head.js
 [test_bug1163447_selectItems_through_shortcut.xul]
 [test_bug427633_no_newfolder_if_noip.xul]
 [test_bug485100-change-case-loses-tag.xul]
 [test_bug549192.xul]
 [test_bug549491.xul]
 [test_bug631374_tags_selector_scroll.xul]
 [test_editBookmarkOverlay_keywords.xul]
 [test_editBookmarkOverlay_tags_liveUpdate.xul]
-[test_RecentBookmarksMenuUI.xul]
 [test_selectItems_on_nested_tree.xul]
 [test_treeview_date.xul]
deleted file mode 100644
--- a/browser/components/places/tests/chrome/test_RecentBookmarksMenuUI.xul
+++ /dev/null
@@ -1,299 +0,0 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
-                 type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
-<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
-
-<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
-
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        title="Test RecentBookmarksMenuUI">
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js" />
-  <script type="application/javascript" src="chrome://browser/content/browser.js"/>
-  <script type="application/javascript"
-          src="chrome://browser/content/browser-places.js" />
-  <script type="application/javascript"
-          src="resource://testing-common/sinon-2.3.2.js" />
-
-  <body xmlns="http://www.w3.org/1999/xhtml" />
-
-  <menu id="fakeMenu">
-    <menuseparator id="fakePreviousSeparator"/>
-    <menuitem id="fakeRecentBookmarks"/>
-    <menuseparator id="fakeNextSeparator"/>
-  </menu>
-
-  <script type="application/javascript">
-  <![CDATA[
-    "use strict"
-
-    const sandbox = sinon.sandbox.create();
-
-    const BASE_URL = "http://example.org/browser/browser/components/places/tests/browser/";
-
-    var bmMenu = document.getElementById("fakeMenu");
-    var prevSep = document.getElementById("fakePreviousSeparator");
-    var recentBmItem = document.getElementById("fakeRecentBookmarks");
-    var nextSep = document.getElementById("fakeNextSeparator");
-
-    function simulateHideMenu() {
-      let event = new CustomEvent("popuphidden");
-      bmMenu.dispatchEvent(event);
-    }
-
-    add_task(async function setup() {
-      let children = [];
-      // Make dateAdded start in the past and advance it on a second for each bookmark,
-      // so that we can guarentee which ones get displayed in the test.
-      let dateAdded = (new Date()).getTime() - 1000;
-
-      for (let i = 0; i < 10; i++) {
-        children.push({
-          title: `bm${i}`,
-          url: `${BASE_URL}bookmark_dummy_${i}.html`,
-          dateAdded: new Date(dateAdded)
-        });
-        dateAdded += 100;
-      }
-
-      await PlacesUtils.bookmarks.insertTree({
-        guid: PlacesUtils.bookmarks.unfiledGuid,
-        children: [{
-          children,
-          title: "TestFolder",
-          type: PlacesUtils.bookmarks.TYPE_FOLDER,
-        }]
-      });
-    });
-
-    add_task(async function test_basic_contents() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      let recentItem = recentBmItem.nextSibling;
-      for (let i = 9; i >= 10 - RecentBookmarksMenuUI.MAX_RESULTS; --i) {
-        is(recentItem.getAttribute("label"), `bm${i}`,
-           "Should have the expected title from the bookmark");
-        is(recentItem.getAttribute("targetURI"), `${BASE_URL}bookmark_dummy_${i}.html`,
-           "Should have the expected targetURI from the bookmark");
-        is(recentItem.getAttribute("simulated-places-node"), "true",
-           "Should be flagged as a simulated-places-node");
-        recentItem = recentItem.nextSibling;
-      }
-
-      is(prevSep.hidden, false, "Previous separator should not be hidden");
-      is(recentBmItem.hidden, false, "The title item should not be hidden");
-      ok(nextSep, "Next separator should still be present");
-      is(nextSep.hidden, false, "Next separator should not be hidden");
-
-      // Also check that hiding the menu stops listening to items.
-      simulateHideMenu();
-
-      ok(!RecentBookmarksMenuUI._recentlyBookmarkedObserver,
-         "Remove observer should have been called");
-    });
-
-    add_task(async function test_remove_bookmark() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      let bmToRemove = await PlacesUtils.bookmarks.fetch({url: `${BASE_URL}bookmark_dummy_9.html`});
-
-      const clock = sandbox.useFakeTimers();
-
-      await PlacesUtils.bookmarks.remove(bmToRemove);
-
-      // Move the clock past the timeout to ensure any update happen.
-      clock.tick(RecentBookmarksMenuUI.ITEM_REMOVED_TIMEOUT + 1);
-      clock.restore();
-
-      let recentItem = recentBmItem.nextSibling;
-      for (let i = 8; i >= 9 - RecentBookmarksMenuUI.MAX_RESULTS; --i) {
-        is(recentItem.getAttribute("label"), `bm${i}`,
-           "Should have the expected title from the bookmark");
-        is(recentItem.getAttribute("targetURI"), `${BASE_URL}bookmark_dummy_${i}.html`,
-           "Should have the expected targetURI from the bookmark");
-        is(recentItem.getAttribute("simulated-places-node"), "true",
-           "Should be flagged as a simulated-places-node");
-        recentItem = recentItem.nextSibling;
-      }
-
-      simulateHideMenu();
-    });
-
-    add_task(async function test_remove_multiple_bookmarks() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      let bmToRemove = await PlacesUtils.bookmarks.fetch({url: `${BASE_URL}bookmark_dummy_8.html`});
-
-      const clock = sandbox.useFakeTimers();
-
-      sinon.stub(RecentBookmarksMenuUI, "_insertRecentMenuItems");
-
-      await PlacesUtils.bookmarks.remove(bmToRemove);
-
-      // Move the clock a little way and check we haven't re-pouplated.
-      clock.tick(RecentBookmarksMenuUI.ITEM_REMOVED_TIMEOUT - 10);
-
-      ok(RecentBookmarksMenuUI._insertRecentMenuItems.notCalled,
-         "should not have populated the recent bookmarks striaght away.")
-
-      bmToRemove = await PlacesUtils.bookmarks.fetch({url: `${BASE_URL}bookmark_dummy_7.html`});
-      await PlacesUtils.bookmarks.remove(bmToRemove);
-
-      // Move the clock a little way and check we haven't re-pouplated.
-      clock.tick(RecentBookmarksMenuUI.ITEM_REMOVED_TIMEOUT - 10);
-
-      ok(RecentBookmarksMenuUI._insertRecentMenuItems.notCalled,
-         "should not have populated the recent bookmarks striaght away.")
-
-      RecentBookmarksMenuUI._insertRecentMenuItems.restore();
-
-      // Move the clock past the timeout and check the menu is updated.
-      clock.tick(20);
-
-      let recentItem = recentBmItem.nextSibling;
-      for (let i = 6; i >= 7 - RecentBookmarksMenuUI.MAX_RESULTS; --i) {
-        is(recentItem.getAttribute("label"), `bm${i}`,
-           "Should have the expected title from the bookmark");
-        is(recentItem.getAttribute("targetURI"), `${BASE_URL}bookmark_dummy_${i}.html`,
-           "Should have the expected targetURI from the bookmark");
-        is(recentItem.getAttribute("simulated-places-node"), "true",
-           "Should be flagged as a simulated-places-node");
-        recentItem = recentItem.nextSibling;
-      }
-
-      clock.restore();
-
-      simulateHideMenu();
-    });
-
-    add_task(async function test_remove_non_shown_bookmark() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      let bmToRemove = await PlacesUtils.bookmarks.fetch({url: `${BASE_URL}bookmark_dummy_1.html`});
-
-      sandbox.stub(RecentBookmarksMenuUI, "_clearExistingItems");
-      sandbox.stub(RecentBookmarksMenuUI, "_insertRecentMenuItems");
-
-      const clock = sandbox.useFakeTimers();
-
-      await PlacesUtils.bookmarks.remove(bmToRemove);
-
-      // Move the clock past the timeout to ensure any update happen.
-      clock.tick(RecentBookmarksMenuUI.ITEM_REMOVED_TIMEOUT + 1);
-      clock.restore();
-
-      is(RecentBookmarksMenuUI._clearExistingItems.notCalled, true,
-         "Should not have cleared the existing items when a bookmark is removed that is not displayed.");
-      is(RecentBookmarksMenuUI._insertRecentMenuItems.notCalled, true,
-         "Should not have inserted new menu items when a bookmark is removed that is not displayed.");
-
-      sandbox.restore();
-      simulateHideMenu();
-    });
-
-    add_task(async function test_hide_recently_bookmarked() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      RecentBookmarksMenuUI.visible = false;
-
-      is(Services.prefs.getBoolPref(RecentBookmarksMenuUI.RECENTLY_BOOKMARKED_PREF), false,
-         "showRecentlyBookmarked pref should have been set to false");
-
-      is(bmMenu.children.length, 3,
-         "There should only be the original 3 items in the menu");
-      is(document.getElementById("fakePreviousSeparator").hidden, true,
-         "The previous separator should be hidden");
-      is(document.getElementById("fakeRecentBookmarks").hidden, true,
-         "The title item should be hidden");
-      is(document.getElementById("fakeNextSeparator").hidden, false,
-         "Next separator should not be hidden");
-
-      simulateHideMenu();
-    });
-
-    add_task(async function test_remove_with_recently_bookmarked_hidden() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-      RecentBookmarksMenuUI.visible = false;
-
-      is(bmMenu.children.length, 3,
-         "There should only be the original 3 items in the menu");
-
-      let bmToRemove = await PlacesUtils.bookmarks.fetch({url: `${BASE_URL}bookmark_dummy_6.html`});
-
-      sandbox.stub(RecentBookmarksMenuUI, "_clearExistingItems");
-      sandbox.stub(RecentBookmarksMenuUI, "_insertRecentMenuItems");
-
-      const clock = sandbox.useFakeTimers();
-
-      await PlacesUtils.bookmarks.remove(bmToRemove);
-
-      // Move the clock past the timeout to ensure any update happen.
-      clock.tick(RecentBookmarksMenuUI.ITEM_REMOVED_TIMEOUT + 1);
-      clock.restore();
-
-      is(bmMenu.children.length, 3,
-         "There should only be the original 3 items in the menu");
-      is(RecentBookmarksMenuUI._clearExistingItems.notCalled, true,
-         "Should not have cleared the existing items when recently bookmarked are hidden.");
-      is(RecentBookmarksMenuUI._insertRecentMenuItems.notCalled, true,
-         "Should not have inserted new menu items when recently bookmarked are hidden.");
-
-      sandbox.restore();
-      simulateHideMenu();
-    });
-
-    add_task(async function test_show_recently_bookmarked() {
-      RecentBookmarksMenuUI.init(document.getElementById("fakeRecentBookmarks"));
-
-      is(bmMenu.children.length, 3,
-         "There should only be the original 3 items in the menu");
-
-      RecentBookmarksMenuUI.visible = true;
-
-      is(bmMenu.children.length, RecentBookmarksMenuUI.MAX_RESULTS + 3,
-         "There should be MAX_RESULTS children plus the 2 separators and 1 menuitem.");
-
-      is(Services.prefs.getBoolPref(RecentBookmarksMenuUI.RECENTLY_BOOKMARKED_PREF), true,
-         "showRecentlyBookmarked pref should have been set to true");
-
-      is(document.getElementById("fakePreviousSeparator").hidden, false,
-         "The previous separator should not be hidden");
-      is(document.getElementById("fakeRecentBookmarks").hidden, false,
-         "The title item should not be hidden");
-      is(document.getElementById("fakeNextSeparator").hidden, false,
-         "Next separator should not be hidden");
-
-      simulateHideMenu();
-    });
-
-    add_task(async function cleanup() {
-      Services.prefs.clearUserPref(RecentBookmarksMenuUI.RECENTLY_BOOKMARKED_PREF);
-      await PlacesUtils.bookmarks.eraseEverything();
-    });
-  ]]>
-  </script>
-</window>
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -428,16 +428,17 @@
       <hbox id="browserContainersExtensionContent" align="center">
         <description control="disableContainersExtension" flex="1" />
         <button id="disableContainersExtension"
                 class="extension-controlled-button accessory-button"
                 label="&disableExtension.label;" />
       </hbox>
       <hbox align="center">
         <checkbox id="browserContainersCheckbox"
+                  class="tail-with-learn-more"
                   label="&browserContainersEnabled.label;"
                   accesskey="&browserContainersEnabled.accesskey;"
                   preference="privacy.userContext.enabled"
                   onsyncfrompreference="return gMainPane.readBrowserContainersCheckbox();"/>
         <label id="browserContainersLearnMore" class="learnMore text-link">
           &browserContainersLearnMore.label;
         </label>
         <spacer flex="1"/>
@@ -732,17 +733,17 @@
     <columns>
       <column flex="1"/>
       <column/>
     </columns>
     <rows id="contentRows-2">
       <row id="playDRMContentRow">
         <hbox align="center">
           <checkbox id="playDRMContent" preference="media.eme.enabled"
-                    label="&playDRMContent2.label;" accesskey="&playDRMContent2.accesskey;"/>
+                    class="tail-with-learn-more" label="&playDRMContent2.label;" accesskey="&playDRMContent2.accesskey;"/>
           <label id="playDRMContentLink" class="learnMore text-link">
             &playDRMContent.learnMore.label;
           </label>
         </hbox>
       </row>
     </rows>
   </grid>
 </groupbox>
@@ -759,20 +760,20 @@
   <label class="header-name" flex="1">&updateApplication.label;</label>
 </hbox>
 
 <!-- Update -->
 <groupbox id="updateApp" data-category="paneGeneral" hidden="true">
   <caption class="search-header" hidden="true"><label>&updateApplication.label;</label></caption>
 
   <label>&updateApplicationDescription.label;</label>
-  <hbox align="start">
+  <hbox align="center">
     <vbox flex="1">
       <description>
-        &updateApplication.version.pre;<label id="version"/>&updateApplication.version.post;
+        &updateApplication.version.pre;<label id="version" class="tail-with-learn-more" />&updateApplication.version.post;
         <label id="releasenotes" class="learnMore text-link" hidden="true">&releaseNotes.link;</label>
       </description>
       <description id="distribution" class="text-blurb" hidden="true"/>
       <description id="distributionId" class="text-blurb" hidden="true"/>
     </vbox>
 #ifdef MOZ_UPDATER
     <spacer flex="1"/>
     <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
@@ -916,16 +917,17 @@
 </hbox>
 
 <!-- Performance -->
 <groupbox id="performanceGroup" data-category="paneGeneral" hidden="true">
   <caption class="search-header" hidden="true"><label>&performance.label;</label></caption>
 
   <hbox align="center">
     <checkbox id="useRecommendedPerformanceSettings"
+              class="tail-with-learn-more"
               label="&useRecommendedPerformanceSettings2.label;"
               accesskey="&useRecommendedPerformanceSettings2.accesskey;"
               preference="browser.preferences.defaultPerformanceSettings.enabled"/>
     <label id="performanceSettingsLearnMore" class="learnMore text-link">&performanceSettingsLearnMore.label;</label>
   </hbox>
   <description class="indent tip-caption">&useRecommendedPerformanceSettings2.description;</description>
 
   <vbox id="performanceSettings" class="indent" hidden="true">
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -267,38 +267,35 @@
     </hbox>
     <label>&historyHeader.post.label;</label>
   </hbox>
   <deck id="historyPane">
     <vbox id="historyRememberPane">
       <hbox align="center" flex="1">
         <vbox flex="1">
           <description>&rememberDescription.label;</description>
-          <separator class="thin"/>
           <description>&rememberActions.pre.label;<label
           class="text-link" id="historyRememberClear"
           >&rememberActions.clearHistory.label;</label>&rememberActions.middle.label;<label
           class="text-link" id="historyRememberCookies"
           >&rememberActions.removeCookies.label;</label>&rememberActions.post.label;</description>
         </vbox>
       </hbox>
     </vbox>
     <vbox id="historyDontRememberPane">
       <hbox align="center" flex="1">
         <vbox flex="1">
           <description>&dontrememberDescription.label;</description>
-          <separator class="thin"/>
           <description>&dontrememberActions.pre.label;<label
           class="text-link" id="historyDontRememberClear"
           >&dontrememberActions.clearHistory.label;</label>&dontrememberActions.post.label;</description>
         </vbox>
       </hbox>
     </vbox>
     <vbox id="historyCustomPane">
-      <separator class="thin"/>
       <vbox>
         <checkbox id="privateBrowsingAutoStart"
                   label="&privateBrowsingPermanent2.label;"
                   accesskey="&privateBrowsingPermanent2.accesskey;"
                   preference="browser.privatebrowsing.autostart"/>
         <vbox class="indent">
           <checkbox id="rememberHistory"
                     label="&rememberHistory2.label;"
@@ -455,17 +452,17 @@
 
 <!-- Site Data -->
 <groupbox id="siteDataGroup" hidden="true" data-category="panePrivacy" data-hidden-from-search="true">
   <caption><label>&siteData.label;</label></caption>
 
   <hbox align="baseline">
     <vbox flex="1">
       <description flex="1">
-        <label id="totalSiteDataSize"></label>
+        <label id="totalSiteDataSize" class="tail-with-learn-more"></label>
         <label id="siteDataLearnMoreLink" class="learnMore text-link">&siteDataLearnMoreLink.label;</label>
       </description>
     </vbox>
     <vbox align="end">
       <button id="siteDataSettings"
               class="accessory-button"
               label="&siteDataSettings.label;"
               accesskey="&siteDataSettings.accesskey;"
@@ -492,17 +489,17 @@
         </description>
       </vbox>
       <spacer flex="1"/>
     </hbox>
     <hbox>
       <vbox id="trackingProtectionBox" flex="1" hidden="true">
         <description id="trackingProtectionDesc"
                      control="trackingProtectionRadioGroup">
-          &trackingProtection2.radioGroupLabel;
+           <label class="tail-with-learn-more">&trackingProtection2.radioGroupLabel;</label>
            <label id="trackingProtectionLearnMore" class="learnMore text-link">&trackingProtectionLearnMore.label;</label>
         </description>
         <radiogroup id="trackingProtectionRadioGroup" aria-labelledby="trackingProtectionDesc">
           <radio value="always"
                  label="&trackingProtectionAlways.label;"
                  accesskey="&trackingProtectionAlways.accesskey;"/>
           <radio value="private"
                  label="&trackingProtectionPrivate.label;"
@@ -545,17 +542,17 @@
                   label="&changeBlockList2.label;"
                   accesskey="&changeBlockList2.accesskey;"
                   preference="pref.privacy.disable_button.change_blocklist"
                   searchkeywords="&button.cancel.label; &button.ok.label;"/>
         </hbox>
       </vbox>
     </hbox>
     <vbox id="doNotTrackLearnMoreBox">
-      <label>&doNotTrack.description;<label
+      <label><label class="tail-with-learn-more">&doNotTrack.description;</label><label
       class="learnMore text-link" href="https://www.mozilla.org/dnt"
       >&doNotTrack.learnMore.label;</label></label>
       <radiogroup id="doNotTrackRadioGroup" aria-labelledby="doNotTrackDesc" preference="privacy.donottrackheader.enabled">
         <radio value="false" label="&doNotTrack.default.label;"/>
         <radio value="true" label="&doNotTrack.always.label;"/>
       </radiogroup>
     </vbox>
   </vbox>
@@ -631,17 +628,17 @@
                                   &button.ok.label;"/>
         </hbox>
       </row>
 
       <row id="notificationSettingsRow" align="center">
         <description flex="1">
           <image class="desktop-notification-icon permission-icon" />
           <separator orient="vertical" class="thin"/>
-          <label id="notificationPermissionsLabel">&notificationPermissions.label;</label>
+          <label id="notificationPermissionsLabel" class="tail-with-learn-more">&notificationPermissions.label;</label>
           <label id="notificationPermissionsLearnMore"
                  class="learnMore text-link">&notificationPermissionsLearnMore.label;</label>
         </description>
         <hbox pack="end">
           <button id="notificationSettingsButton"
                   class="accessory-button"
                   label="&notificationSettingsButton.label;"
                   accesskey="&notificationSettingsButton.accesskey;"
@@ -654,18 +651,18 @@
     </rows>
   </grid>
 
   <separator flex="1"/>
 
   <vbox id="notificationsDoNotDisturbBox" hidden="true">
     <checkbox id="notificationsDoNotDisturb" label="&notificationsDoNotDisturb.label;"
               accesskey="&notificationsDoNotDisturb.accesskey;"/>
-    <label id="notificationsDoNotDisturbDetails"
-           class="indent">&notificationsDoNotDisturbDetails.value;</label>
+    <description id="notificationsDoNotDisturbDetails"
+           class="indent tip-caption">&notificationsDoNotDisturbDetails.value;</description>
   </vbox>
 
   <hbox align="start">
     <checkbox id="popupPolicy" preference="dom.disable_open_during_load"
               label="&blockPopups.label;" accesskey="&blockPopups.accesskey;"
               onsyncfrompreference="return gPrivacyPane.updateButtons('popupPolicyButton',
                                          'dom.disable_open_during_load');"
               flex="1" />
@@ -697,23 +694,24 @@
                               &removepermission2.label;
                               &removeallpermissions2.label;
                               &button.cancel.label;
                               &button.ok.label;"/>
     </hbox>
   </hbox>
 
   <vbox id="a11yPermissionsBox">
-    <description flex="1">
-      <checkbox id="a11yPrivacyCheckbox" label="&a11yPrivacy.checkbox.label;"
+    <hbox flex="1" align="center">
+      <checkbox id="a11yPrivacyCheckbox" class="tail-with-learn-more"
+                label="&a11yPrivacy.checkbox.label;"
                 accesskey="&a11yPrivacy.checkbox.accesskey;"
                 oncommand="return gPrivacyPane.updateA11yPrefs(this.checked)"/>
       <label id="a11yLearnMoreLink" class="learnMore text-link"
               value="&a11yPrivacy.learnmore.label;"></label>
-    </description>
+    </hbox>
   </vbox>
 </groupbox>
 
 <hbox id="dataCollectionCategory"
       class="subcategory"
       hidden="true"
       data-category="panePrivacy"
       data-subcategory="reports">
@@ -722,31 +720,33 @@
 
 <!-- Firefox Data Collection and Use -->
 #ifdef MOZ_DATA_REPORTING
 <groupbox id="dataCollectionGroup" data-category="panePrivacy" data-subcategory="reports" hidden="true">
   <caption class="search-header" hidden="true"><label>&dataCollection.label;</label></caption>
 
   <vbox>
     <description>
-      &dataCollectionDesc.label;<label id="dataCollectionPrivacyNotice" class="learnMore text-link">&dataCollectionPrivacyNotice.label;</label>
+      <label class="tail-with-learn-more">&dataCollectionDesc.label;</label><label id="dataCollectionPrivacyNotice" class="learnMore text-link">&dataCollectionPrivacyNotice.label;</label>
     </description>
     <description flex="1">
       <checkbox id="submitHealthReportBox" label="&enableHealthReport2.label;"
+                class="tail-with-learn-more"
                 accesskey="&enableHealthReport2.accesskey;"/>
       <label id="FHRLearnMore"
              class="learnMore text-link">&healthReportLearnMore.label;</label>
     </description>
 #ifndef MOZ_TELEMETRY_REPORTING
     <description id="TelemetryDisabledDesc" class="indent tip-caption" control="telemetryGroup">&healthReportingDisabled.label;</description>
 #endif
   </vbox>
 #ifdef MOZ_CRASHREPORTER
   <hbox align="center">
     <checkbox id="automaticallySubmitCrashesBox"
+              class="tail-with-learn-more"
               preference="browser.crashReports.unsubmittedCheck.autoSubmit"
               label="&alwaysSubmitCrashReports1.label;"
               accesskey="&alwaysSubmitCrashReports1.accesskey;"/>
     <label id="crashReporterLearnMore"
            class="learnMore text-link">&crashReporterLearnMore.label;</label>
   </hbox>
 #endif
 </groupbox>
@@ -760,16 +760,17 @@
 </hbox>
 
 <!-- addons, forgery (phishing) UI Security -->
 <groupbox id="browsingProtectionGroup" data-category="panePrivacy" hidden="true">
   <caption><label>&browsingProtection.label;</label></caption>
   <hbox align = "center">
     <checkbox id="enableSafeBrowsing"
               label="&enableSafeBrowsing.label;"
+              class="tail-with-learn-more"
               accesskey="&enableSafeBrowsing.accesskey;" />
     <label id="enableSafeBrowsingLearnMore"
            class="learnMore text-link">&enableSafeBrowsingLearnMore.label;</label>
   </hbox>
   <vbox class="indent">
 #ifdef MOZILLA_OFFICIAL
     <checkbox id="blockDownloads"
               label="&blockDownloads.label;"
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -67,17 +67,17 @@
       </vbox>
     </groupbox>
 
     <groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
       <caption><label>&oneClickSearchEngines.label;</label></caption>
       <description>&chooseWhichOneToDisplay2.label;</description>
 
       <tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
-            seltype="single">
+            seltype="single" allowunderflowscroll="true">
         <treechildren id="engineChildren" flex="1"/>
         <treecols>
           <treecol id="engineShown" type="checkbox" editable="true" sortable="false"/>
           <treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
           <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
                    sortable="false"/>
         </treecols>
       </tree>
--- a/browser/components/search/test/browser_searchbar_openpopup.js
+++ b/browser/components/search/test/browser_searchbar_openpopup.js
@@ -37,27 +37,25 @@ function synthesizeNativeMouseClick(aEle
     utils.sendNativeMouseEvent(x * scale, y * scale, mouseUp, 0, null);
   });
 }
 
 async function endCustomizing(aWindow = window) {
   if (aWindow.document.documentElement.getAttribute("customizing") != "true") {
     return true;
   }
-  await SpecialPowers.pushPrefEnv({set: [["browser.uiCustomization.disableAnimation", true]]});
   let eventPromise = BrowserTestUtils.waitForEvent(aWindow.gNavToolbox, "aftercustomization");
   aWindow.gCustomizeMode.exit();
   return eventPromise;
 }
 
 async function startCustomizing(aWindow = window) {
   if (aWindow.document.documentElement.getAttribute("customizing") == "true") {
     return true;
   }
-  await SpecialPowers.pushPrefEnv({set: [["browser.uiCustomization.disableAnimation", true]]});
   let eventPromise = BrowserTestUtils.waitForEvent(aWindow.gNavToolbox, "customizationready");
   aWindow.gCustomizeMode.enter();
   return eventPromise;
 }
 
 let searchbar;
 let textbox;
 let searchIcon;
--- a/browser/components/syncedtabs/sidebar.xhtml
+++ b/browser/components/syncedtabs/sidebar.xhtml
@@ -92,17 +92,20 @@
     </template>
 
     <div class="content-container">
       <!-- the non-scrollable header -->
       <div class="content-header">
         <div class="sidebar-search-container tabs-container sync-state">
           <div class="search-box">
             <div class="textbox-input-box">
-              <input type="text" class="tabsFilter textbox-input" tabindex="1"/>
+              <input type="text"
+                     class="tabsFilter textbox-input"
+                     placeholder="&syncedTabs.sidebar.searchPlaceholder;"
+                     tabindex="1"/>
               <div class="textbox-search-icons">
                 <a class="textbox-search-clear"></a>
                 <a class="textbox-search-icon"></a>
               </div>
             </div>
           </div>
         </div>
       </div>
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -471,16 +471,33 @@ this.FormAutofillHeuristics = {
       "cc-name",
       "cc-number",
       "cc-exp-month",
       "cc-exp-year",
       "cc-exp",
     ];
     let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
 
+    if (!FormAutofillUtils.isAutofillCreditCardsAvailable) {
+      if (isAutoCompleteOff) {
+        if (!this._regexpListOf_CcUnavailable_AcOff) {
+          this._regexpListOf_CcUnavailable_AcOff = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
+        }
+        regexps = this._regexpListOf_CcUnavailable_AcOff;
+      } else {
+        if (!this._regexpListOf_CcUnavailable_AcOn) {
+          this._regexpListOf_CcUnavailable_AcOn = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
+        }
+        regexps = this._regexpListOf_CcUnavailable_AcOn;
+      }
+    }
+    if (regexps.length == 0) {
+      return null;
+    }
+
     let labelStrings;
     let getElementStrings = {};
     getElementStrings[Symbol.iterator] = function* () {
       yield element.id;
       yield element.name;
       if (!labelStrings) {
         labelStrings = [];
         let labels = LabelUtils.findLabelElements(element);
--- a/browser/extensions/formautofill/FormAutofillPreferences.jsm
+++ b/browser/extensions/formautofill/FormAutofillPreferences.jsm
@@ -75,16 +75,17 @@ FormAutofillPreferences.prototype = {
     let addressAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
     let addressAutofillLearnMore = document.createElementNS(XUL_NS, "label");
     let savedAddressesBtn = document.createElementNS(XUL_NS, "button");
     // Wrappers are used to properly compute the search tooltip positions
     let savedAddressesBtnWrapper = document.createElementNS(XUL_NS, "hbox");
     let savedCreditCardsBtnWrapper = document.createElementNS(XUL_NS, "hbox");
 
     savedAddressesBtn.className = "accessory-button";
+    addressAutofillCheckbox.className = "tail-with-learn-more";
     addressAutofillLearnMore.className = "learnMore text-link";
 
     formAutofillGroup.id = "formAutofillGroup";
     addressAutofill.id = "addressAutofill";
     addressAutofillLearnMore.id = "addressAutofillLearnMore";
 
     addressAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
     addressAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableAddressAutofill"));
@@ -118,16 +119,17 @@ FormAutofillPreferences.prototype = {
 
     if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
       let creditCardAutofill = document.createElementNS(XUL_NS, "hbox");
       let creditCardAutofillCheckboxGroup = document.createElementNS(XUL_NS, "description");
       let creditCardAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
       let creditCardAutofillLearnMore = document.createElementNS(XUL_NS, "label");
       let savedCreditCardsBtn = document.createElementNS(XUL_NS, "button");
       savedCreditCardsBtn.className = "accessory-button";
+      creditCardAutofillCheckbox.className = "tail-with-learn-more";
       creditCardAutofillLearnMore.className = "learnMore text-link";
 
       creditCardAutofill.id = "creditCardAutofill";
       creditCardAutofillLearnMore.id = "creditCardAutofillLearnMore";
 
       creditCardAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
       creditCardAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableCreditCardAutofill"));
       savedCreditCardsBtn.setAttribute("label", this.bundle.GetStringFromName("savedCreditCards"));
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -204,16 +204,17 @@
   padding-top: 14px;
   padding-bottom: 14px;
   margin-bottom: 9px;
   background-repeat: no-repeat;
   background-position: left 17px top 14px;
   background-size: 20px;
   font-size: 16px;
   cursor: pointer;
+  max-height: 54px;
 }
 
 #onboarding-tour-list .onboarding-tour-item:dir(rtl) {
   background-position-x: right 17px;
 }
 
 #onboarding-tour-list .onboarding-tour-item.onboarding-complete::before {
   content: url("img/icons_tour-complete.svg");
@@ -525,17 +526,17 @@ a#onboarding-tour-screenshots-button:vis
   transform: translate(-50%, -50%);
 }
 
 #onboarding-notification-body {
   width: 500px;
   margin: 0 18px;
   color: #0c0c0d;
   display: inline-block;
-  max-height: 100%;
+  max-height: 120px;
   overflow: auto;
   padding: 15px 0;
   box-sizing: border-box;
 }
 
 #onboarding-notification-body * {
   font-size: 12px;
   font-weight: normal;
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -367,19 +367,18 @@ var PocketOverlay = {
     // we need to manually unregister here anyway to ensure these aren't part
     // of the chrome process and avoid errors.
     AboutPocket.aboutSaved.unregister();
     AboutPocket.aboutSignup.unregister();
 
     PocketPageAction.shutdown();
 
     for (let window of browserWindows()) {
-      for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket",
-                      "panelMenu_pocketSeparator", "menu_pocketSeparator",
-                      "BMB_pocketSeparator", "appMenu-library-pocket-button"]) {
+      for (let id of ["panelMenu_pocket", "panelMenu_pocketSeparator",
+                      "appMenu-library-pocket-button"]) {
         let element = window.document.getElementById(id) ||
                       window.gNavToolbox.palette.querySelector("#" + id);
         if (element)
           element.remove();
       }
       this.removeStyles(window);
       // remove script getters/objects
       delete window.Pocket;
@@ -408,57 +407,18 @@ var PocketOverlay = {
     Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging", window));
   },
   // called for each window as it is opened
   updateWindow(window) {
     // insert our three menu items
     let document = window.document;
     let hidden = !isPocketEnabled();
 
-    // add to bookmarksMenu
-    let sib = document.getElementById("menu_bookmarkThisPage");
-    if (sib && !document.getElementById("menu_pocket")) {
-      let menu = createElementWithAttrs(document, "menuitem", {
-        "id": "menu_pocket",
-        "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
-        "class": "menuitem-iconic", // OSX only
-        "oncommand": "Pocket.openList(event)",
-        "hidden": hidden
-      });
-      let sep = createElementWithAttrs(document, "menuseparator", {
-        "id": "menu_pocketSeparator",
-        "hidden": hidden
-      });
-      sib.parentNode.insertBefore(menu, sib);
-      sib.parentNode.insertBefore(sep, sib);
-    }
-
-    // add to bookmarks-menu-button
-    sib = document.getElementById("BMB_bookmarksToolbar");
-    if (!sib) {
-      sib = window.gNavToolbox.palette.querySelector("#BMB_bookmarksToolbar");
-    }
-    if (sib && !sib.parentNode.querySelector("#BMB_pocket")) {
-      let menu = createElementWithAttrs(document, "menuitem", {
-        "id": "BMB_pocket",
-        "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
-        "class": "menuitem-iconic bookmark-item subviewbutton",
-        "oncommand": "Pocket.openList(event)",
-        "hidden": hidden
-      });
-      let sep = createElementWithAttrs(document, "menuseparator", {
-        "id": "BMB_pocketSeparator",
-        "hidden": hidden
-      });
-      sib.parentNode.insertBefore(menu, sib);
-      sib.parentNode.insertBefore(sep, sib);
-    }
-
     // add to PanelUI-bookmarks
-    sib = document.getElementById("panelMenuBookmarkThisPage");
+    let sib = document.getElementById("panelMenuBookmarkThisPage");
     if (sib && !document.getElementById("panelMenu_pocket")) {
       let menu = createElementWithAttrs(document, "toolbarbutton", {
         "id": "panelMenu_pocket",
         "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
         "class": "subviewbutton cui-withicon",
         "oncommand": "Pocket.openList(event)",
         "hidden": hidden
       });
--- a/browser/extensions/pocket/skin/shared/pocket.css
+++ b/browser/extensions/pocket/skin/shared/pocket.css
@@ -202,26 +202,22 @@
     -moz-image-region: rect(64px, 64px, 128px, 0);
   }
 }
 
 #appMenu-library-pocket-button {
   list-style-image: url("chrome://pocket-shared/skin/pocket.svg");
 }
 
-#panelMenu_pocket,
-#menu_pocket,
-#BMB_pocket {
+#panelMenu_pocket {
   list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16.png");
 }
 
 @media (min-resolution: 2dppx) {
-  #panelMenu_pocket,
-  #menu_pocket,
-  #BMB_pocket {
+  #panelMenu_pocket {
     list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16@2x.png");
   }
 
   #panelMenu_pocket > .toolbarbutton-icon {
     width: 16px;
   }
 }
 
--- a/browser/extensions/pocket/test/browser_pocket_ui_check.js
+++ b/browser/extensions/pocket/test/browser_pocket_ui_check.js
@@ -23,19 +23,18 @@ add_task(async function test_setup() {
     }
   });
 });
 
 add_task(async function() {
   await promisePocketEnabled();
 
   checkWindowProperties(true, ["Pocket", "pktUI", "pktUIMessaging"]);
-  checkElements(true, ["pocket-button", "panelMenu_pocket", "menu_pocket", "BMB_pocket",
-                       "panelMenu_pocketSeparator", "menu_pocketSeparator",
-                       "BMB_pocketSeparator"]);
+  checkElements(true, ["pocket-button", "panelMenu_pocket",
+                       "panelMenu_pocketSeparator"]);
 
   // check context menu exists
   info("checking content context menu");
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com/browser/browser/extensions/pocket/test/test.html");
 
   let contextMenu = document.getElementById("contentAreaContextMenu");
   let popupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
   let popupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
@@ -49,14 +48,13 @@ add_task(async function() {
 
   contextMenu.hidePopup();
   await popupHidden;
   await BrowserTestUtils.removeTab(tab);
 
   await promisePocketDisabled();
 
   checkWindowProperties(false, ["Pocket", "pktUI", "pktUIMessaging"]);
-  checkElements(false, ["pocket-button", "panelMenu_pocket", "menu_pocket", "BMB_pocket",
-                       "panelMenu_pocketSeparator", "menu_pocketSeparator",
-                       "BMB_pocketSeparator", "context-pocket", "context-savelinktopocket"]);
+  checkElements(false, ["pocket-button", "panelMenu_pocket", "panelMenu_pocketSeparator",
+                        "context-pocket", "context-savelinktopocket"]);
 
   await promisePocketReset();
 });
--- a/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
+++ b/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
@@ -101,16 +101,17 @@ this.ShieldPreferences = {
     container.classList.add("indent");
 
     const hContainer = doc.createElementNS(XUL_NS, "hbox");
     hContainer.setAttribute("align", "center");
     container.appendChild(hContainer);
 
     const checkbox = doc.createElementNS(XUL_NS, "checkbox");
     checkbox.setAttribute("id", "optOutStudiesEnabled");
+    checkbox.setAttribute("class", "tail-with-learn-more");
     checkbox.setAttribute("label", "Allow Firefox to install and run studies");
     checkbox.setAttribute("preference", OPT_OUT_STUDIES_ENABLED_PREF);
     checkbox.setAttribute("disabled", !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF));
     hContainer.appendChild(checkbox);
 
     const viewStudies = doc.createElementNS(XUL_NS, "label");
     viewStudies.setAttribute("id", "viewShieldStudies");
     viewStudies.setAttribute("href", "about:studies");
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -800,16 +800,17 @@ you can use these alternative items. Oth
 <!ENTITY syncedTabs.sidebar.noclients.title    "No synced tabs… yet!">
 <!ENTITY syncedTabs.sidebar.noclients.subtitle "Want to see your tabs from other devices here?">
 <!ENTITY syncedTabs.sidebar.notsignedin.label  "Sign in to view a list of tabs from your other devices.">
 <!ENTITY syncedTabs.sidebar.notabs.label       "No open tabs">
 <!ENTITY syncedTabs.sidebar.openprefs.label    "Open &syncBrand.shortName.label; Preferences">
 <!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown
      when Sync is configured but syncing tabs is disabled. -->
 <!ENTITY syncedTabs.sidebar.tabsnotsyncing.label       "Turn on tab syncing to view a list of tabs from your other devices.">
+<!ENTITY syncedTabs.sidebar.searchPlaceholder  "Search synced tabs">
 
 <!-- LOCALIZATION NOTE (syncedTabs.context.open.accesskey,
                         syncedTabs.context.openAllInTabs.accesskey):
      These access keys are identical because their associated menu items are
      mutually exclusive -->
 <!ENTITY syncedTabs.context.open.label                       "Open">
 <!ENTITY syncedTabs.context.open.accesskey                   "O">
 <!ENTITY syncedTabs.context.openInNewTab.label               "Open in a New Tab">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -763,23 +763,16 @@ slowStartup.helpButton.accesskey = L
 slowStartup.disableNotificationButton.label = Don’t Tell Me Again
 slowStartup.disableNotificationButton.accesskey = A
 
 # LOCALIZATION NOTE  - %S is brandShortName
 flashHang.message = %S changed some Adobe Flash settings to improve performance.
 flashHang.helpButton.label = Learn More…
 flashHang.helpButton.accesskey = L
 
-# LOCALIZATION NOTE(customizeTips.tip0): %1$S will be replaced with the text defined
-# in customizeTips.tip0.hint, %2$S will be replaced with brandShortName, %3$S will
-# be replaced with a hyperlink containing the text defined in customizeTips.tip0.learnMore.
-customizeTips.tip0 = %1$S: You can customize %2$S to work the way you do. Simply drag any of the above to the menu or toolbar. %3$S about customizing %2$S.
-customizeTips.tip0.hint = Hint
-customizeTips.tip0.learnMore = Learn more
-
 # LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
 customizeMode.tabTitle = Customize %S
 
 # LOCALIZATION NOTE (appMenuRemoteTabs.mobilePromo.text2):
 # %1$S will be replaced with a link, the text of which is
 # appMenuRemoteTabs.mobilePromo.android and the link will be to
 # https://www.mozilla.org/firefox/android/.
 # %2$S will be replaced with a link, the text of which is
--- a/browser/locales/en-US/chrome/browser/places/places.dtd
+++ b/browser/locales/en-US/chrome/browser/places/places.dtd
@@ -80,17 +80,18 @@
 <!ENTITY col.tags.label          "Tags">
 <!ENTITY col.url.label           "Location">
 <!ENTITY col.mostrecentvisit.label "Most Recent Visit">
 <!ENTITY col.visitcount.label    "Visit Count">
 <!ENTITY col.description.label   "Description">
 <!ENTITY col.dateadded.label     "Added">
 <!ENTITY col.lastmodified.label  "Last Modified">
 
-<!ENTITY search.placeholder  "Search">
+<!ENTITY historySearch.placeholder  "Search history">
+<!ENTITY bookmarksSearch.placeholder  "Search bookmarks">
 
 <!ENTITY cmd.find.key  "f">
 
 <!ENTITY maintenance.label      "Import and Backup">
 <!ENTITY maintenance.accesskey  "I">
 <!ENTITY maintenance.tooltip    "Import and backup your bookmarks">
 
 <!ENTITY backButton.tooltip  "Go back">
--- a/browser/modules/test/browser/browser_PageActions.js
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -1020,17 +1020,29 @@ function promisePanelEvent(panelIDOrNode
     }
     panel.addEventListener(eventType, () => {
       executeSoon(resolve);
     }, { once: true });
   });
 }
 
 function promisePageActionViewShown() {
-  return new Promise(resolve => {
-    BrowserPageActions.panelNode.addEventListener("ViewShown", (event) => {
-      let target = event.originalTarget;
-      window.setTimeout(() => {
-        resolve(target);
-      }, 5000);
-    }, { once: true });
+  let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                  .getInterface(Ci.nsIDOMWindowUtils);
+  info("promisePageActionViewShown waiting for ViewShown");
+  return BrowserTestUtils.waitForEvent(BrowserPageActions.panelNode, "ViewShown").then(async event => {
+    let panelViewNode = event.originalTarget;
+    // Wait for the subview to be really truly shown by making sure there's at
+    // least one child with non-zero bounds.
+    info("promisePageActionViewShown waiting for a child node to be visible");
+    await BrowserTestUtils.waitForCondition(() => {
+      let bodyNode = panelViewNode.firstChild;
+      for (let childNode of bodyNode.childNodes) {
+        let bounds = dwu.getBoundsWithoutFlushing(childNode);
+        if (bounds.width > 0 && bounds.height > 0) {
+          return true;
+        }
+      }
+      return false;
+    });
+    return panelViewNode;
   });
 }
--- a/browser/themes/linux/preferences/in-content/preferences.css
+++ b/browser/themes/linux/preferences/in-content/preferences.css
@@ -40,12 +40,11 @@ caption > label:not(.dialogTitle) {
   margin-top: 2px !important;
 }
 
 menulist.actionsMenu > .menulist-dropmarker {
   margin-top: 11px;
   margin-bottom: 11px;
 }
 
-textbox + button,
 filefield + button {
   margin-inline-start: -4px;
 }
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -179,16 +179,24 @@ span#hostname {
   padding-inline-start: 38%;
 }
 
 .illustrated #errorPageContainer {
   background-repeat: no-repeat;
   background-size: 38%;
 }
 
+.connectionFailure #errorPageContainer,
+.netInterrupt #errorPageContainer,
+.netTimeout #errorPageContainer,
+.netReset #errorPageContainer,
+.netOffline #errorPageContainer {
+  background-image: url("chrome://browser/content/illustrations/error-connection-failure.svg");
+}
+
 .dnsNotFound #errorPageContainer {
   background-image: url("chrome://browser/content/illustrations/error-server-not-found.svg");
 }
 
 .malformedURI #errorPageContainer {
   background-image: url("chrome://browser/content/illustrations/error-malformed-url.svg");
 }
 
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -82,20 +82,18 @@ toolbar[brighttext] .toolbarbutton-1 {
 }
 
 /* Default findbar text color doesn't look good - Bug 1125677 */
 .browserContainer > findbar .findbar-find-status,
 .browserContainer > findbar .found-matches {
   color: inherit;
 }
 
-#navigator-toolbox .toolbarbutton-1,
 .browserContainer > findbar .findbar-button,
 #PlacesToolbar toolbarbutton.bookmark-item {
-  color: var(--chrome-color);
   text-shadow: none;
 }
 
 #TabsToolbar {
   text-shadow: none !important;
 }
 
 /* URL bar and search bar*/
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1364,16 +1364,26 @@ photonpanelmultiview .PanelUI-subView .t
   min-width: auto;
   padding: 4px;
 }
 
 #appMenu-zoom-controls > .subviewbutton {
   margin-inline-start: 10px;
 }
 
+/* An em-based minimum height works better for a text-only button. */
+#appMenu-zoomReset-button {
+  min-height: 2em;
+}
+
+#appMenu-zoomReset-button > .toolbarbutton-text {
+  min-width: 3em;
+  text-align: center;
+}
+
 .toolbaritem-combined-buttons > toolbarseparator[orient="vertical"] + .subviewbutton,
 #appMenu-zoom-controls > toolbarseparator[orient="vertical"] + .subviewbutton {
   margin-inline-start: 0;
 }
 
 photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons >
   .subviewbutton-iconic > .toolbarbutton-text,
 photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons >
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -25,17 +25,17 @@
 
 #mainPrefPane {
   width: 100%;
   padding: 0;
   font: message-box;
   color: currentColor;
 }
 
-groupbox + groupbox {
+prefpane > groupbox + groupbox {
   margin-top: 16px;
 }
 
 groupbox + groupbox > .groupbox-body,
 groupbox + vbox groupbox > .groupbox-body {
   margin-top: 4px;
 }
 
@@ -57,43 +57,46 @@ html|option {
 
 description,
 label {
   line-height: 30px;
   margin-top: 0 !important;
   margin-bottom: 0 !important;
 }
 
-description > checkbox {
-  vertical-align: bottom;
+menuitem > label,
+button > hbox > label {
+  line-height: unset;
 }
 
 .indent {
   margin-inline-start: 28px !important;
 }
 
-separator.thin:not([orient="vertical"]) {
-  height: 8px;
-}
-
 .checkbox-check {
   margin-inline-end: 8px;
   width: 20px;
   height: 20px;
 }
 
+.tail-with-learn-more {
+  margin-inline-start: 0px;
+  margin-inline-end: 10px;
+}
+
 .learnMore {
-  margin-inline-start: 10px;
+  margin-inline-start: 0px;
   font-weight: normal;
   white-space: nowrap;
 }
 
 .accessory-button {
-  min-width: 145px;
-  margin: 2px 0;
+  height: 30px;
+  min-width: 150px;
+  margin: 4px 0;
 }
 
 #searchInput {
   border-radius: 0;
 }
 
 /* Subcategory title */
 
@@ -144,16 +147,17 @@ separator.thin:not([orient="vertical"]) 
 
 #startupPageBox {
   padding-top: 32px;
 }
 
 #browserHomePage {
   margin-inline-start: 0;
   margin-inline-end: 0;
+  margin-bottom: 4px;
 }
 
 .homepage-button:first-of-type {
   margin-inline-start: 0;
 }
 
 .homepage-button:last-of-type {
   margin-inline-end: 0;
@@ -185,17 +189,17 @@ separator.thin:not([orient="vertical"]) 
 }
 
 #updateApp > .groupbox-body > description {
   line-height: 30px;
   margin: 0;
 }
 
 #updateBox {
-  margin-top: 8px;
+  margin-top: 4px;
   margin-bottom: 32px;
 }
 
 #updateDeck > hbox > button {
   margin-top: 0;
   margin-bottom: 0;
   margin-inline-end: 0;
 }
@@ -203,17 +207,18 @@ separator.thin:not([orient="vertical"]) 
 #updateDeck > hbox > label {
   -moz-box-flex: 1;
 }
 
 #manualLink {
   margin-inline-start: 6px !important;
 }
 
-#updateRadioGroup > radio {
+#updateRadioGroup > radio,
+#browserStartupPage > radio {
   height: 30px;
   margin: 2px 0;
 }
 
 #filter {
   margin: 4px 0 8px 0;
 }
 
@@ -252,21 +257,16 @@ separator.thin:not([orient="vertical"]) 
 }
 
 .actionsMenu > menupopup > menuitem > .menu-iconic-left {
   margin-inline-end: 8px !important;
 }
 
 /* Search Pane */
 
-#defaultEngine {
-  margin-top: 2px;
-  margin-bottom: 6px;
-}
-
 #engineList {
   margin: 2px 0 5px 0;
 }
 
 #engineList > treechildren::-moz-tree-image(engineShown, checked),
 #blocklistsTree > treechildren::-moz-tree-image(selectionCol, checked) {
   list-style-image: url("chrome://global/skin/in-content/check.svg");
   -moz-context-properties: fill, stroke;
@@ -489,19 +489,23 @@ separator.thin:not([orient="vertical"]) 
 }
 
 #fxaNoLoginStatus {
   margin-top: 46px;
   margin-bottom: 64px;
 }
 
 #fxaSyncComputerName {
-  margin-top: 3px;
   margin-inline-start: 0;
-  margin-bottom: 0;
+  margin-bottom: 4px;
+}
+
+#fxaChangeDeviceName {
+  margin-top: 4px;
+  margin-bottom: 4px;
 }
 
 #tosPP-small-ToS {
   margin-bottom: 14px;
 }
 
 #noFxaCaption {
   line-height: 30px;
@@ -670,17 +674,17 @@ separator.thin:not([orient="vertical"]) 
 
 .search-tooltip {
   font-size: 1.25rem;
   position: absolute;
   padding: 0 10px;
   background-color: #ffe900;
   border: 1px solid #d7b600;
   -moz-user-select: none;
-  bottom: 35px;
+  bottom: 36px;
 }
 
 .search-tooltip:hover,
 .search-tooltip:hover::before {
   opacity: .1;
 }
 
 .search-tooltip::before {
@@ -704,16 +708,22 @@ separator.thin:not([orient="vertical"]) 
 .search-tooltip-parent {
   position: relative;
 }
 
 .visually-hidden {
   visibility: hidden;
 }
 
+menulist {
+  height: 30px;
+  margin-top: 4px;
+  margin-bottom: 4px;
+}
+
 menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left {
   display: -moz-box;
   min-width: auto; /* Override the min-width defined in menu.css */
   margin-inline-end: 6px;
 }
 
 menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left > .menu-iconic-icon {
   width: 8px;
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -5,17 +5,16 @@
 # This is not a complete / proper jar manifest. It is included by the
 # actual theme-specific manifests, so that shared resources need only
 # be specified once. As a result, the source file paths are relative
 # to the location of the actual manifest.
 
   skin/classic/browser/aboutNetError.css                       (../shared/aboutNetError.css)
   skin/classic/browser/blockedSite.css                         (../shared/blockedSite.css)
   skin/classic/browser/error-pages.css                         (../shared/error-pages.css)
-  skin/classic/browser/aboutRights.css                         (../shared/aboutRights.css)
 * skin/classic/browser/aboutSessionRestore.css                 (../shared/aboutSessionRestore.css)
   skin/classic/browser/aboutTabCrashed.css                     (../shared/aboutTabCrashed.css)
   skin/classic/browser/aboutWelcomeBack.css                    (../shared/aboutWelcomeBack.css)
   skin/classic/browser/addons/addon-install-blocked.svg        (../shared/addons/addon-install-blocked.svg)
   skin/classic/browser/addons/addon-install-confirm.svg        (../shared/addons/addon-install-confirm.svg)
   skin/classic/browser/addons/addon-install-downloading.svg    (../shared/addons/addon-install-downloading.svg)
   skin/classic/browser/addons/addon-install-error.svg          (../shared/addons/addon-install-error.svg)
   skin/classic/browser/addons/addon-install-installed.svg      (../shared/addons/addon-install-installed.svg)
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -265,17 +265,17 @@ toolbar .toolbarbutton-1[checked]:not(:a
   margin-top: -20px;
   margin-bottom: -20px;
 }
 
 /* ::::: bookmark buttons ::::: */
 
 toolbarbutton.bookmark-item:not(.subviewbutton) {
   margin: 0 2px;
-  padding: 0 4px;
+  padding: 1px 4px;
   -moz-appearance: none;
 }
 
 :root[uidensity=compact] toolbarbutton.bookmark-item:not(.subviewbutton) {
   margin: 0 1px;
 }
 
 :root[uidensity=touch] toolbarbutton.bookmark-item:not(.subviewbutton) {
@@ -322,11 +322,11 @@ toolbarbutton.bookmark-item {
 #PersonalToolbar .toolbarbutton-1 > .toolbarbutton-text,
 #PersonalToolbar .toolbarbutton-1 > .toolbarbutton-badge-stack {
   padding: 0 !important;
   background: none !important;
   min-height: 16px;
 }
 
 #PersonalToolbar .toolbarbutton-1 {
-  padding: 0 var(--toolbarbutton-inner-padding);
+  padding: 1px var(--toolbarbutton-inner-padding);
   border-radius: var(--toolbarbutton-border-radius);
 }
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -321,21 +321,16 @@
 }
 
 @media (-moz-windows-glass) {
   #main-window[sizemode=normal] #nav-bar {
     border-top-left-radius: 2.5px;
     border-top-right-radius: 2.5px;
   }
 
-  #main-window[sizemode=fullscreen]:not(:-moz-lwtheme) {
-    -moz-appearance: none;
-    background-color: #556;
-  }
-
   #toolbar-menubar:not(:-moz-lwtheme) {
     text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
   }
 
   #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
     color: black;
     border-radius: 4px;
@@ -346,52 +341,16 @@
   #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme {
     border-top: 2px solid;
     -moz-border-top-colors: @glassActiveBorderColor@ rgba(255,255,255,.6);
   }
 
   #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme:-moz-window-inactive {
     -moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
   }
-
-  /* Glass Fog */
-
-  #TabsToolbar:not(:-moz-lwtheme) {
-    position: relative;
-  }
-
-  #TabsToolbar:not(:-moz-lwtheme)::after {
-    /* Because we use placeholders for window controls etc. in the tabstrip,
-     * and position those with ordinal attributes, and because our layout code
-     * expects :before/:after nodes to come first/last in the frame list,
-     * we have to reorder this element to come last, hence the
-     * ordinal group value (see bug 853415). */
-    -moz-box-ordinal-group: 1001;
-    box-shadow: 0 0 30px 30px rgba(174,189,204,0.85);
-    content: "";
-    display: -moz-box;
-    height: 0;
-    margin: 0 60px; /* (30px + 30px) from box-shadow */
-    position: absolute;
-    pointer-events: none;
-    top: 50%;
-    width: -moz-available;
-    z-index: -1;
-  }
-
-  /* Need to constrain the glass fog to avoid overlapping layers, see bug 886281. */
-  #navigator-toolbox:not(:-moz-lwtheme) {
-    overflow: -moz-hidden-unscrollable;
-  }
-
-  #main-window[sizemode=normal] .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox:not(:-moz-lwtheme) {
-    position: relative;
-  }
-
-  /* End Glass Fog */
 }
 
 /* Aero Basic */
 @media (-moz-windows-compositor: 0) {
   @media (-moz-windows-default-theme) {
     #main-window {
       background-color: rgb(185,209,234);
     }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -98,16 +98,47 @@
   color: var(--toolbar-color, inherit);
 }
 
 #toolbar-menubar,
 #TabsToolbar {
   color: var(--titlebar-text-color);
 }
 
+/*
+ * Windows 7 draws the chrome background color as the tab background
+ * instead of in the tabs toolbar.
+ */
+@media (-moz-os-version: windows-win7) {
+  @media (-moz-windows-default-theme) {
+    :root:not(:-moz-lwtheme) {
+      --tabs-border: #4A4A4F;
+    }
+
+    #TabsToolbar:not(:-moz-lwtheme) {
+      color: hsl(240,9%,98%);
+    }
+
+    /* Always show full-height tab separators on tabs with borders. */
+    .tabbrowser-tab:not(:-moz-lwtheme)::before {
+      border-image: none !important;
+    }
+
+    /* Show the tabs toolbar background color inside tabs on Win 7. */
+    .tab-background:not(:-moz-lwtheme):not([selected=true]) {
+      background-color: hsl(235,33%,19%) !important;
+    }
+
+    /* Show border on tabs with background colors in Windows 7. */
+    .tab-background:not(:-moz-lwtheme) {
+      border-top: 1px solid var(--tabs-border);
+    }
+  }
+}
+
 @media (-moz-windows-compositor: 0),
        (-moz-windows-default-theme: 0) {
   /* Please keep the menu text colors in this media block in sync with
    * compacttheme.css, minus the :not(:-moz-lwtheme) condition - see Bug 1165718.
    */
   :root[tabsintitlebar]:not([inFullscreen]):not(:-moz-lwtheme) {
     --titlebar-text-color: CaptionText;
   }
@@ -1077,24 +1108,16 @@ notification[value="translation"] {
  * labels during the customize mode transition. Subpixel anti-aliasing
  * on Windows with Direct2D layers acceleration is particularly slow to
  * paint, so this hack is how we sidestep that performance bottleneck.
  */
 #main-window:-moz-any([customize-entering],[customize-exiting]) label {
   transform: perspective(0.01px);
 }
 
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="left"] {
-  margin-right: -2px;
-}
-
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="right"] {
-  margin-left: -2px;
-}
-
 /* End customization mode */
 
 /* Private browsing indicators */
 
 /**
  * Currently, we have two places where we put private browsing indicators on
  * Windows. When tabsintitlebar is enabled, we draw the indicator in the titlebar.
  * When tabsintitlebar is disabled, we draw the indicator at the end of the
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -13,88 +13,80 @@
    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 {
     visibility: visible;
   }
-
-  #main-window {
-    background: var(--chrome-background-color) !important;
-  }
 }
 
 @media (-moz-windows-compositor) {
   #main-window {
     background: transparent !important;
   }
 }
 
 #toolbar-menubar {
   text-shadow: none !important;
 }
 
 @media (-moz-windows-glass) {
+  /* Always show light toolbar elements on aero glass surface. */
+  #TabsToolbar {
+    color: hsl(240,9%,98%);
+  }
+
+  /* Keep showing the correct color inside the tabs. */
   .tabbrowser-tab {
-    background-color: var(--chrome-background-color);
+    color: var(--chrome-color) !important;
+  }
+
+  /* Make the menubar text readable on aero glass (copied from browser-aero.css). */
+  #toolbar-menubar {
+    text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
+  }
+
+  #main-menubar:not(:-moz-window-inactive) {
+    background-color: rgba(255,255,255,.5);
+    color: black;
+    border-radius: 4px;
+  }
+}
+
+/* Windows 7 specific tab styles that apply to default, dark and light themes
+ * (the default theme counterpart lives in browser.css) */
+@media (-moz-os-version: windows-win7) {
+  /* Always show full-height tab separators on tabs with borders. */
+  .tabbrowser-tab::before {
+    border-image: none !important;
+  }
+
+  /* Show the tabs toolbar background color inside tabs on Win 7. */
+  .tab-background:not([selected=true]) {
+    background-color: var(--chrome-background-color) !important;
+  }
+
+  /* Show border on tabs with background colors in Windows 7. */
+  .tab-background {
+    border-top: 1px solid var(--tabs-border);
   }
 }
 
 @media (-moz-os-version: windows-win7),
        (-moz-os-version: windows-win8) {
-  /* It'd be nice if there was an element in the scrollbox's inner content
-     that collapsed to the current width of the tabs. Since there isn't we
-     need to handle overflowing and non-overflowing tabs separately.
-
-     In the case of overflowing tabs, set a border-top on the entire container,
-     otherwise we need to set it on each element individually */
-  #main-window[sizemode=normal] .tabbrowser-tabs[overflow="true"] {
-    background-clip: padding-box;
-    border-top: 1px solid var(--chrome-nav-bar-separator-color);
-    border-inline-end: 1px solid var(--chrome-nav-bar-separator-color);
-  }
-
-  /* Add a border to the left of the first tab (or scroll arrow).  Using .tabbrowser-tabs
-     instead of #TabsToolbar because it will work even in customize mode. */
-  #main-window[sizemode=normal] .tabbrowser-tabs {
-    background-clip: padding-box;
-    border-inline-start: 1px solid var(--chrome-nav-bar-separator-color);
-    border-inline-end: 1px solid transparent;
-  }
-
-  #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .closing-tabs-spacer {
-    background-clip: padding-box;
-    border-inline-start: 1px solid var(--chrome-nav-bar-separator-color);
-  }
-
   /* Use default window colors when in non-maximized mode */
   #tabbrowser-tabs,
   #TabsToolbar,
   #browser-panel,
   #titlebar-content {
     background: transparent;
   }
 
-  /* Ensure that the entire background is styled when maximized/fullscreen */
-  #main-window:not([sizemode="normal"]):not([customizing]) #browser-panel {
-    background: var(--chrome-background-color) !important;
-  }
-
-  /* The menu items need to be visible when the entire background is styled */
-  #main-window:not([sizemode="normal"]) #main-menubar {
-    color: var(--chrome-color);
-    background-color: transparent;
-  }
-
-  #main-window[sizemode="maximized"] #main-menubar > menu:not(:-moz-window-inactive) {
-    color: inherit;
-  }
-
   /* Use proper menu text styling in Win7 classic mode (copied from browser.css) */
   @media (-moz-windows-compositor: 0),
          (-moz-windows-default-theme: 0) {
     :root[tabsintitlebar]:not([inFullscreen]) {
       --titlebar-text-color: CaptionText;
     }
 
     :root[tabsintitlebar]:not([inFullscreen]):-moz-window-inactive {
--- a/browser/themes/windows/preferences/in-content/preferences.css
+++ b/browser/themes/windows/preferences/in-content/preferences.css
@@ -18,14 +18,13 @@ caption > label:not(.dialogTitle) {
 .help-button {
   font-size: 1.08rem;
 }
 
 .actionsMenu > .menulist-label-box > .menulist-icon {
   margin-inline-end: 9px;
 }
 
-textbox + button,
 filefield + button {
   margin-inline-start: -4px;
   margin-top: 4px;
   margin-bottom: 4px;
 }
--- a/devtools/client/commandline/test/browser_cmd_appcache_invalid.js
+++ b/devtools/client/commandline/test/browser_cmd_appcache_invalid.js
@@ -49,17 +49,17 @@ function* spawnTest() {
       "after http://sub1.test1.example.com/browser/devtools/client/" +
       "commandline/test/browser_cmd_appcache_invalid_appcache.appcache. Unless " +
       "the text in the manifest file is changed the cached version will be used " +
       "instead at line 39.",
     "browser_cmd_appcache_invalid_page3.html has cache-control set to no-store. " +
       "This will prevent the application cache from storing the file at line 39.",
     "http://example.com/logo.png points to a resource that is not available at line 40.",
     "http://example.com/check.png points to a resource that is not available at line 41.",
-    "Spaces in URIs need to be replaced with % at line 42.",
+    "Spaces in URIs need to be replaced with %20 at line 42.",
     "http://example.com/cr oss.png points to a resource that is not available at line 42.",
     "Asterisk (*) incorrectly used in the CACHE section at line 43. If a line " +
       "in the NETWORK section contains only a single asterisk character, then " +
       "any URI not listed in the manifest will be treated as if the URI was " +
       "listed in the NETWORK section. Otherwise such URIs will be treated as " +
       "unavailable. Other uses of the * character are prohibited",
     "The SETTINGS section may only contain a single value, \u201cprefer-online\u201d or \u201cfast\u201d at line 47.",
     "FALLBACK section line 50 (/section1/ /offline1.html) prevents caching of " +
--- a/devtools/client/locales/en-US/appcacheutils.properties
+++ b/devtools/client/locales/en-US/appcacheutils.properties
@@ -75,20 +75,22 @@ firstLineMustBeCacheManifest=The first line of the manifest must be “CACHE MANIFEST” at line %S.
 # Parameters: %S is the line number where "CACHE MANIFEST" appears.
 cacheManifestOnlyFirstLine2=“CACHE MANIFEST” is only valid on the first line but was found at line %S.
 
 # LOCALIZATION NOTE (asteriskInWrongSection2): the associated cache manifest
 # has an asterisk (*) in a section other than the NETWORK section. Parameters:
 # %1$S is the section name, %2$S is the line number.
 asteriskInWrongSection2=Asterisk (*) incorrectly used in the %1$S section at line %2$S. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section. Otherwise such URIs will be treated as unavailable. Other uses of the * character are prohibited.
 
-# LOCALIZATION NOTE (escapeSpaces): the associated cache manifest has a space
+# LOCALIZATION NOTE (escapeSpaces1): the associated cache manifest has a space
 # in a URI. Spaces must be replaced with %20. Parameters: %S is the line
 # number where this error occurs.
-escapeSpaces=Spaces in URIs need to be replaced with %20 at line %S.
+# %% will be displayed as a single % character (% is commonly used to define
+# format specifiers, so it needs to be escaped).
+escapeSpaces1=Spaces in URIs need to be replaced with %%20 at line %S.
 
 # LOCALIZATION NOTE (slashDotDotSlashBad): the associated cache manifest has a
 # URI containing /../, which is invalid. Parameters: %S is the line number
 # where this error occurs.
 slashDotDotSlashBad=/../ is not a valid URI prefix at line %S.
 
 # LOCALIZATION NOTE (tooManyDotDotSlashes): the associated cache manifest has
 # a URI containing too many ../ operators. Too many of these operators mean
--- a/devtools/client/shared/AppCacheUtils.jsm
+++ b/devtools/client/shared/AppCacheUtils.jsm
@@ -444,17 +444,17 @@ ManifestParser.prototype = {
       if (this.currSection != "NETWORK" || text.length != 1) {
         this._addError(this.currentLine, "asteriskInWrongSection2",
                        this.currSection, this.currentLine);
         return;
       }
     }
 
     if (/\s/.test(text)) {
-      this._addError(this.currentLine, "escapeSpaces", this.currentLine);
+      this._addError(this.currentLine, "escapeSpaces1", this.currentLine);
       text = text.replace(/\s/g, "%20");
     }
 
     if (text[0] == "/") {
       if (text.substr(0, 4) == "/../") {
         this._addError(this.currentLine, "slashDotDotSlashBad", this.currentLine);
       } else {
         this.uris.push(this._wrapURI(this.origin + text.substring(1)));
@@ -497,17 +497,17 @@ ManifestParser.prototype = {
 
     let [ namespace, fallback ] = split;
 
     if (namespace.indexOf("*") != -1) {
       this._addError(this.currentLine, "fallbackAsterisk2", this.currentLine);
     }
 
     if (/\s/.test(namespace)) {
-      this._addError(this.currentLine, "escapeSpaces", this.currentLine);
+      this._addError(this.currentLine, "escapeSpaces1", this.currentLine);
       namespace = namespace.replace(/\s/g, "%20");
     }
 
     if (namespace.substr(0, 4) == "/../") {
       this._addError(this.currentLine, "slashDotDotSlashBad", this.currentLine);
     }
 
     if (namespace.substr(0, 2) == "./") {
--- a/devtools/client/shared/components/notification-box.css
+++ b/devtools/client/shared/components/notification-box.css
@@ -78,17 +78,17 @@
   height: 20px;
   margin: 4px;
   margin-inline-end: 8px;
   background-image: url("chrome://devtools/skin/images/close.svg");
   background-position: center;
   background-color: transparent;
   background-repeat: no-repeat;
   border-radius: 11px;
-  filter: invert(0);
+  filter: var(--theme-messageCloseButtonFilter);
 }
 
 .notificationbox .messageCloseButton:hover {
   background-color: gray;
   filter: invert(1);
 }
 
 .notificationbox .messageCloseButton:active {
--- a/devtools/client/themes/variables.css
+++ b/devtools/client/themes/variables.css
@@ -93,16 +93,17 @@
   --theme-tooltip-background: rgba(255, 255, 255, .9);
   --theme-tooltip-shadow: rgba(155, 155, 155, 0.26);
 
   /* Command line */
   --theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme);
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme-focus);
 
   --theme-codemirror-gutter-background: #f4f4f4;
+  --theme-messageCloseButtonFilter: invert(0);
 }
 
 :root.theme-dark {
   --theme-body-background: var(--grey-80);
   --theme-sidebar-background: var(--grey-90);
   --theme-contrast-background: #ffb35b;
 
   /* Toolbar */
@@ -177,16 +178,17 @@
   --theme-tooltip-background: rgba(19, 28, 38, .9);
   --theme-tooltip-shadow: rgba(25, 25, 25, 0.76);
 
   /* Command line */
   --theme-command-line-image: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme);
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme-focus);
 
   --theme-codemirror-gutter-background: #262b37;
+  --theme-messageCloseButtonFilter: invert(1);
 }
 
 :root.theme-firebug {
   --theme-body-background: #fff;
   --theme-sidebar-background: #fcfcfc;
   --theme-contrast-background: #e6b064;
 
   --theme-tab-toolbar-background: rgb(240, 240, 240) linear-gradient(rgba(255, 255, 255, 0.8), transparent);
--- a/devtools/server/actors/highlighters.css
+++ b/devtools/server/actors/highlighters.css
@@ -20,16 +20,18 @@
   Content CSS applying to the html element impact the highlighters.
   To avoid that, possible cases have been set to initial.
   */
   text-transform: initial;
   text-indent: initial;
   letter-spacing: initial;
   word-spacing: initial;
   color: initial;
+  direction: initial;
+  writing-mode: initial;
 }
 
 :-moz-native-anonymous .highlighter-container {
   --highlighter-guide-color: #08c;
   --highlighter-content-color: #87ceeb;
   --highlighter-bubble-text-color: hsl(216, 33%, 97%);
   --highlighter-bubble-background-color: hsl(214, 13%, 24%);
   --highlighter-bubble-border-color: rgba(255, 255, 255, 0.2);
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1714,35 +1714,33 @@ nsMessageManagerScriptExecutor::Unlink()
 bool
 nsMessageManagerScriptExecutor::InitChildGlobalInternal(
   nsISupports* aScope,
   const nsACString& aID)
 {
   AutoSafeJSContext cx;
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
-  nsIXPConnect* xpc = nsContentUtils::XPConnect();
-  const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
+  const uint32_t flags = xpc::INIT_JS_STANDARD_CLASSES;
 
   JS::CompartmentOptions options;
   options.creationOptions().setSystemZone();
   options.behaviors().setVersion(JSVERSION_DEFAULT);
 
   if (xpc::SharedMemoryEnabled()) {
     options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
   }
 
-  nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
-  nsresult rv =
-    xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
-                                         flags, options,
-                                         getter_AddRefs(globalHolder));
+  JS::Rooted<JSObject*> global(cx);
+  nsresult rv = xpc::InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
+                                                     flags, options,
+                                                     &global);
   NS_ENSURE_SUCCESS(rv, false);
 
-  mGlobal = globalHolder->GetJSObject();
+  mGlobal = global;
   NS_ENSURE_TRUE(mGlobal, false);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information.
   xpc::SetLocationForGlobal(mGlobal, aID);
 
   DidCreateGlobal();
   return true;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2943,18 +2943,18 @@ CreateNativeGlobalForInner(JSContext* aC
 
   options.creationOptions().setSecureContext(aIsSecureContext);
 
   xpc::InitGlobalObjectOptions(options, aPrincipal);
 
   // Determine if we need the Components object.
   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
                         TreatAsRemoteXUL(aPrincipal);
-  uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
-  flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
+  uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
+  flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
 
   if (!WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
                            nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
       !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3754,55 +3754,63 @@ HTMLMediaElement::LookupMediaElementURIT
       if (decoder->CanClone()) {
         return elem;
       }
     }
   }
   return nullptr;
 }
 
-class HTMLMediaElement::ShutdownObserver : public nsIObserver {
-  enum class Phase : int8_t {
+class HTMLMediaElement::ShutdownObserver : public nsIObserver
+{
+  enum class Phase : int8_t
+  {
     Init,
     Subscribed,
     Unsubscribed
   };
+
 public:
   NS_DECL_ISUPPORTS
 
-  NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*) override {
-    MOZ_DIAGNOSTIC_ASSERT(mPhase == Phase::Subscribed);
+  NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*) override
+  {
+    if (mPhase != Phase::Subscribed) {
+      // Bail out if we are not subscribed for this might be called even after
+      // |nsContentUtils::UnregisterShutdownObserver(this)|.
+      return NS_OK;
+    }
     MOZ_DIAGNOSTIC_ASSERT(mWeak);
     if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
       mWeak->NotifyShutdownEvent();
     }
     return NS_OK;
   }
-  void Subscribe(HTMLMediaElement* aPtr) {
+  void Subscribe(HTMLMediaElement* aPtr)
+  {
     MOZ_DIAGNOSTIC_ASSERT(mPhase == Phase::Init);
     MOZ_DIAGNOSTIC_ASSERT(!mWeak);
     mWeak = aPtr;
     nsContentUtils::RegisterShutdownObserver(this);
     mPhase = Phase::Subscribed;
   }
-  void Unsubscribe() {
+  void Unsubscribe()
+  {
     MOZ_DIAGNOSTIC_ASSERT(mPhase == Phase::Subscribed);
     MOZ_DIAGNOSTIC_ASSERT(mWeak);
     mWeak = nullptr;
     nsContentUtils::UnregisterShutdownObserver(this);
     mPhase = Phase::Unsubscribed;
   }
-  void AddRefMediaElement() {
-    mWeak->AddRef();
-  }
-  void ReleaseMediaElement() {
-    mWeak->Release();
-  }
+  void AddRefMediaElement() { mWeak->AddRef(); }
+  void ReleaseMediaElement() { mWeak->Release(); }
+
 private:
-  virtual ~ShutdownObserver() {
+  virtual ~ShutdownObserver()
+  {
     MOZ_DIAGNOSTIC_ASSERT(mPhase == Phase::Unsubscribed);
     MOZ_DIAGNOSTIC_ASSERT(!mWeak);
   }
   // Guaranteed to be valid by HTMLMediaElement.
   HTMLMediaElement* mWeak = nullptr;
   Phase mPhase = Phase::Init;
 };
 
--- a/dom/media/ChannelMediaResource.cpp
+++ b/dom/media/ChannelMediaResource.cpp
@@ -259,16 +259,21 @@ ChannelMediaResource::OnStartRequest(nsI
     // and the server isn't sending Accept-Ranges:bytes then we don't
     // support seeking. We also can't seek in compressed streams.
     seekable = !isCompressed && acceptsRanges;
   } else {
     // Not an HTTP channel. Assume data will be sent from position zero.
     startOffset = 0;
   }
 
+  // Update principals before OnDataAvailable() putting the data in the cache.
+  // This is important, we want to make sure all principals are updated before
+  // any consumer can see the new data.
+  UpdatePrincipal();
+
   mCacheStream.NotifyDataStarted(mLoadID, startOffset);
   mCacheStream.SetTransportSeekable(seekable);
   mChannelStatistics.Start();
   mReopenOnError = false;
 
   mSuspendAgent.UpdateSuspendedStatusIfNeeded();
 
   // Fires an initial progress event.
@@ -408,22 +413,16 @@ nsresult
 ChannelMediaResource::OnDataAvailable(uint32_t aLoadID,
                                       nsIInputStream* aStream,
                                       uint32_t aCount)
 {
   // This might happen off the main thread.
   // Don't assert |mChannel.get() == aRequest| since reading mChannel here off
   // the main thread is a data race.
 
-  // Update principals before putting the data in the cache. This is important,
-  // we want to make sure all principals are updated before any consumer can see
-  // the new data.
-  // TODO: Handle the case where OnDataAvailable() runs off the main thread.
-  UpdatePrincipal();
-
   RefPtr<ChannelMediaResource> self = this;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
     "ChannelMediaResource::OnDataAvailable",
     [self, aCount]() { self->mChannelStatistics.AddBytes(aCount); });
   mCallback->AbstractMainThread()->Dispatch(r.forget());
 
   Closure closure{ aLoadID, this };
   uint32_t count = aCount;
@@ -779,19 +778,20 @@ ChannelMediaResource::CacheClientNotifyP
 
   mCallback->NotifyPrincipalChanged();
 }
 
 void
 ChannelMediaResource::UpdatePrincipal()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mChannel);
   nsCOMPtr<nsIPrincipal> principal;
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
-  if (secMan && mChannel) {
+  if (secMan) {
     secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
     mCacheStream.UpdatePrincipal(principal);
   }
 }
 
 void
 ChannelMediaResource::CacheClientNotifySuspendedStatusChanged()
 {
--- a/dom/svg/SVGLength.cpp
+++ b/dom/svg/SVGLength.cpp
@@ -18,21 +18,17 @@ namespace mozilla {
 
 // Declare some helpers defined below:
 static void GetUnitString(nsAString& unit, uint16_t unitType);
 static uint16_t GetUnitTypeForString(const nsAString& unitStr);
 
 void
 SVGLength::GetValueAsString(nsAString &aValue) const
 {
-  char16_t buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
-                            u"%g",
-                            (double)mValue);
-  aValue.Assign(buf);
+  nsTextFormatter::ssprintf(aValue, u"%g", (double)mValue);
 
   nsAutoString unitString;
   GetUnitString(unitString, mUnit);
   aValue.Append(unitString);
 }
 
 bool
 SVGLength::SetValueFromString(const nsAString &aString)
--- a/dom/svg/SVGPathSegUtils.cpp
+++ b/dom/svg/SVGPathSegUtils.cpp
@@ -70,25 +70,16 @@ SVGPathSegUtils::GetValueAsString(const 
       break;
 
     default:
       MOZ_ASSERT(false, "Unknown segment type");
       aValue = u"<unknown-segment-type>";
       return;
     }
   }
-
-  // nsTextFormatter::ssprintf is one of the nsTextFormatter methods that
-  // randomly appends '\0' to its output string, which means that the length
-  // of the output string is one too long. We need to manually remove that '\0'
-  // until nsTextFormatter is fixed.
-  //
-  if (aValue[aValue.Length() - 1] == char16_t('\0')) {
-    aValue.SetLength(aValue.Length() - 1);
-  }
 }
 
 
 static float
 CalcDistanceBetweenPoints(const Point& aP1, const Point& aP2)
 {
   return NS_hypot(aP2.x - aP1.x, aP2.y - aP1.y);
 }
--- a/dom/svg/nsSVGAngle.cpp
+++ b/dom/svg/nsSVGAngle.cpp
@@ -78,21 +78,17 @@ GetUnitTypeForString(const nsAString& un
   }
 
   return SVG_ANGLETYPE_UNKNOWN;
 }
 
 static void
 GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType)
 {
-  char16_t buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
-                            u"%g",
-                            (double)aValue);
-  aValueAsString.Assign(buf);
+  nsTextFormatter::ssprintf(aValueAsString, u"%g", (double)aValue);
 
   nsAutoString unitString;
   GetUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 static bool
 GetValueFromString(const nsAString& aString,
--- a/dom/svg/nsSVGLength2.cpp
+++ b/dom/svg/nsSVGLength2.cpp
@@ -81,21 +81,17 @@ GetUnitTypeForString(const nsAString& un
   }
 
   return nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN;
 }
 
 static void
 GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType)
 {
-  char16_t buf[24];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
-                            u"%g",
-                            (double)aValue);
-  aValueAsString.Assign(buf);
+  nsTextFormatter::ssprintf(aValueAsString, u"%g", (double)aValue);
 
   nsAutoString unitString;
   GetUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 static bool
 GetValueFromString(const nsAString& aString,
--- a/dom/svg/nsSVGTransform.cpp
+++ b/dom/svg/nsSVGTransform.cpp
@@ -13,69 +13,65 @@ namespace {
   const double kRadPerDegree = 2.0 * M_PI / 360.0;
 } // namespace
 
 namespace mozilla {
 
 void
 nsSVGTransform::GetValueAsString(nsAString& aValue) const
 {
-  char16_t buf[256];
-
   switch (mType) {
     case SVG_TRANSFORM_TRANSLATE:
       // The spec say that if Y is not provided, it is assumed to be zero.
       if (mMatrix._32 != 0)
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"translate(%g, %g)",
             mMatrix._31, mMatrix._32);
       else
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"translate(%g)",
             mMatrix._31);
       break;
     case SVG_TRANSFORM_ROTATE:
       if (mOriginX != 0.0f || mOriginY != 0.0f)
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"rotate(%g, %g, %g)",
             mAngle, mOriginX, mOriginY);
       else
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"rotate(%g)", mAngle);
       break;
     case SVG_TRANSFORM_SCALE:
       if (mMatrix._11 != mMatrix._22)
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"scale(%g, %g)", mMatrix._11, mMatrix._22);
       else
-        nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+        nsTextFormatter::ssprintf(aValue,
             u"scale(%g)", mMatrix._11);
       break;
     case SVG_TRANSFORM_SKEWX:
-      nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+      nsTextFormatter::ssprintf(aValue,
                                 u"skewX(%g)", mAngle);
       break;
     case SVG_TRANSFORM_SKEWY:
-      nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+      nsTextFormatter::ssprintf(aValue,
                                 u"skewY(%g)", mAngle);
       break;
     case SVG_TRANSFORM_MATRIX:
-      nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+      nsTextFormatter::ssprintf(aValue,
           u"matrix(%g, %g, %g, %g, %g, %g)",
                             mMatrix._11, mMatrix._12,
                             mMatrix._21, mMatrix._22,
                             mMatrix._31, mMatrix._32);
       break;
     default:
-      buf[0] = '\0';
+      aValue.Truncate();
       NS_ERROR("unknown transformation type");
       break;
   }
-
-  aValue.Assign(buf);
 }
 
 void
 nsSVGTransform::SetMatrix(const gfxMatrix& aMatrix)
 {
   mType    = SVG_TRANSFORM_MATRIX;
   mMatrix  = aMatrix;
   // We set the other members here too, since operator== requires it and
--- a/dom/svg/nsSVGViewBox.cpp
+++ b/dom/svg/nsSVGViewBox.cpp
@@ -201,22 +201,20 @@ nsSVGViewBox::SetBaseValueString(const n
 
 void
 nsSVGViewBox::GetBaseValueString(nsAString& aValue) const
 {
   if (mBaseVal.none) {
     aValue.AssignLiteral("none");
     return;
   }
-  char16_t buf[200];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
+  nsTextFormatter::ssprintf(aValue,
                             u"%g %g %g %g",
                             (double)mBaseVal.x, (double)mBaseVal.y,
                             (double)mBaseVal.width, (double)mBaseVal.height);
-  aValue.Assign(buf);
 }
 
 
 already_AddRefed<dom::SVGAnimatedRect>
 nsSVGViewBox::ToSVGAnimatedRect(nsSVGElement* aSVGElement)
 {
   RefPtr<dom::SVGAnimatedRect> domAnimatedRect =
     sSVGAnimatedRectTearoffTable.GetTearoff(this);
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -418,23 +418,16 @@ XPCShellEnvironment::Init()
     // unbuffer stdout so that output is in the correct order; note that stderr
     // is unbuffered by default
     setbuf(stdout, 0);
 
     AutoSafeJSContext cx;
 
     mGlobalHolder.init(cx);
 
-    nsCOMPtr<nsIXPConnect> xpc =
-      do_GetService(nsIXPConnect::GetCID());
-    if (!xpc) {
-        NS_ERROR("failed to get nsXPConnect service!");
-        return false;
-    }
-
     nsCOMPtr<nsIPrincipal> principal;
     nsCOMPtr<nsIScriptSecurityManager> securityManager =
         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     if (NS_SUCCEEDED(rv) && securityManager) {
         rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
         if (NS_FAILED(rv)) {
             fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
         }
@@ -450,28 +443,27 @@ XPCShellEnvironment::Init()
     }
 
     JS::CompartmentOptions options;
     options.creationOptions().setSystemZone();
     options.behaviors().setVersion(JSVERSION_DEFAULT);
     if (xpc::SharedMemoryEnabled())
         options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
 
-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    rv = xpc->InitClassesWithNewWrappedGlobal(cx,
+    JS::Rooted<JSObject*> globalObj(cx);
+    rv = xpc::InitClassesWithNewWrappedGlobal(cx,
                                               static_cast<nsIGlobalObject *>(backstagePass),
                                               principal, 0,
                                               options,
-                                              getter_AddRefs(holder));
+                                              &globalObj);
     if (NS_FAILED(rv)) {
         NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
         return false;
     }
 
-    JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
     if (!globalObj) {
         NS_ERROR("Failed to get global JSObject!");
         return false;
     }
     JSAutoCompartment ac(cx, globalObj);
 
     backstagePass->SetGlobalObject(globalObj);
 
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -787,17 +787,17 @@ static void
 DumpName(GenericPrinter& out, const CharT* s, size_t len)
 {
     if (len == 0)
         out.put("#<zero-length name>");
 
     for (size_t i = 0; i < len; i++) {
         char16_t c = s[i];
         if (c > 32 && c < 127)
-            fputc(c, stderr);
+            out.putChar(c);
         else if (c <= 255)
             out.printf("\\x%02x", unsigned(c));
         else
             out.printf("\\u%04x", unsigned(c));
     }
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1401014.js
@@ -0,0 +1,52 @@
+// Prevent optimizing top-level
+with ({}) { }
+
+
+// Unboxed object constructor candidate
+function Thing() {
+    this.a = {};    // Object || null
+    this.b = {};    // Object || null
+}
+
+(new Thing());
+(new Thing()).a = null;
+(new Thing()).b = null;
+
+
+var arr = new Array(1000);
+arr[0];
+
+var ctx = new Thing();
+
+function funPsh(t, x) {
+    t.a = x;
+}
+
+function funBug(t, i) {
+    t.b = t.a;      // GETPROP t.a
+    t.a = null;     // SETPROP t.a
+    arr[i] = 0;     // Bailout on uninitialized elements
+    return t.b;
+}
+
+// Ion compile
+for (var i = 0; i < 20000; ++i) {
+    funBug(ctx, 0);
+    funPsh(ctx, {});
+}
+
+// Invalidate
+let tmp = { a: null, b: {} };
+funBug(tmp, 0);
+
+// Ion compile
+for (var i = 0; i < 20000; ++i) {
+    funBug(ctx, 0);
+    funPsh(ctx, {});
+}
+
+// Trigger bailout
+let res = funBug(ctx, 500);
+
+// Result should not be clobbered by |t.a = null|
+assertEq(res === null, false);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -12023,20 +12023,22 @@ IonBuilder::setPropTryInlineAccess(bool*
             return Ok();
 
         obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
 
         if (needsPostBarrier(value))
             current->add(MPostWriteBarrier::New(alloc(), obj, value));
 
         const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
-        storeUnboxedProperty(obj, property->offset, property->type, value);
+        MInstruction* store = storeUnboxedProperty(obj, property->offset, property->type, value);
 
         current->push(value);
 
+        MOZ_TRY(resumeAfter(store));
+
         trackOptimizationOutcome(TrackedOutcome::Monomorphic);
         *emitted = true;
         return Ok();
     }
 
     MOZ_ASSERT(receivers.length() > 1);
     spew("Inlining polymorphic SETPROP");
 
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -275,43 +275,16 @@ interface nsIXPCFunctionThisTranslator :
 [noscript, uuid(768507b5-b981-40c7-8276-f6a1da502a24)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
-     * Creates a new global object using the given aCOMObj as the global
-     * object. The object will be set up according to the flags (defined
-     * below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj
-     * must implement nsIXPCScriptable so it can resolve the standard
-     * classes when asked by the JS engine.
-     *
-     * @param aJSContext the context to use while creating the global object.
-     * @param aCOMObj the native object that represents the global object.
-     * @param aPrincipal the principal of the code that will run in this
-     *                   compartment. Can be null if not on the main thread.
-     * @param aFlags one of the flags below specifying what options this
-     *               global object wants.
-     * @param aOptions JSAPI-specific options for the new compartment.
-     */
-    nsIXPConnectJSObjectHolder
-    initClassesWithNewWrappedGlobal(
-                  in JSContextPtr         aJSContext,
-                  in nsISupports          aCOMObj,
-                  in nsIPrincipal         aPrincipal,
-                  in uint32_t             aFlags,
-                  in JSCompartmentOptions aOptions);
-
-    const uint32_t INIT_JS_STANDARD_CLASSES  = 1 << 0;
-    const uint32_t DONT_FIRE_ONNEWGLOBALHOOK = 1 << 1;
-    const uint32_t OMIT_COMPONENTS_OBJECT    = 1 << 2;
-
-    /**
     * wrapNative will create a new JSObject or return an existing one.
     *
     * This method now correctly deals with cases where the passed in xpcom
     * object already has an associated JSObject for the cases:
     *  1) The xpcom object has already been wrapped for use in the same scope
     *     as an nsIXPConnectWrappedNative.
     *  2) The xpcom object is in fact a nsIXPConnectWrappedJS and thus already
     *     has an underlying JSObject.
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -508,27 +508,25 @@ mozJSComponentLoader::CreateLoaderGlobal
     options.behaviors().setVersion(JSVERSION_DEFAULT);
 
     if (xpc::SharedMemoryEnabled())
         options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
 
     // Defer firing OnNewGlobalObject until after the __URI__ property has
     // been defined so the JS debugger can tell what module the global is
     // for
-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    rv = nsXPConnect::XPConnect()->
-        InitClassesWithNewWrappedGlobal(aCx,
-                                        static_cast<nsIGlobalObject*>(backstagePass),
-                                        nsContentUtils::GetSystemPrincipal(),
-                                        nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK,
-                                        options,
-                                        getter_AddRefs(holder));
+    RootedObject global(aCx);
+    rv = xpc::InitClassesWithNewWrappedGlobal(aCx,
+                                              static_cast<nsIGlobalObject*>(backstagePass),
+                                              nsContentUtils::GetSystemPrincipal(),
+                                              xpc::DONT_FIRE_ONNEWGLOBALHOOK,
+                                              options,
+                                              &global);
     NS_ENSURE_SUCCESS_VOID(rv);
 
-    RootedObject global(aCx, holder->GetJSObject());
     NS_ENSURE_TRUE_VOID(global);
 
     backstagePass->SetGlobalObject(global);
 
     JSAutoCompartment ac(aCx, global);
     if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
         !JS_DefineProfilingFunctions(aCx, global)) {
         return;
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1301,24 +1301,23 @@ XRE_XPCShellMain(int argc, char** argv, 
 
         // Make the default XPCShell global use a fresh zone (rather than the
         // System Zone) to improve cross-zone test coverage.
         JS::CompartmentOptions options;
         options.creationOptions().setNewZoneInSystemZoneGroup();
         if (xpc::SharedMemoryEnabled())
             options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
         options.behaviors().setVersion(JSVERSION_DEFAULT);
-        nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-        rv = nsXPConnect::XPConnect()->
-            InitClassesWithNewWrappedGlobal(cx,
-                                            static_cast<nsIGlobalObject*>(backstagePass),
-                                            systemprincipal,
-                                            0,
-                                            options,
-                                            getter_AddRefs(holder));
+        JS::Rooted<JSObject*> glob(cx);
+        rv = xpc::InitClassesWithNewWrappedGlobal(cx,
+                                                  static_cast<nsIGlobalObject*>(backstagePass),
+                                                  systemprincipal,
+                                                  0,
+                                                  options,
+                                                  &glob);
         if (NS_FAILED(rv))
             return 1;
 
         // Initialize graphics prefs on the main thread, if not already done
         gfxPrefs::GetSingleton();
         // Initialize e10s check on the main thread, if not already done
         BrowserTabsRemoteAutostart();
 #ifdef XP_WIN
@@ -1338,17 +1337,16 @@ XRE_XPCShellMain(int argc, char** argv, 
 #endif
 #endif
 
 #ifdef MOZ_CODE_COVERAGE
         CodeCoverageHandler::Init();
 #endif
 
         {
-            JS::Rooted<JSObject*> glob(cx, holder->GetJSObject());
             if (!glob) {
                 return 1;
             }
 
             // Even if we're building in a configuration where source is
             // discarded, there's no reason to do that on XPCShell, and doing so
             // might break various automation scripts.
             JS::CompartmentBehaviorsRef(glob).setDiscardSource(false);
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -541,72 +541,71 @@ InitGlobalObject(JSContext* aJSContext, 
 {
     // Immediately enter the global's compartment so that everything we create
     // ends up there.
     JSAutoCompartment ac(aJSContext, aGlobal);
 
     // Stuff coming through this path always ends up as a DOM global.
     MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
 
-    if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
+    if (!(aFlags & xpc::OMIT_COMPONENTS_OBJECT)) {
         // XPCCallContext gives us an active request needed to save/restore.
         if (!RealmPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
             !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
             return UnexpectedFailure(false);
         }
     }
 
-    if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
+    if (!(aFlags & xpc::DONT_FIRE_ONNEWGLOBALHOOK))
         JS_FireOnNewGlobalObject(aJSContext, aGlobal);
 
     return true;
 }
 
-} // namespace xpc
-
-NS_IMETHODIMP
-nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
-                                             nsISupports* aCOMObj,
-                                             nsIPrincipal * aPrincipal,
-                                             uint32_t aFlags,
-                                             JS::CompartmentOptions& aOptions,
-                                             nsIXPConnectJSObjectHolder** _retval)
+nsresult
+InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
+                                nsISupports* aCOMObj,
+                                nsIPrincipal* aPrincipal,
+                                uint32_t aFlags,
+                                JS::CompartmentOptions& aOptions,
+                                MutableHandleObject aNewGlobal)
 {
     MOZ_ASSERT(aJSContext, "bad param");
     MOZ_ASSERT(aCOMObj, "bad param");
-    MOZ_ASSERT(_retval, "bad param");
 
     // We pass null for the 'extra' pointer during global object creation, so
     // we need to have a principal.
     MOZ_ASSERT(aPrincipal);
 
     InitGlobalObjectOptions(aOptions, aPrincipal);
 
     // Call into XPCWrappedNative to make a new global object, scope, and global
     // prototype.
     xpcObjectHelper helper(aCOMObj);
     MOZ_ASSERT(helper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
     RefPtr<XPCWrappedNative> wrappedGlobal;
     nsresult rv =
         XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
-                                        aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
+                                        aFlags & xpc::INIT_JS_STANDARD_CLASSES,
                                         aOptions, getter_AddRefs(wrappedGlobal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Grab a copy of the global and enter its compartment.
     RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
     MOZ_ASSERT(JS_IsGlobalObject(global));
 
     if (!InitGlobalObject(aJSContext, global, aFlags))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    wrappedGlobal.forget(_retval);
+    aNewGlobal.set(global);
     return NS_OK;
 }
 
+} // namespace xpc
+
 static nsresult
 NativeInterface2JSObject(HandleObject aScope,
                          nsISupports* aCOMObj,
                          nsWrapperCache* aCache,
                          const nsIID * aIID,
                          bool aAllowWrapping,
                          MutableHandleValue aVal,
                          nsIXPConnectJSObjectHolder** aHolder)
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -170,16 +170,45 @@ bool
 XrayAwareCalleeGlobalForSpecializedGetters(JSContext* cx,
                                            JS::Handle<JSObject*> thisObj,
                                            JS::MutableHandle<JSObject*> global);
 
 
 void
 TraceXPCGlobal(JSTracer* trc, JSObject* obj);
 
+/**
+ * Creates a new global object using the given aCOMObj as the global
+ * object. The object will be set up according to the flags (defined
+ * below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj
+ * must implement nsIXPCScriptable so it can resolve the standard
+ * classes when asked by the JS engine.
+ *
+ * @param aJSContext the context to use while creating the global object.
+ * @param aCOMObj the native object that represents the global object.
+ * @param aPrincipal the principal of the code that will run in this
+ *                   compartment. Can be null if not on the main thread.
+ * @param aFlags one of the flags below specifying what options this
+ *               global object wants.
+ * @param aOptions JSAPI-specific options for the new compartment.
+ */
+nsresult
+InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
+                                nsISupports* aCOMObj,
+                                nsIPrincipal* aPrincipal,
+                                uint32_t aFlags,
+                                JS::CompartmentOptions& aOptions,
+                                JS::MutableHandleObject aNewGlobal);
+
+enum InitClassesFlag {
+    INIT_JS_STANDARD_CLASSES  = 1 << 0,
+    DONT_FIRE_ONNEWGLOBALHOOK = 1 << 1,
+    OMIT_COMPONENTS_OBJECT    = 1 << 2,
+};
+
 } /* namespace xpc */
 
 namespace JS {
 
 struct RuntimeStats;
 
 } // namespace JS
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1550,17 +1550,17 @@ private:
   nsDisplayItem*                 mGlassDisplayItem;
   // A temporary list that we append scroll info items to while building
   // display items for the contents of frames with SVG effects.
   // Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
   // This is a pointer and not a real nsDisplayList value because the
   // nsDisplayList class is defined below this class, so we can't use it here.
   nsDisplayList*                 mScrollInfoItemsForHoisting;
   nsTArray<ActiveScrolledRoot*>  mActiveScrolledRoots;
-  nsTArray<DisplayItemClipChain*> mClipChainsToDestroy;
+  AutoTArray<DisplayItemClipChain*, 128> mClipChainsToDestroy;
   nsTArray<nsDisplayItem*> mTemporaryItems;
   const ActiveScrolledRoot*      mActiveScrolledRootForRootScrollframe;
   nsDisplayListBuilderMode       mMode;
   ViewID                         mCurrentScrollParentId;
   ViewID                         mCurrentScrollbarTarget;
   uint32_t                       mCurrentScrollbarFlags;
   Preserves3DContext             mPreserves3DCtx;
   uint32_t                       mPerspectiveItemIndex;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1401317-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+.foo::-moz-list-bullet { color: red }
+.foo { color: black; }
+</style>
+</head>
+<body>
+  <ul>
+    <li class="foo">one</li>
+    <li>two</li>
+  </ul>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1401317.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+.foo::-moz-list-bullet { color: red }
+</style>
+</head>
+<body>
+  <ul>
+    <li class="foo">one</li>
+    <li>two</li>
+  </ul>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -2037,8 +2037,9 @@ needs-focus != 1377447-1.html 1377447-2.
 == 1379041.html 1379041-ref.html
 == 1379696.html 1379696-ref.html
 == 1380224-1.html 1380224-1-ref.html
 == 1384065.html 1384065-ref.html
 == 1384275-1.html 1384275-1-ref.html
 == 1381821.html 1381821-ref.html
 == 1395650-1.html 1395650-1-ref.html
 == 1398500-1.html 1398500-1-ref.html
+== 1401317.html 1401317-ref.html
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -32,16 +32,19 @@ SERVO_BINDING_FUNC(Servo_Element_GetPrim
 SERVO_BINDING_FUNC(Servo_Element_HasPseudoComputedValues, bool,
                    RawGeckoElementBorrowed node, size_t index)
 SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
                    ServoStyleContextStrong,
                    RawGeckoElementBorrowed node, size_t index)
 SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone,
                    bool,
                    RawGeckoElementBorrowed element)
+SERVO_BINDING_FUNC(Servo_Element_IsPrimaryStyleReusedViaRuleNode,
+                   bool,
+                   RawGeckoElementBorrowed element)
 
 // Styleset and Stylesheet management
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes,
                    RawServoStyleSheetContentsStrong,
                    mozilla::css::Loader* loader,
                    mozilla::ServoStyleSheet* gecko_stylesheet,
                    const uint8_t* data,
                    size_t data_len,
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -543,16 +543,26 @@ ServoStyleSet::ResolveStyleForPlaceholde
                                  InheritTarget::PlaceholderFrame)
                                  .Consume();
   MOZ_ASSERT(computedValues);
 
   cache = computedValues;
   return computedValues.forget();
 }
 
+static inline bool
+LazyPseudoIsCacheable(CSSPseudoElementType aType,
+                      Element* aOriginatingElement,
+                      ServoStyleContext* aParentContext)
+{
+  return aParentContext &&
+         !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) &&
+         !Servo_Element_IsPrimaryStyleReusedViaRuleNode(aOriginatingElement);
+}
+
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement,
                                          CSSPseudoElementType aType,
                                          ServoStyleContext* aParentContext,
                                          Element* aPseudoElement)
 {
   UpdateStylistIfNeeded();
 
@@ -561,17 +571,17 @@ ServoStyleSet::ResolvePseudoElementStyle
   RefPtr<ServoStyleContext> computedValues;
 
   if (aPseudoElement) {
     MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
     computedValues =
       Servo_ResolveStyle(aPseudoElement, mRawSet.get()).Consume();
   } else {
     bool cacheable =
-      !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) && aParentContext;
+      LazyPseudoIsCacheable(aType, aOriginatingElement, aParentContext);
     computedValues =
       cacheable ? aParentContext->GetCachedLazyPseudoStyle(aType) : nullptr;
 
     if (!computedValues) {
       computedValues = Servo_ResolvePseudoStyle(aOriginatingElement,
                                                 aType,
                                                 /* is_probe = */ false,
                                                 aParentContext,
@@ -890,17 +900,17 @@ ServoStyleSet::ProbePseudoElementStyle(E
 
   // NB: We ignore aParentContext, because in some cases
   // (first-line/first-letter on anonymous box blocks) Gecko passes something
   // nonsensical there.  In all other cases we want to inherit directly from
   // aOriginatingElement's styles anyway.
   MOZ_ASSERT(aType < CSSPseudoElementType::Count);
 
   bool cacheable =
-    !nsCSSPseudoElements::IsEagerlyCascadedInServo(aType) && aParentContext;
+    LazyPseudoIsCacheable(aType, aOriginatingElement, aParentContext);
 
   RefPtr<ServoStyleContext> computedValues =
     cacheable ? aParentContext->GetCachedLazyPseudoStyle(aType) : nullptr;
   if (!computedValues) {
     computedValues = Servo_ResolvePseudoStyle(aOriginatingElement, aType,
                                               /* is_probe = */ true,
                                               nullptr,
                                               mRawSet.get()).Consume();
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -4147,23 +4147,23 @@ ExtractImageLayerSizePairList(const nsSt
         break;
     }
   }
 
   aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget());
 }
 
 static bool
-StyleClipBasicShapeToCSSArray(const StyleShapeSource& aClipPath,
-                              nsCSSValue::Array* aResult)
+StyleShapeSourceToCSSArray(const StyleShapeSource& aShapeSource,
+                           nsCSSValue::Array* aResult)
 {
   MOZ_ASSERT(aResult->Count() == 2,
              "Expected array to be presized for a function and the sizing-box");
 
-  const StyleBasicShape* shape = aClipPath.GetBasicShape();
+  const StyleBasicShape* shape = aShapeSource.GetBasicShape();
   nsCSSKeyword functionName = shape->GetShapeTypeName();
   RefPtr<nsCSSValue::Array> functionArray;
   switch (shape->GetShapeType()) {
     case StyleBasicShapeType::Circle:
     case StyleBasicShapeType::Ellipse: {
       const nsTArray<nsStyleCoord>& coords = shape->Coordinates();
       MOZ_ASSERT(coords.Length() == ShapeArgumentCount(functionName) - 1,
                  "Unexpected radii count");
@@ -4231,17 +4231,46 @@ StyleClipBasicShapeToCSSArray(const Styl
       functionArray->Item(functionArray->Count() - 1).
                        SetArrayValue(radiusArray, eCSSUnit_Array);
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown shape type");
       return false;
   }
-  aResult->Item(1).SetEnumValue(aClipPath.GetReferenceBox());
+  aResult->Item(1).SetEnumValue(aShapeSource.GetReferenceBox());
+  return true;
+}
+
+static bool
+ExtractComputedValueFromShapeSource(const StyleShapeSource& aShapeSource,
+                                    StyleAnimationValue& aComputedValue)
+{
+  const StyleShapeSourceType type = aShapeSource.GetType();
+
+  if (type == StyleShapeSourceType::URL) {
+    auto result = MakeUnique<nsCSSValue>();
+    result->SetURLValue(aShapeSource.GetURL());
+    aComputedValue.SetAndAdoptCSSValueValue(result.release(),
+                                            StyleAnimationValue::eUnit_URL);
+  } else if (type == StyleShapeSourceType::Box) {
+    aComputedValue.SetEnumValue(aShapeSource.GetReferenceBox());
+  } else if (type == StyleShapeSourceType::Shape) {
+    RefPtr<nsCSSValue::Array> result = nsCSSValue::Array::Create(2);
+    if (!StyleShapeSourceToCSSArray(aShapeSource, result)) {
+      return false;
+    }
+    aComputedValue.SetCSSValueArrayValue(result,
+                                         StyleAnimationValue::eUnit_Shape);
+
+  } else {
+    MOZ_ASSERT(type == StyleShapeSourceType::None, "unknown type");
+    aComputedValue.SetNoneValue();
+  }
+
   return true;
 }
 
 static void
 SetFallbackValue(nsCSSValuePair* aPair, const nsStyleSVGPaint& aPaint)
 {
   if (aPaint.GetFallbackType() == eStyleSVGFallbackType_Color) {
     aPair->mYValue.SetColorValue(aPaint.GetFallbackColor());
@@ -4544,39 +4573,33 @@ StyleAnimationValue::ExtractComputedValu
           ExtractImageLayerSizePairList(layers, aComputedValue);
           break;
         }
 #endif
 
         case eCSSProperty_clip_path: {
           const nsStyleSVGReset* svgReset =
             static_cast<const nsStyleSVGReset*>(styleStruct);
-          const StyleShapeSource& clipPath = svgReset->mClipPath;
-          const StyleShapeSourceType type = clipPath.GetType();
-
-          if (type == StyleShapeSourceType::URL) {
-            auto result = MakeUnique<nsCSSValue>();
-            result->SetURLValue(clipPath.GetURL());
-            aComputedValue.SetAndAdoptCSSValueValue(result.release(), eUnit_URL);
-          } else if (type == StyleShapeSourceType::Box) {
-            aComputedValue.SetEnumValue(clipPath.GetReferenceBox());
-          } else if (type == StyleShapeSourceType::Shape) {
-            RefPtr<nsCSSValue::Array> result = nsCSSValue::Array::Create(2);
-            if (!StyleClipBasicShapeToCSSArray(clipPath, result)) {
-              return false;
-            }
-            aComputedValue.SetCSSValueArrayValue(result, eUnit_Shape);
-
-          } else {
-            MOZ_ASSERT(type == StyleShapeSourceType::None, "unknown type");
-            aComputedValue.SetNoneValue();
+          if (!ExtractComputedValueFromShapeSource(svgReset->mClipPath,
+                                                   aComputedValue)) {
+            return false;
           }
           break;
         }
 
+        case eCSSProperty_shape_outside: {
+          const nsStyleDisplay* styleDisplay =
+            static_cast<const nsStyleDisplay*>(styleStruct);
+          if (!ExtractComputedValueFromShapeSource(styleDisplay->mShapeOutside,
+                                                   aComputedValue)) {
+            return false;
+          };
+          break;
+        }
+
         case eCSSProperty_filter: {
           const nsStyleEffects* effects =
             static_cast<const nsStyleEffects*>(styleStruct);
           const nsTArray<nsStyleFilter>& filters = effects->mFilters;
           nsAutoPtr<nsCSSValueList> result;
           nsCSSValueList **resultTail = getter_Transfers(result);
           for (uint32_t i = 0; i < filters.Length(); ++i) {
             nsCSSValueList *item = new nsCSSValueList;
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3746,22 +3746,23 @@ CSS_PROP_DISPLAY(
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Discrete)
 CSS_PROP_DISPLAY(
     shape-outside,
     shape_outside,
     ShapeOutside,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
+        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
+        CSS_PROPERTY_STORES_CALC,
     "layout.css.shape-outside.enabled",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
-    eStyleAnimType_Discrete) // FIXME: Bug 1289049 for adding animation support
+    eStyleAnimType_Custom)
 CSS_PROP_SVG(
     shape-rendering,
     shape_rendering,
     ShapeRendering,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kShapeRenderingKTable,
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -281,19 +281,17 @@ var supported_properties = {
     "word-spacing": [ test_length_transition, test_length_unclamped ],
     "z-index": [ test_integer_transition, test_pos_integer_or_auto_transition ],
     "-webkit-text-fill-color": [ test_color_transition,
                                  test_true_currentcolor_transition ],
     "-webkit-text-stroke-color": [ test_color_transition,
                                    test_true_currentcolor_transition ]
 };
 
-// Bug 1289049: After making shape-outside animatable on Gecko, we can remove
-// |isServo| flag from this if-condition.
-if (SpecialPowers.getBoolPref("layout.css.shape-outside.enabled") && isServo) {
+if (SpecialPowers.getBoolPref("layout.css.shape-outside.enabled")) {
   supported_properties["shape-outside"] =
     [ test_basic_shape_or_url_transition ];
 }
 
 if (SupportsMaskShorthand()) {
   supported_properties["mask-position"] = [ test_background_position_transition,
                                      // FIXME: We don't currently test clamping,
                                      // since mask-position uses calc() as
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -3708,16 +3708,22 @@ static void RecordIceStats_s(
 nsresult
 PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
 
   ASSERT_ON_THREAD(query->iceCtx->thread());
 
   // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
 
   for (size_t p = 0; p < query->pipelines.Length(); ++p) {
+    MOZ_ASSERT(query->pipelines[p]);
+    MOZ_ASSERT(query->pipelines[p]->Conduit());
+    if (!query->pipelines[p] || !query->pipelines[p]->Conduit()) {
+      // continue if we don't have a valid conduit
+      continue;
+    }
     const MediaPipeline& mp = *query->pipelines[p];
     bool isAudio = (mp.Conduit()->type() == MediaSessionConduit::AUDIO);
     nsString mediaType = isAudio ?
         NS_LITERAL_STRING("audio") : NS_LITERAL_STRING("video");
     nsString idstr = mediaType;
     idstr.AppendLiteral("_");
     idstr.AppendInt(mp.level());
 
--- a/mobile/android/app/src/main/res/layout/firstrun_sync_fragment.xml
+++ b/mobile/android/app/src/main/res/layout/firstrun_sync_fragment.xml
@@ -35,36 +35,34 @@
 
         <TextView android:id="@+id/firstrun_subtext"
                   android:layout_width="@dimen/firstrun_content_width"
                   android:layout_height="wrap_content"
                   android:paddingTop="20dp"
                   android:gravity="center"
                   android:textAppearance="@style/TextAppearance.FirstrunRegular.Body"/>
 
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
+        <View
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible"/>
 
-            <Button
-                android:id="@+id/welcome_account"
-                style="@style/Widget.Firstrun.Button"
-                android:layout_above="@+id/welcome_browse"
-                android:layout_gravity="center"
-                android:layout_centerHorizontal="true"
-                android:layout_marginBottom="20dp"
-                android:background="@drawable/button_background_action_photon_round"
-                android:text="@string/firstrun_signin_button"/>
+        <Button
+            android:id="@+id/welcome_account"
+            style="@style/Widget.Firstrun.Button"
+            android:layout_gravity="center"
+            android:layout_marginTop="30dp"
+            android:layout_marginBottom="20dp"
+            android:background="@drawable/button_background_action_photon_round"
+            android:text="@string/firstrun_signin_button"/>
 
-            <TextView
-                android:id="@+id/welcome_browse"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentBottom="true"
-                android:layout_centerHorizontal="true"
-                android:layout_marginBottom="30dp"
-                android:text="@string/firstrun_welcome_button_browser"
-                android:textAllCaps="true"
-                android:textAppearance="@style/TextAppearance.Link"/>
-        </RelativeLayout>
+        <TextView
+            android:id="@+id/welcome_browse"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="30dp"
+            android:text="@string/firstrun_welcome_button_browser"
+            android:textAllCaps="true"
+            android:textAppearance="@style/TextAppearance.Link"/>
 
     </LinearLayout>
 </ScrollView>
--- a/mobile/android/app/src/photon/res/layout/tab_strip_item_view.xml
+++ b/mobile/android/app/src/photon/res/layout/tab_strip_item_view.xml
@@ -16,17 +16,17 @@
         style="@style/TabStrip.Favicon"
         android:layout_width="@dimen/browser_toolbar_favicon_size"
         android:layout_height="@dimen/browser_toolbar_favicon_size"
         android:layout_gravity="center"
         android:duplicateParentState="true"
         android:scaleType="centerInside"
         tools:src="@drawable/toolbar_favicon_default"/>
 
-    <org.mozilla.gecko.widget.FadedSingleColorTextView
+    <org.mozilla.gecko.widget.CheckableFadedSingleColorTextView
         android:id="@+id/title"
         android:layout_width="0dip"
         android:layout_height="match_parent"
         android:layout_weight="1.0"
         android:duplicateParentState="true"
         android:ellipsize="end"
         android:gravity="center_vertical"
         android:maxLines="1"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/CheckableFadedSingleColorTextView.java
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+/* 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/. */
+
+package org.mozilla.gecko.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+
+public class CheckableFadedSingleColorTextView extends FadedSingleColorTextView implements Checkable {
+
+    private static final int[] STATE_CHECKED = {
+        android.R.attr.state_checked
+    };
+
+    private boolean checked;
+
+    public CheckableFadedSingleColorTextView(Context context) {
+        this(context, null);
+    }
+
+    public CheckableFadedSingleColorTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+
+        if (checked) {
+            mergeDrawableStates(drawableState, STATE_CHECKED);
+        }
+
+        return drawableState;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return checked;
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        if (this.checked == checked) {
+            return;
+        }
+
+        this.checked = checked;
+        refreshDrawableState();
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!checked);
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -952,16 +952,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'webapps/WebApps.java',
     'widget/ActionModePresenter.java',
     'widget/ActivityChooserModel.java',
     'widget/AllCapsTextView.java',
     'widget/AnchoredPopup.java',
     'widget/AnimatedHeightLayout.java',
     'widget/AnimatedProgressBar.java',
     'widget/BasicColorPicker.java',
+    'widget/CheckableFadedSingleColorTextView.java',
     'widget/CheckableLinearLayout.java',
     'widget/ClickableWhenDisabledEditText.java',
     'widget/ContentSecurityDoorHanger.java',
     'widget/CropImageView.java',
     'widget/DateTimePicker.java',
     'widget/DefaultDoorHanger.java',
     'widget/DefaultItemAnimatorBase.java',
     'widget/DoorHanger.java',
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -26,16 +26,18 @@ from mach.decorators import (
     CommandProvider,
     Command,
     SettingsProvider,
     SubCommand,
 )
 
 from mach.mixin.logging import LoggingMixin
 
+from mach.main import Mach
+
 from mozbuild.base import (
     BuildEnvironmentNotFoundException,
     MachCommandBase,
     MachCommandConditions as conditions,
     MozbuildObject,
     MozconfigFindException,
     MozconfigLoadException,
     ObjdirMismatchException,
@@ -2039,16 +2041,406 @@ class PackageFrontend(MachCommandBase):
 
         if artifacts:
             ensureParentDir(artifact_manifest)
             with open(artifact_manifest, 'w') as fh:
                 json.dump(artifacts, fh, indent=4, sort_keys=True)
 
         return 0
 
+class StaticAnalysisSubCommand(SubCommand):
+    def __call__(self, func):
+        after = SubCommand.__call__(self, func)
+        args = [
+            CommandArgument('--verbose', '-v', action='store_true',
+                            help='Print verbose output.'),
+        ]
+        for arg in args:
+            after = arg(after)
+        return after
+
+
+class StaticAnalysisMonitor(object):
+    def __init__(self, srcdir, objdir, total):
+        self._total = total
+        self._processed = 0
+        self._current = None
+        self._srcdir = srcdir
+
+        from mozbuild.compilation.warnings import (
+            WarningsCollector,
+            WarningsDatabase,
+        )
+
+        self._warnings_database = WarningsDatabase()
+
+        def on_warning(warning):
+            filename = warning['filename']
+            self._warnings_database.insert(warning)
+
+        self._warnings_collector = WarningsCollector(on_warning, objdir=objdir)
+
+    @property
+    def num_files(self):
+        return self._total
+
+    @property
+    def num_files_processed(self):
+        return self._processed
+
+    @property
+    def current_file(self):
+        return self._current
+
+    @property
+    def warnings_db(self):
+        return self._warnings_database
+
+    def on_line(self, line):
+        warning = None
+
+        try:
+            warning = self._warnings_collector.process_line(line)
+        except:
+            pass
+
+        if line.find('clang-tidy') != -1:
+            filename = line.split(' ')[-1]
+            if os.path.isfile(filename):
+                self._current = os.path.relpath(filename, self._srcdir)
+            else:
+                self._current = None
+            self._processed = self._processed + 1
+            return (warning, False)
+        return (warning, True)
+
+
+class StaticAnalysisFooter(Footer):
+    """Handles display of a static analysis progress indicator in a terminal.
+    """
+
+    def __init__(self, terminal, monitor):
+        Footer.__init__(self, terminal)
+        self.monitor = monitor
+
+    def draw(self):
+        """Draws this footer in the terminal."""
+
+        monitor = self.monitor
+        total = monitor.num_files
+        processed = monitor.num_files_processed
+        percent = '(%.2f%%)' % (processed * 100.0 / total)
+        parts = [
+            ('dim', 'Processing'),
+            ('yellow', str(processed)),
+            ('dim', 'of'),
+            ('yellow', str(total)),
+            ('dim', 'files'),
+            ('green', percent)
+        ]
+        if monitor.current_file:
+            parts.append(('bold', monitor.current_file))
+
+        self.write(parts)
+
+
+class StaticAnalysisOutputManager(OutputManager):
+    """Handles writing static analysis output to a terminal."""
+
+    def __init__(self, log_manager, monitor, footer):
+        self.monitor = monitor
+        OutputManager.__init__(self, log_manager, footer)
+
+    def on_line(self, line):
+        warning, relevant = self.monitor.on_line(line)
+
+        if warning:
+            self.log(logging.INFO, 'compiler_warning', warning,
+                'Warning: {flag} in {filename}: {message}')
+
+        if relevant:
+            self.log(logging.INFO, 'build_output', {'line': line}, '{line}')
+        else:
+            have_handler = hasattr(self, 'handler')
+            if have_handler:
+                self.handler.acquire()
+            try:
+                self.refresh()
+            finally:
+                if have_handler:
+                    self.handler.release()
+
+
+@CommandProvider
+class StaticAnalysis(MachCommandBase):
+    """Utilities for running C++ static analysis checks."""
+
+    @Command('static-analysis', category='testing',
+             description='Run C++ static analysis checks')
+    def static_analysis(self):
+        # If not arguments are provided, just print a help message.
+        mach = Mach(os.getcwd())
+        mach.run(['static-analysis', '--help'])
+
+    @StaticAnalysisSubCommand('static-analysis', 'check',
+                              'Run the checks using the helper tool')
+    @CommandArgument('source', nargs='*', default=['.*'],
+                     help='Source files to be analyzed (regex on path). '
+                          'Can be omitted, in which case the entire code base '
+                          'is analyzed.  The source argument is ignored if '
+                          'there is anything fed through stdin, in which case '
+                          'the analysis is only performed on the files changed '
+                          'in the patch streamed through stdin.  This is called '
+                          'the diff mode.')
+    @CommandArgument('--checks', '-c', default='-*,mozilla-*', metavar='checks',
+        help='Static analysis checks to enable.  By default, this enables only '
+             'custom Mozilla checks, but can be any clang-tidy checks syntax.')
+    @CommandArgument('--jobs', '-j', default='0', metavar='jobs', type=int,
+        help='Number of concurrent jobs to run. Default is the number of CPUs.')
+    @CommandArgument('--strip', '-p', default='1', metavar='NUM',
+                     help='Strip NUM leading components from file names in diff mode.')
+    @CommandArgument('--fix', '-f', default=False, action='store_true',
+                     help='Try to autofix errors detected by clang-tidy checkers.')
+    def check(self, source=None, jobs=2, strip=1, verbose=False,
+              checks='-*,mozilla-*', fix=False):
+        self._set_log_level(verbose)
+        rc = self._build_compile_db(verbose=verbose)
+        if rc != 0:
+            return rc
+
+        rc = self._build_export(jobs=jobs, verbose=verbose)
+        if rc != 0:
+            return rc
+
+        rc = self._get_clang_tidy(verbose=verbose)
+        if rc != 0:
+            return rc
+
+        python = self.virtualenv_manager.python_path
+
+        common_args = ['-clang-tidy-binary', self._clang_tidy_path,
+                       '-checks=%s' % checks,
+                       '-extra-arg=-DMOZ_CLANG_PLUGIN']
+        if fix:
+            common_args.append('-fix')
+
+        self.log_manager.register_structured_logger(logging.getLogger('mozbuild'))
+
+        compile_db = json.loads(open(self._compile_db, 'r').read())
+        total = 0
+        files = []
+        import re
+        name_re = re.compile('(' + ')|('.join(source) + ')')
+        for f in compile_db:
+            if name_re.search(f['file']):
+                total = total + 1
+                files.append(f['file'])
+
+        if not total:
+            return 0
+
+        args = [python, self._run_clang_tidy_path, '-p', self.topobjdir]
+        args += ['-j', str(jobs)] + files + common_args
+        cwd = self.topobjdir
+
+        monitor = StaticAnalysisMonitor(self.topsrcdir, self.topobjdir, total)
+
+        footer = StaticAnalysisFooter(self.log_manager.terminal, monitor)
+        with StaticAnalysisOutputManager(self.log_manager, monitor, footer) as output:
+            rc = self.run_process(args=args, line_handler=output.on_line, cwd=cwd)
+
+            self.log(logging.WARNING, 'warning_summary',
+                     {'count': len(monitor.warnings_db)},
+                     '{count} warnings present.')
+            return rc
+
+    @StaticAnalysisSubCommand('static-analysis', 'install',
+                              'Install the static analysis helper tool')
+    @CommandArgument('source', nargs='?', type=str,
+                     help='Where to fetch a local archive containing the clang-tidy helper tool.'
+                          'It will be installed in ~/.mozbuild/clang-tidy/.'
+                          'Can be omitted, in which case the latest clang-tidy '
+                          ' helper for the platform would be automatically '
+                          'detected and installed.')
+    @CommandArgument('--skip-cache', action='store_true',
+                     help='Skip all local caches to force re-fetching the helper tool.',
+                     default=False)
+    def install(self, source=None, skip_cache=False, verbose=False):
+        self._set_log_level(verbose)
+        rc = self._get_clang_tidy(force=True, skip_cache=skip_cache,
+                                  source=source, verbose=verbose)
+        return rc
+
+    @StaticAnalysisSubCommand('static-analysis', 'clear-cache',
+                              'Delete local helpers and reset static analysis helper tool cache')
+    def clear_cache(self, verbose=False):
+        self._set_log_level(verbose)
+        rc = self._get_clang_tidy(force=True, download_if_needed=False,
+                                  verbose=verbose)
+        if rc != 0:
+            return rc
+
+        self._artifact_manager.artifact_clear_cache()
+
+    @StaticAnalysisSubCommand('static-analysis', 'print-checks',
+                              'Print a list of the static analysis checks performed by default')
+    def print_checks(self, verbose=False):
+        self._set_log_level(verbose)
+        rc = self._get_clang_tidy(verbose=verbose)
+        if rc != 0:
+            return rc
+        args = [self._clang_tidy_path, '-list-checks', '-checks=-*,mozilla-*']
+        return self._run_command_in_objdir(args=args, pass_thru=True)
+
+    def _get_config_environment(self):
+        ran_configure = False
+        config = None
+        builder = Build(self._mach_context)
+
+        try:
+            config = self.config_environment
+        except Exception:
+            print('Looks like configure has not run yet, running it now...')
+            rc = builder.configure()
+            if rc != 0:
+                return (rc, config, ran_configure)
+            ran_configure = True
+            try:
+                config = self.config_environment
+            except Exception as e:
+                pass
+
+        return (0, config, ran_configure)
+
+    def _build_compile_db(self, verbose=False):
+        self._compile_db = mozpath.join(self.topobjdir, 'compile_commands.json')
+        if os.path.exists(self._compile_db):
+            return 0
+        else:
+            rc, config, ran_configure = self._get_config_environment()
+            if rc != 0:
+                return rc
+
+            if ran_configure:
+                # Configure may have created the compilation database if the
+                # mozconfig enables building the CompileDB backend by default,
+                # So we recurse to see if the file exists once again.
+                return self._build_compile_db(verbose=verbose)
+
+            if config:
+                print('Looks like a clang compilation database has not been '
+                      'created yet, creating it now...')
+                builder = Build(self._mach_context)
+                rc = builder.build_backend(['CompileDB'], verbose=verbose)
+                if rc != 0:
+                    return rc
+                assert os.path.exists(self._compile_db)
+                return 0
+
+    def _build_export(self, jobs, verbose=False):
+        def on_line(line):
+            self.log(logging.INFO, 'build_output', {'line': line}, '{line}')
+
+        builder = Build(self._mach_context)
+        # First install what we can through install manifests.
+        rc = builder._run_make(directory=self.topobjdir, target='pre-export',
+                               line_handler=None, silent=not verbose)
+        if rc != 0:
+            return rc
+
+        # Then build the rest of the build dependencies by running the full
+        # export target, because we can't do anything better.
+        return builder._run_make(directory=self.topobjdir, target='export',
+                                 line_handler=None, silent=not verbose,
+                                 num_jobs=jobs)
+
+    def _get_clang_tidy(self, force=False, skip_cache=False,
+                        source=None, download_if_needed=True,
+                        verbose=False):
+        rc, config, _ = self._get_config_environment()
+
+        if rc != 0:
+            return rc
+
+        clang_tidy_path = mozpath.join(self._mach_context.state_dir,
+                                       "clang-tidy")
+        self._clang_tidy_path = mozpath.join(clang_tidy_path, "clang", "bin",
+                                             "clang-tidy" + config.substs.get('BIN_SUFFIX', ''))
+        self._run_clang_tidy_path = mozpath.join(clang_tidy_path, "clang", "share",
+                                                 "clang", "run-clang-tidy.py")
+
+        if os.path.exists(self._clang_tidy_path) and \
+           os.path.exists(self._run_clang_tidy_path) and \
+           not force:
+            return 0
+        else:
+            if os.path.isdir(clang_tidy_path) and download_if_needed:
+                # The directory exists, perhaps it's corrupted?  Delete it
+                # and start from scratch.
+                import shutil
+                shutil.rmtree(clang_tidy_path)
+                return self._get_clang_tidy(force=force, skip_cache=skip_cache,
+                                            source=source, verbose=verbose,
+                                            download_if_needed=download_if_needed)
+
+            # Create base directory where we store clang binary
+            os.mkdir(clang_tidy_path)
+
+            if source:
+                return self._get_clang_tidy_from_source(source)
+
+            self._artifact_manager = PackageFrontend(self._mach_context)
+
+            if not download_if_needed:
+                return 0
+
+            job, _ = self.platform
+
+            if job is None:
+                raise Exception('The current platform isn\'t supported. '
+                                'Currently only the following platforms are '
+                                'supported: win32/win64, linux64 and macosx64.')
+            else:
+                job += '-clang-tidy'
+
+            # We want to unpack data in the clang-tidy mozbuild folder
+            currentWorkingDir = os.getcwd()
+            os.chdir(clang_tidy_path)
+            rc = self._artifact_manager.artifact_toolchain(verbose=verbose,
+                                                           skip_cache=skip_cache,
+                                                           from_build=[job],
+                                                           no_unpack=False,
+                                                           retry=0)
+            # Change back the cwd
+            os.chdir(currentWorkingDir)
+
+            return rc
+
+    def _get_clang_tidy_from_source(self, filename):
+        from mozbuild.action.tooltool import unpack_file
+        clang_tidy_path = mozpath.join(self._mach_context.state_dir,
+                                       "clang-tidy")
+
+        currentWorkingDir = os.getcwd()
+        os.chdir(clang_tidy_path)
+
+        unpack_file(filename)
+
+        # Change back the cwd
+        os.chdir(currentWorkingDir)
+
+        clang_path = mozpath.join(clang_tidy_path, 'clang')
+
+        if not os.path.isdir(clang_path):
+            raise Exception('Extracted the archive but didn\'t find '
+                            'the expected output')
+
+        assert os.path.exists(self._clang_tidy_path)
+        assert os.path.exists(self._run_clang_tidy_path)
+        return 0
 
 @CommandProvider
 class Vendor(MachCommandBase):
     """Vendor third-party dependencies into the source repository."""
 
     @Command('vendor', category='misc',
              description='Vendor third-party dependencies into the source repository.')
     def vendor(self):
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -348,17 +348,17 @@ var TPS = {
       // be reasonably confident the sessionstore time has fired is simpler.
       // Without this timeout, we are likely to see "error locating tab"
       // on subsequent syncs.
       await new Promise(resolve => setTimeout(resolve, 2500));
     }
     Logger.logPass("executing action " + action.toUpperCase() + " on tabs");
   },
 
-  HandlePrefs(prefs, action) {
+  async HandlePrefs(prefs, action) {
     for (let pref of prefs) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on pref " + JSON.stringify(pref));
       let preference = new Preference(pref);
       switch (action) {
         case ACTION_MODIFY:
           preference.Modify();
           break;
@@ -428,17 +428,17 @@ var TPS = {
       Logger.logPass("executing action " + action.toUpperCase() +
                      " on history");
     } catch (e) {
       DumpHistory();
       throw (e);
     }
   },
 
-  HandlePasswords(passwords, action) {
+  async HandlePasswords(passwords, action) {
     this.shouldValidatePasswords = true;
     try {
       for (let password of passwords) {
         Logger.logInfo("executing action " + action.toUpperCase() +
                       " on password " + JSON.stringify(password));
         let passwordOb = new Password(password);
         switch (action) {
           case ACTION_ADD:
@@ -468,17 +468,17 @@ var TPS = {
       Logger.logPass("executing action " + action.toUpperCase() +
                      " on passwords");
     } catch (e) {
       DumpPasswords();
       throw (e);
     }
   },
 
-  HandleAddons(addons, action, state) {
+  async HandleAddons(addons, action, state) {
     this.shouldValidateAddons = true;
     for (let entry of addons) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on addon " + JSON.stringify(entry));
       let addon = new Addon(this, entry);
       switch (action) {
         case ACTION_ADD:
           addon.install();
@@ -1197,30 +1197,30 @@ var TPS = {
    */
   async EnsureTracking() {
     await this.Login(false);
     await this.waitForTracking();
   }
 };
 
 var Addons = {
-  install: function Addons__install(addons) {
-    TPS.HandleAddons(addons, ACTION_ADD);
+  async install(addons) {
+    await TPS.HandleAddons(addons, ACTION_ADD);
   },
-  setEnabled: function Addons__setEnabled(addons, state) {
-    TPS.HandleAddons(addons, ACTION_SET_ENABLED, state);
+  async setEnabled(addons, state) {
+    await TPS.HandleAddons(addons, ACTION_SET_ENABLED, state);
   },
-  uninstall: function Addons__uninstall(addons) {
-    TPS.HandleAddons(addons, ACTION_DELETE);
+  async uninstall(addons) {
+    await TPS.HandleAddons(addons, ACTION_DELETE);
   },
-  verify: function Addons__verify(addons, state) {
-    TPS.HandleAddons(addons, ACTION_VERIFY, state);
+  async verify(addons, state) {
+    await TPS.HandleAddons(addons, ACTION_VERIFY, state);
   },
-  verifyNot: function Addons__verifyNot(addons) {
-    TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
+  async verifyNot(addons) {
+    await TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
   },
   skipValidation() {
     TPS.shouldValidateAddons = false;
   }
 };
 
 var Bookmarks = {
   async add(bookmarks) {
@@ -1239,72 +1239,72 @@ var Bookmarks = {
     await TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT);
   },
   skipValidation() {
     TPS.shouldValidateBookmarks = false;
   }
 };
 
 var Formdata = {
-  add: function Formdata__add(formdata) {
-    this.HandleForms(formdata, ACTION_ADD);
+  async add(formdata) {
+    await this.HandleForms(formdata, ACTION_ADD);
   },
-  delete: function Formdata__delete(formdata) {
-    this.HandleForms(formdata, ACTION_DELETE);
+  async delete(formdata) {
+    await this.HandleForms(formdata, ACTION_DELETE);
   },
-  verify: function Formdata__verify(formdata) {
-    this.HandleForms(formdata, ACTION_VERIFY);
+  async verify(formdata) {
+    await this.HandleForms(formdata, ACTION_VERIFY);
   },
-  verifyNot: function Formdata__verifyNot(formdata) {
-    this.HandleForms(formdata, ACTION_VERIFY_NOT);
+  async verifyNot(formdata) {
+    await this.HandleForms(formdata, ACTION_VERIFY_NOT);
   }
 };
 
 var History = {
-  add: function History__add(history) {
-    this.HandleHistory(history, ACTION_ADD);
+  async add(history) {
+    await this.HandleHistory(history, ACTION_ADD);
   },
-  delete: function History__delete(history) {
-    this.HandleHistory(history, ACTION_DELETE);
+  async delete(history) {
+    await this.HandleHistory(history, ACTION_DELETE);
   },
-  verify: function History__verify(history) {
-    this.HandleHistory(history, ACTION_VERIFY);
+  async verify(history) {
+    await this.HandleHistory(history, ACTION_VERIFY);
   },
-  verifyNot: function History__verifyNot(history) {
-    this.HandleHistory(history, ACTION_VERIFY_NOT);
+  async verifyNot(history) {
+    await this.HandleHistory(history, ACTION_VERIFY_NOT);
   }
 };
 
 var Passwords = {
-  add: function Passwords__add(passwords) {
-    this.HandlePasswords(passwords, ACTION_ADD);
+  async add(passwords) {
+    await this.HandlePasswords(passwords, ACTION_ADD);
   },
-  modify: function Passwords__modify(passwords) {
-    this.HandlePasswords(passwords, ACTION_MODIFY);
+  async modify(passwords) {
+    await this.HandlePasswords(passwords, ACTION_MODIFY);
   },
-  delete: function Passwords__delete(passwords) {
-    this.HandlePasswords(passwords, ACTION_DELETE);
+  async delete(passwords) {
+    await this.HandlePasswords(passwords, ACTION_DELETE);
   },
-  verify: function Passwords__verify(passwords) {
-    this.HandlePasswords(passwords, ACTION_VERIFY);
+  async verify(passwords) {
+    await this.HandlePasswords(passwords, ACTION_VERIFY);
   },
-  verifyNot: function Passwords__verifyNot(passwords) {
-    this.HandlePasswords(passwords, ACTION_VERIFY_NOT);
+  async verifyNot(passwords) {
+    await this.HandlePasswords(passwords, ACTION_VERIFY_NOT);
   },
   skipValidation() {
     TPS.shouldValidatePasswords = false;
   }
 };
 
 var Prefs = {
-  modify: function Prefs__modify(prefs) {
-    TPS.HandlePrefs(prefs, ACTION_MODIFY);
+  async modify(prefs) {
+    await TPS.HandlePrefs(prefs, ACTION_MODIFY);
   },
-  verify: function Prefs__verify(prefs) {
-    TPS.HandlePrefs(prefs, ACTION_VERIFY);
+  async verify(prefs) {
+    await TPS.HandlePrefs(prefs, ACTION_VERIFY);
   }
 };
 
 var Tabs = {
   async add(tabs) {
     await TPS.HandleTabs(tabs, ACTION_ADD);
   },
   async verify(tabs) {
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -102,17 +102,17 @@ dependencies = [
 name = "azure"
 version = "0.21.0"
 source = "git+https://github.com/servo/rust-azure#dea0d6ebf4603771740acf2cebceab88f2efcc5e"
 dependencies = [
  "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-skia 0.30000006.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -310,33 +310,33 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.21.0 (git+https://github.com/servo/rust-azure)",
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.50.0 (git+https://github.com/servo/webrender)",
  "webrender_api 0.50.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "canvas_traits"
 version = "0.0.1"
 dependencies = [
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "webrender_api 0.50.0 (git+https://github.com/servo/webrender)",
@@ -470,17 +470,17 @@ dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "compositing"
 version = "0.0.1"
 dependencies = [
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
@@ -501,17 +501,17 @@ dependencies = [
  "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "canvas 0.0.1",
  "canvas_traits 0.0.1",
  "clipboard 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
  "debugger 0.0.1",
  "devtools_traits 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gaol 0.0.1 (git+https://github.com/servo/gaol)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout_traits 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -783,17 +783,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "embedding"
 version = "0.0.1"
 dependencies = [
  "cocoa 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
  "devtools 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin_app 0.0.1",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "libservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -932,17 +932,17 @@ name = "error-chain"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "euclid"
-version = "0.15.2"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1090,17 +1090,17 @@ version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
  "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "harfbuzz-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1184,17 +1184,17 @@ version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "glutin_app"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "osmesa-src 17.2.0-devel (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1500,17 +1500,17 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1548,17 +1548,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "layout_thread"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout 0.0.1",
  "layout_traits 0.0.1",
@@ -1656,17 +1656,17 @@ dependencies = [
  "canvas 0.0.1",
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "constellation 0.0.1",
  "debugger 0.0.1",
  "devtools 0.0.1",
  "devtools_traits 0.0.1",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gaol 0.0.1 (git+https://github.com/servo/gaol)",
  "gfx 0.0.1",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout_thread 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
@@ -1723,17 +1723,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "malloc_size_of"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "servo_arc 0.0.1",
  "smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "malloc_size_of_derive"
@@ -1795,17 +1795,17 @@ dependencies = [
  "script_traits 0.0.1",
  "servo_config 0.0.1",
 ]
 
 [[package]]
 name = "metrics_tests"
 version = "0.0.1"
 dependencies = [
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "metrics 0.0.1",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "style 0.0.1",
@@ -1906,23 +1906,23 @@ name = "msg_tests"
 version = "0.0.1"
 dependencies = [
  "msg 0.0.1",
  "size_of_test 0.0.1",
 ]
 
 [[package]]
 name = "multistr"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bow 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "extra-default 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "len-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "push-trait 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "push-trait 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "net"
 version = "0.0.1"
 dependencies = [
  "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1938,17 +1938,17 @@ dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "parse-hosts 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parse-hosts 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-websocket 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2112,17 +2112,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libloading 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2226,20 +2226,20 @@ dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "parse-hosts"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "multistr 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "multistr 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "pdqsort"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -2293,17 +2293,17 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plane-split"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "plugin_compiletest"
 version = "0.0.1"
 dependencies = [
@@ -2381,19 +2381,20 @@ version = "0.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "push-trait"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "len-trait 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "quasi"
 version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2565,17 +2566,17 @@ dependencies = [
  "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "deny_public_fields 0.0.1",
  "devtools_traits 0.0.1",
  "dom_struct 0.0.1",
  "domobject_derive 0.0.1",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2632,17 +2633,17 @@ dependencies = [
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "metrics 0.0.1",
@@ -2662,31 +2663,31 @@ dependencies = [
 [[package]]
 name = "script_plugins"
 version = "0.0.1"
 
 [[package]]
 name = "script_tests"
 version = "0.0.1"
 dependencies = [
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "script 0.0.1",
  "servo_url 0.0.1",
 ]
 
 [[package]]
 name = "script_traits"
 version = "0.0.1"
 dependencies = [
  "bluetooth_traits 0.0.1",
  "canvas_traits 0.0.1",
  "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
@@ -2863,17 +2864,17 @@ dependencies = [
 
 [[package]]
 name = "servo-skia"
 version = "0.30000006.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "io-surface 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2916,17 +2917,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "servo_config"
 version = "0.0.1"
 dependencies = [
  "android_injected_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
@@ -2941,17 +2942,17 @@ dependencies = [
  "servo_config 0.0.1",
 ]
 
 [[package]]
 name = "servo_geometry"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "servo_rand"
 version = "0.0.1"
 dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3110,17 +3111,17 @@ dependencies = [
  "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible 0.0.1",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3170,17 +3171,17 @@ dependencies = [
 
 [[package]]
 name = "style_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
@@ -3192,17 +3193,17 @@ dependencies = [
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "selectors 0.19.0",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "webrender_api 0.50.0 (git+https://github.com/servo/webrender)",
@@ -3210,17 +3211,17 @@ dependencies = [
 
 [[package]]
 name = "stylo_tests"
 version = "0.0.1"
 dependencies = [
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "size_of_test 0.0.1",
  "style 0.0.1",
@@ -3562,17 +3563,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "webdriver_server"
 version = "0.0.1"
 dependencies = [
  "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3591,17 +3592,17 @@ source = "git+https://github.com/servo/w
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3617,30 +3618,30 @@ version = "0.50.0"
 source = "git+https://github.com/servo/webrender#68e2e7cd0e39d216bb6c35dfb353dc0700bb6948"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webvr"
 version = "0.0.1"
 dependencies = [
  "canvas_traits 0.0.1",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "rust-webvr 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
  "webvr_traits 0.0.1",
 ]
@@ -3826,17 +3827,17 @@ dependencies = [
 "checksum energymon 0.3.0 (git+https://github.com/energymon/energymon-rust.git)" = "<none>"
 "checksum energymon-builder 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-default-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
 "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
 "checksum error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "318cb3c71ee4cdea69fdc9e15c173b245ed6063e1709029e8fd32525a881120f"
-"checksum euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "50c9e4c3b53de731815135191f0b77969bea953211b8bbd3cc3083a7b10e190e"
+"checksum euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "01a550d73de4eac12cee6316ccef84a9f71493c3839015bfda6465a53e31b879"
 "checksum expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cef36cd1a8a02d28b91d97347c63247b9e4cb8a8e36df36f8201dc87a1c0859c"
 "checksum extra-default 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca1434e1920ba21b45516c16b5edbd82e8f2e4349b12a7a53eb9903ed2928d56"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum fontsan 0.3.2 (git+https://github.com/servo/fontsan)" = "<none>"
 "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
 "checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
 "checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3"
@@ -3898,17 +3899,17 @@ dependencies = [
 "checksum mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d69889cdc6336ed56b174514ce876c4c3dc564cc23dd872e7bca589bb2a36c8"
 "checksum mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76da6df85047af8c0edfa53f48eb1073012ce1cc95c8fedc0a374f659a89dd65"
 "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
 "checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
 "checksum mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)" = "<none>"
 "checksum mp3-metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61cf32f7fc3cec83a15a255ac60bceb6cac59a7ce190cb824ca25c0fce0feb"
 "checksum mp4parse 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b81651f9ede53d59281b54c7eb51ae50a868ac4765dd3bdfbbc79ce3d8aca7a"
-"checksum multistr 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60a0c9d992b79e7385ced5a7cbda426d9129de49b4e8d4ac224d3f175a631b7d"
+"checksum multistr 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "90fb6e1b4f6ca2f2098a437e1c7f09c122da62bbf2bde45b3693defc1eb61e2d"
 "checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
 "checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37"
 "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e"
 "checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44"
 "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
 "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
@@ -3923,31 +3924,31 @@ dependencies = [
 "checksum openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bb5d1663b73d10c6a3eda53e2e9d0346f822394e7b858d7257718f65f61dfbe2"
 "checksum openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3a5886d87d3e2a0d890bf62dc8944f5e3769a405f7e1e9ef6e517e47fd7a0897"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
 "checksum osmesa-src 17.2.0-devel (git+https://github.com/servo/osmesa-src)" = "<none>"
 "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
 "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
 "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
 "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
-"checksum parse-hosts 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9aebf4a4f84ce5d940a30a919c93325a66ab4ddb646f5f0a3d77483eb99595a6"
+"checksum parse-hosts 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3842db828281691db6e6f1709ed6a73025747c0cd15cc10346a5cb021e2bc28"
 "checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
 "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
 "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
 "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
 "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
 "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
 "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum plane-split 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e57800a97ca52c556db6b6184a3201f05366ad5e11876f7d17e234589ca2fa26"
 "checksum png 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cb773e9a557edb568ce9935cf783e3cdcabe06a9449d41b3e5506d88e582c82"
 "checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
 "checksum procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c93cdc1fb30af9ddf3debc4afbdb0f35126cbd99daa229dd76cdd5349b41d989"
 "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
-"checksum push-trait 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0cfb17705aef2ae8592219161c5019d7f3765d92adb8586f21e99a4c129bafb6"
+"checksum push-trait 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdc13b1a53bc505b526086361221aaa612fefb9b0ecf2853f9d31f807764e004"
 "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
 "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
 "checksum rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "705cf28d52a26a9ab548930a9a3d9799eb77cf84d66d7cc6e52fa222ca662424"
 "checksum rayon-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c21a92a5dca958fb030787c1158446c6deb7f976399b72fa8074603f169e2a"
 "checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b"
 "checksum ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b5ceb840e4009da4841ed22a15eb49f64fdd00a2138945c5beacf506b2fb5ed"
--- a/servo/components/net/Cargo.toml
+++ b/servo/components/net/Cargo.toml
@@ -23,17 +23,17 @@ ipc-channel = "0.8"
 lazy_static = "0.2"
 log = "0.3.5"
 matches = "0.1"
 mime = "0.2.1"
 mime_guess = "1.8.0"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 openssl = "0.9"
-parse-hosts = "0.4.0"
+parse-hosts = "0.5.0"
 profile_traits = {path = "../profile_traits"}
 serde = "1.0"
 serde_json = "1.0"
 servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 servo-websocket = "0.19"
 threadpool = "1.0"
 time = "0.1.17"
--- a/servo/components/script/dom/bindings/refcounted.rs
+++ b/servo/components/script/dom/bindings/refcounted.rs
@@ -35,17 +35,17 @@ use libc;
 use std::cell::RefCell;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::collections::hash_map::HashMap;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::os;
 use std::rc::Rc;
 use std::sync::{Arc, Weak};
-use task::Task;
+use task::TaskOnce;
 
 
 #[allow(missing_docs)]  // FIXME
 mod dummy {  // Attributes don’t apply through the macro.
     use std::cell::RefCell;
     use std::rc::Rc;
     use super::LiveDOMReferences;
     thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> =
@@ -117,30 +117,30 @@ impl TrustedPromise {
                 Vacant(_) => unreachable!(),
             };
             promise
         })
     }
 
     /// A task which will reject the promise.
     #[allow(unrooted_must_root)]
-    pub fn reject_task(self, error: Error) -> impl Send + Task {
+    pub fn reject_task(self, error: Error) -> impl TaskOnce {
         let this = self;
         task!(reject_promise: move || {
             debug!("Rejecting promise.");
             let this = this.root();
             let cx = this.global().get_cx();
             let _ac = JSAutoCompartment::new(cx, this.reflector().get_jsobject().get());
             this.reject_error(cx, error);
         })
     }
 
     /// A task which will resolve the promise.
     #[allow(unrooted_must_root)]
-    pub fn resolve_task<T>(self, value: T) -> impl Send + Task
+    pub fn resolve_task<T>(self, value: T) -> impl TaskOnce
     where
         T: ToJSValConvertible + Send,
     {
         let this = self;
         task!(resolve_promise: move || {
             debug!("Resolving promise.");
             let this = this.root();
             let cx = this.global().get_cx();
--- a/servo/components/script/dom/bluetooth.rs
+++ b/servo/components/script/dom/bluetooth.rs
@@ -35,17 +35,17 @@ use ipc_channel::router::ROUTER;
 use js::conversions::ConversionResult;
 use js::jsapi::{JSAutoCompartment, JSContext, JSObject};
 use js::jsval::{ObjectValue, UndefinedValue};
 use std::cell::Ref;
 use std::collections::HashMap;
 use std::rc::Rc;
 use std::str::FromStr;
 use std::sync::{Arc, Mutex};
-use task::Task;
+use task::TaskOnce;
 
 const KEY_CONVERSION_ERROR: &'static str = "This `manufacturerData` key can not be parsed as unsigned short:";
 const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices.";
 const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
 const MANUFACTURER_DATA_ERROR: &'static str = "'manufacturerData', if present, must be non-empty to filter devices.";
 const MASK_LENGTH_ERROR: &'static str = "`mask`, if present, must have the same length as `dataPrefix`.";
 // 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
 const MAX_DEVICE_NAME_LENGTH: usize = 248;
@@ -224,28 +224,27 @@ pub fn response_async<T: AsyncBluetoothL
         receiver: Trusted::new(receiver),
     }));
     ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
         struct ListenerTask<T: AsyncBluetoothListener + DomObject> {
             context: Arc<Mutex<BluetoothContext<T>>>,
             action: BluetoothResponseResult,
         }
 
-        impl<T> Task for ListenerTask<T>
+        impl<T> TaskOnce for ListenerTask<T>
         where
             T: AsyncBluetoothListener + DomObject,
         {
-            fn run(self: Box<Self>) {
-                let this = *self;
-                let mut context = this.context.lock().unwrap();
-                context.response(this.action);
+            fn run_once(self) {
+                let mut context = self.context.lock().unwrap();
+                context.response(self.action);
             }
         }
 
-        let task = box ListenerTask {
+        let task = ListenerTask {
             context: context.clone(),
             action: message.to().unwrap(),
         };
 
         let result = task_source.queue_unconditionally(task);
         if let Err(err) = result {
             warn!("failed to deliver network data: {:?}", err);
         }
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -1711,17 +1711,17 @@ impl Document {
         assert!(!self.loader.borrow().events_inhibited());
         self.loader.borrow_mut().inhibit_events();
 
         // The rest will ever run only once per document.
         // Step 7.
         debug!("Document loads are complete.");
         let document = Trusted::new(self);
         self.window.dom_manipulation_task_source().queue(
-            box task!(fire_load_event: move || {
+            task!(fire_load_event: move || {
                 let document = document.root();
                 let window = document.window();
                 if !window.is_alive() {
                     return;
                 }
 
                 // Step 7.1.
                 document.set_ready_state(DocumentReadyState::Complete);
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -114,17 +114,17 @@ use style::properties::longhands::{self,
 use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
 use style::selector_parser::extended_filtering;
 use style::shared_lock::{SharedRwLock, Locked};
 use style::thread_state;
 use style::values::{CSSFloat, Either};
 use style::values::{specified, computed};
 use stylesheet_loader::StylesheetOwner;
-use task::Task;
+use task::TaskOnce;
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
 // and when the element enters or leaves a browsing context container.
 // https://html.spec.whatwg.org/multipage/#selector-focus
 
 #[dom_struct]
 pub struct Element {
     node: Node,
@@ -3042,19 +3042,19 @@ impl ElementPerformFullscreenEnter {
         box ElementPerformFullscreenEnter {
             element: element,
             promise: promise,
             error: error,
         }
     }
 }
 
-impl Task for ElementPerformFullscreenEnter {
+impl TaskOnce for ElementPerformFullscreenEnter {
     #[allow(unrooted_must_root)]
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         let element = self.element.root();
         let document = document_from_node(element.r());
 
         // Step 7.1
         if self.error || !element.fullscreen_element_ready_check() {
             // JSAutoCompartment needs to be manually made.
             // Otherwise, Servo will crash.
             let promise = self.promise.root();
@@ -3095,19 +3095,19 @@ impl ElementPerformFullscreenExit {
     pub fn new(element: Trusted<Element>, promise: TrustedPromise) -> Box<ElementPerformFullscreenExit> {
         box ElementPerformFullscreenExit {
             element: element,
             promise: promise,
         }
     }
 }
 
-impl Task for ElementPerformFullscreenExit {
+impl TaskOnce for ElementPerformFullscreenExit {
     #[allow(unrooted_must_root)]
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         let element = self.element.root();
         let document = document_from_node(element.r());
         // TODO Step 9.1-5
         // Step 9.6
         element.set_fullscreen_state(false);
 
         document.window().reflow(ReflowGoal::ForDisplay,
                                  ReflowQueryType::NoQuery,
--- a/servo/components/script/dom/event.rs
+++ b/servo/components/script/dom/event.rs
@@ -18,17 +18,17 @@ use dom::eventtarget::{CompiledEventList
 use dom::globalscope::GlobalScope;
 use dom::node::Node;
 use dom::virtualmethods::vtable_for;
 use dom::window::Window;
 use dom_struct::dom_struct;
 use servo_atoms::Atom;
 use std::cell::Cell;
 use std::default::Default;
-use task::Task;
+use task::TaskOnce;
 use time;
 
 #[dom_struct]
 pub struct Event {
     reflector_: Reflector,
     current_target: MutNullableJS<EventTarget>,
     target: MutNullableJS<EventTarget>,
     type_: DOMRefCell<Atom>,
@@ -383,33 +383,33 @@ pub enum EventStatus {
 // https://dom.spec.whatwg.org/#concept-event-fire
 pub struct EventTask {
     pub target: Trusted<EventTarget>,
     pub name: Atom,
     pub bubbles: EventBubbles,
     pub cancelable: EventCancelable,
 }
 
-impl Task for EventTask {
-    fn run(self: Box<Self>) {
+impl TaskOnce for EventTask {
+    fn run_once(self) {
         let target = self.target.root();
         let bubbles = self.bubbles;
         let cancelable = self.cancelable;
         target.fire_event_with_params(self.name, bubbles, cancelable);
     }
 }
 
 // https://html.spec.whatwg.org/multipage/#fire-a-simple-event
 pub struct SimpleEventTask {
     pub target: Trusted<EventTarget>,
     pub name: Atom,
 }
 
-impl Task for SimpleEventTask {
-    fn run(self: Box<Self>) {
+impl TaskOnce for SimpleEventTask {
+    fn run_once(self) {
         let target = self.target.root();
         target.fire_event(self.name);
     }
 }
 
 // See dispatch_event.
 // https://dom.spec.whatwg.org/#concept-event-dispatch
 fn dispatch_to_listeners(event: &Event, target: &EventTarget, event_path: &[&EventTarget]) {
--- a/servo/components/script/dom/eventsource.rs
+++ b/servo/components/script/dom/eventsource.rs
@@ -95,17 +95,17 @@ impl EventSourceContext {
         let event_source = self.event_source.root();
         if self.gen_id != event_source.generation_id.get() {
             return;
         }
         let global = event_source.global();
         let event_source = self.event_source.clone();
         // FIXME(nox): Why are errors silenced here?
         let _ = global.networking_task_source().queue(
-            box task!(announce_the_event_source_connection: move || {
+            task!(announce_the_event_source_connection: move || {
                 let event_source = event_source.root();
                 if event_source.ready_state.get() != ReadyState::Closed {
                     event_source.ready_state.set(ReadyState::Open);
                     event_source.upcast::<EventTarget>().fire_event(atom!("open"));
                 }
             }),
             &global,
         );
@@ -116,17 +116,17 @@ impl EventSourceContext {
         let event_source = self.event_source.root();
         if self.gen_id != event_source.generation_id.get() {
             return;
         }
         let global = event_source.global();
         let event_source = self.event_source.clone();
         // FIXME(nox): Why are errors silenced here?
         let _ = global.networking_task_source().queue(
-            box task!(fail_the_event_source_connection: move || {
+            task!(fail_the_event_source_connection: move || {
                 let event_source = event_source.root();
                 if event_source.ready_state.get() != ReadyState::Closed {
                     event_source.ready_state.set(ReadyState::Closed);
                     event_source.upcast::<EventTarget>().fire_event(atom!("error"));
                 }
             }),
             &global,
         );
@@ -140,17 +140,17 @@ impl EventSourceContext {
             return;
         }
 
         let trusted_event_source = self.event_source.clone();
         let action_sender = self.action_sender.clone();
         let global = event_source.global();
         // FIXME(nox): Why are errors silenced here?
         let _ = global.networking_task_source().queue(
-            box task!(reestablish_the_event_source_onnection: move || {
+            task!(reestablish_the_event_source_onnection: move || {
                 let event_source = trusted_event_source.root();
 
                 // Step 1.1.
                 if event_source.ready_state.get() == ReadyState::Closed {
                     return;
                 }
 
                 // Step 1.2.
@@ -237,17 +237,17 @@ impl EventSourceContext {
         self.data.clear();
 
         // Step 8.
         let global = event_source.global();
         let event_source = self.event_source.clone();
         let event = Trusted::new(&*event);
         // FIXME(nox): Why are errors silenced here?
         let _ = global.networking_task_source().queue(
-            box task!(dispatch_the_event_source_event: move || {
+            task!(dispatch_the_event_source_event: move || {
                 let event_source = event_source.root();
                 if event_source.ready_state.get() != ReadyState::Closed {
                     event.root().upcast::<Event>().fire(&event_source.upcast());
                 }
             }),
             &global,
         );
     }
--- a/servo/components/script/dom/filereader.rs
+++ b/servo/components/script/dom/filereader.rs
@@ -411,16 +411,16 @@ fn perform_annotated_read_operation(
     data: ReadMetaData,
     blob_contents: Arc<Vec<u8>>,
     filereader: TrustedFileReader,
     task_source: FileReadingTaskSource,
     canceller: TaskCanceller,
 ) {
     // Step 4
     let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id);
-    task_source.queue_with_canceller(box task, &canceller).unwrap();
+    task_source.queue_with_canceller(task, &canceller).unwrap();
 
     let task = FileReadingTask::ProcessReadData(filereader.clone(), gen_id);
-    task_source.queue_with_canceller(box task, &canceller).unwrap();
+    task_source.queue_with_canceller(task, &canceller).unwrap();
 
     let task = FileReadingTask::ProcessReadEOF(filereader, gen_id, data, blob_contents);
-    task_source.queue_with_canceller(box task, &canceller).unwrap();
+    task_source.queue_with_canceller(task, &canceller).unwrap();
 }
--- a/servo/components/script/dom/htmldetailselement.rs
+++ b/servo/components/script/dom/htmldetailselement.rs
@@ -65,17 +65,17 @@ impl VirtualMethods for HTMLDetailsEleme
         if attr.local_name() == &local_name!("open") {
             let counter = self.toggle_counter.get() + 1;
             self.toggle_counter.set(counter);
 
             let window = window_from_node(self);
             let this = Trusted::new(self);
             // FIXME(nox): Why are errors silenced here?
             let _ = window.dom_manipulation_task_source().queue(
-                box task!(details_notification_task_steps: move || {
+                task!(details_notification_task_steps: move || {
                     let this = this.root();
                     if counter == this.toggle_counter.get() {
                         this.upcast::<EventTarget>().fire_event(atom!("toggle"));
                     }
                 }),
                 window.upcast(),
             );
         }
--- a/servo/components/script/dom/htmlformelement.rs
+++ b/servo/components/script/dom/htmlformelement.rs
@@ -435,17 +435,17 @@ impl HTMLFormElement {
         // generation ID is the same as its own generation ID.
         let generation_id = GenerationId(self.generation_id.get().0 + 1);
         self.generation_id.set(generation_id);
 
         // Step 2.
         let pipeline_id = window.upcast::<GlobalScope>().pipeline_id();
         let script_chan = window.main_thread_script_chan().clone();
         let this = Trusted::new(self);
-        let task = box task!(navigate_to_form_planned_navigation: move || {
+        let task = task!(navigate_to_form_planned_navigation: move || {
             if generation_id != this.root().generation_id.get() {
                 return;
             }
             script_chan.send(MainThreadScriptMsg::Navigate(
                 pipeline_id,
                 load_data,
                 false,
             )).unwrap();
--- a/servo/components/script/dom/htmliframeelement.rs
+++ b/servo/components/script/dom/htmliframeelement.rs
@@ -231,17 +231,17 @@ impl HTMLIFrameElement {
         let window = window_from_node(self);
 
         // https://github.com/whatwg/html/issues/490
         if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) {
             let this = Trusted::new(self);
             let pipeline_id = self.pipeline_id().unwrap();
             // FIXME(nox): Why are errors silenced here?
             let _ = window.dom_manipulation_task_source().queue(
-                box task!(iframe_load_event_steps: move || {
+                task!(iframe_load_event_steps: move || {
                     this.root().iframe_load_event_steps(pipeline_id);
                 }),
                 window.upcast(),
             );
             return;
         }
 
         let url = self.get_url();
--- a/servo/components/script/dom/htmlimageelement.rs
+++ b/servo/components/script/dom/htmlimageelement.rs
@@ -169,17 +169,17 @@ impl HTMLImageElement {
             ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
                 debug!("Got image {:?}", message);
                 // Return the image via a message to the script thread, which marks
                 // the element as dirty and triggers a reflow.
                 let element = trusted_node.clone();
                 let image = message.to().unwrap();
                 // FIXME(nox): Why are errors silenced here?
                 let _ = task_source.queue_with_canceller(
-                    box task!(process_image_response: move || {
+                    task!(process_image_response: move || {
                         let element = element.root();
                         // Ignore any image response for a previous request that has been discarded.
                         if generation == element.generation.get() {
                             element.process_image_response(image);
                         }
                     }),
                     &task_canceller,
                 );
@@ -420,17 +420,17 @@ impl HTMLImageElement {
                 // Step 8.
                 // TODO: Handle pixel density.
                 src
             },
             None => {
                 // Step 9.
                 // FIXME(nox): Why are errors silenced here?
                 let _ = task_source.queue(
-                    box task!(image_null_source_error: move || {
+                    task!(image_null_source_error: move || {
                         let this = this.root();
                         {
                             let mut current_request =
                                 this.current_request.borrow_mut();
                             current_request.source_url = None;
                             current_request.parsed_url = None;
                         }
                         if this.upcast::<Element>().has_attribute(&local_name!("src")) {
@@ -446,17 +446,17 @@ impl HTMLImageElement {
                 );
                 return;
             },
         };
         // Step 10.
         let target = Trusted::new(self.upcast::<EventTarget>());
         // FIXME(nox): Why are errors silenced here?
         let _ = task_source.queue(
-            box task!(fire_progress_event: move || {
+            task!(fire_progress_event: move || {
                 let target = target.root();
 
                 let event = ProgressEvent::new(
                     &target.global(),
                     atom!("loadstart"),
                     EventBubbles::DoesNotBubble,
                     EventCancelable::NotCancelable,
                     false,
@@ -475,17 +475,17 @@ impl HTMLImageElement {
                     // Step 12
                 self.prepare_image_request(&url, &src);
             },
             Err(_) => {
                 // Step 11.1-11.5.
                 let src = String::from(src);
                 // FIXME(nox): Why are errors silenced here?
                 let _ = task_source.queue(
-                    box task!(image_selected_source_error: move || {
+                    task!(image_selected_source_error: move || {
                         let this = this.root();
                         {
                             let mut current_request =
                                 this.current_request.borrow_mut();
                             current_request.source_url = Some(src.into());
                         }
                         this.upcast::<EventTarget>().fire_event(atom!("error"));
                         this.upcast::<EventTarget>().fire_event(atom!("loadend"));
@@ -544,17 +544,17 @@ impl HTMLImageElement {
                     self.abort_request(State::CompletelyAvailable, ImageRequestPhase::Pending);
                     let mut current_request = self.current_request.borrow_mut();
                     current_request.final_url = Some(url);
                     current_request.image = Some(image.clone());
                     current_request.metadata = Some(metadata);
                     let this = Trusted::new(self);
                     let src = String::from(src);
                     let _ = window.dom_manipulation_task_source().queue(
-                        box task!(image_load_event: move || {
+                        task!(image_load_event: move || {
                             let this = this.root();
                             {
                                 let mut current_request =
                                     this.current_request.borrow_mut();
                                 current_request.parsed_url = Some(img_url);
                                 current_request.source_url = Some(src.into());
                             }
                             // TODO: restart animation, if set.
--- a/servo/components/script/dom/htmlmediaelement.rs
+++ b/servo/components/script/dom/htmlmediaelement.rs
@@ -149,17 +149,17 @@ impl HTMLMediaElement {
             // FIXME(nox): Take pending play promises and let promises be the
             // result.
 
             // Step 2.3.
             let window = window_from_node(self);
             let target = Trusted::new(self.upcast::<EventTarget>());
             // FIXME(nox): Why are errors silenced here?
             let _ = window.dom_manipulation_task_source().queue(
-                box task!(internal_pause_steps: move || {
+                task!(internal_pause_steps: move || {
                     let target = target.root();
 
                     // Step 2.3.1.
                     target.fire_event(atom!("timeupdate"));
 
                     // Step 2.3.2.
                     target.fire_event(atom!("pause"));
 
@@ -181,17 +181,17 @@ impl HTMLMediaElement {
         // Step 1.
         // TODO(nox): Take pending play promises and let promises be the result.
 
         // Step 2.
         let target = Trusted::new(self.upcast::<EventTarget>());
         let window = window_from_node(self);
         // FIXME(nox): Why are errors silenced here?
         let _ = window.dom_manipulation_task_source().queue(
-            box task!(notify_about_playing: move || {
+            task!(notify_about_playing: move || {
                 let target = target.root();
 
                 // Step 2.1.
                 target.fire_event(atom!("playing"));
 
                 // Step 2.2.
                 // FIXME(nox): Resolve pending play promises with promises.
             }),
@@ -490,17 +490,17 @@ impl HTMLMediaElement {
     /// Queues the [dedicated media source failure steps][steps].
     ///
     /// [steps]: https://html.spec.whatwg.org/multipage/#dedicated-media-source-failure-steps
     fn queue_dedicated_media_source_failure_steps(&self) {
         let this = Trusted::new(self);
         let window = window_from_node(self);
         // FIXME(nox): Why are errors silenced here?
         let _ = window.dom_manipulation_task_source().queue(
-            box task!(dedicated_media_source_failure_steps: move || {
+            task!(dedicated_media_source_failure_steps: move || {
                 let this = this.root();
 
                 // Step 1.
                 this.error.set(Some(&*MediaError::new(
                     &window_from_node(&*this),
                     MEDIA_ERR_SRC_NOT_SUPPORTED,
                 )));
 
--- a/servo/components/script/dom/serviceworker.rs
+++ b/servo/components/script/dom/serviceworker.rs
@@ -14,17 +14,17 @@ use dom::bindings::str::USVString;
 use dom::bindings::structuredclone::StructuredCloneData;
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom_struct::dom_struct;
 use js::jsapi::{HandleValue, JSContext};
 use script_traits::{ScriptMsg, DOMMessage};
 use servo_url::ServoUrl;
 use std::cell::Cell;
-use task::Task;
+use task::TaskOnce;
 
 pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
 
 #[dom_struct]
 pub struct ServiceWorker {
     eventtarget: EventTarget,
     script_url: DOMRefCell<String>,
     scope_url: ServoUrl,
@@ -99,15 +99,14 @@ impl ServiceWorkerMethods for ServiceWor
 
     // https://w3c.github.io/ServiceWorker/#service-worker-container-onerror-attribute
     event_handler!(error, GetOnerror, SetOnerror);
 
     // https://w3c.github.io/ServiceWorker/#ref-for-service-worker-onstatechange-attribute-1
     event_handler!(statechange, GetOnstatechange, SetOnstatechange);
 }
 
-impl Task for SimpleWorkerErrorHandler<ServiceWorker> {
+impl TaskOnce for SimpleWorkerErrorHandler<ServiceWorker> {
     #[allow(unrooted_must_root)]
-    fn run(self: Box<Self>) {
-        let this = *self;
-        ServiceWorker::dispatch_simple_error(this.addr);
+    fn run_once(self) {
+        ServiceWorker::dispatch_simple_error(self.addr);
     }
 }
--- a/servo/components/script/dom/storage.rs
+++ b/servo/components/script/dom/storage.rs
@@ -162,17 +162,17 @@ impl Storage {
         url: ServoUrl,
         key: Option<String>,
         old_value: Option<String>,
         new_value: Option<String>,
     ) {
         let global = self.global();
         let this = Trusted::new(self);
         global.as_window().dom_manipulation_task_source().queue(
-            box task!(send_storage_notification: move || {
+            task!(send_storage_notification: move || {
                 let this = this.root();
                 let global = this.global();
                 let event = StorageEvent::new(
                     global.as_window(),
                     atom!("storage"),
                     EventBubbles::DoesNotBubble,
                     EventCancelable::NotCancelable,
                     key.map(DOMString::from),
--- a/servo/components/script/dom/websocket.rs
+++ b/servo/components/script/dom/websocket.rs
@@ -32,17 +32,17 @@ use net_traits::MessageData;
 use script_runtime::CommonScriptMsg;
 use script_runtime::ScriptThreadEventCategory::WebSocketEvent;
 use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::ptr;
 use std::thread;
-use task::{Task, TaskCanceller};
+use task::{TaskOnce, TaskCanceller};
 use task_source::TaskSource;
 use task_source::networking::NetworkingTaskSource;
 
 #[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable, PartialEq)]
 enum WebSocketRequestState {
     Connecting = 0,
     Open = 1,
     Closing = 2,
@@ -69,31 +69,31 @@ mod close_code {
 
 pub fn close_the_websocket_connection(
     address: Trusted<WebSocket>,
     task_source: &NetworkingTaskSource,
     canceller: &TaskCanceller,
     code: Option<u16>,
     reason: String,
 ) {
-    let close_task = box CloseTask {
+    let close_task = CloseTask {
         address: address,
         failed: false,
         code: code,
         reason: Some(reason),
     };
     task_source.queue_with_canceller(close_task, &canceller).unwrap();
 }
 
 pub fn fail_the_websocket_connection(
     address: Trusted<WebSocket>,
     task_source: &NetworkingTaskSource,
     canceller: &TaskCanceller,
 ) {
-    let close_task = box CloseTask {
+    let close_task = CloseTask {
         address: address,
         failed: true,
         code: Some(close_code::ABNORMAL),
         reason: None,
     };
     task_source.queue_with_canceller(close_task, &canceller).unwrap();
 }
 
@@ -201,24 +201,24 @@ impl WebSocket {
         *ws.sender.borrow_mut() = Some(dom_action_sender);
 
         let task_source = global.networking_task_source();
         let canceller = global.task_canceller();
         thread::spawn(move || {
             while let Ok(event) = dom_event_receiver.recv() {
                 match event {
                     WebSocketNetworkEvent::ConnectionEstablished { protocol_in_use } => {
-                        let open_thread = box ConnectionEstablishedTask {
+                        let open_thread = ConnectionEstablishedTask {
                             address: address.clone(),
                             protocol_in_use,
                         };
                         task_source.queue_with_canceller(open_thread, &canceller).unwrap();
                     },
                     WebSocketNetworkEvent::MessageReceived(message) => {
-                        let message_thread = box MessageReceivedTask {
+                        let message_thread = MessageReceivedTask {
                             address: address.clone(),
                             message: message,
                         };
                         task_source.queue_with_canceller(message_thread, &canceller).unwrap();
                     },
                     WebSocketNetworkEvent::Fail => {
                         fail_the_websocket_connection(address.clone(),
                             &task_source, &canceller);
@@ -392,19 +392,19 @@ impl WebSocketMethods for WebSocket {
 
 /// Task queued when *the WebSocket connection is established*.
 /// https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol:concept-websocket-established
 struct ConnectionEstablishedTask {
     address: Trusted<WebSocket>,
     protocol_in_use: Option<String>,
 }
 
-impl Task for ConnectionEstablishedTask {
+impl TaskOnce for ConnectionEstablishedTask {
     /// https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol:concept-websocket-established
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         let ws = self.address.root();
 
         // Step 1.
         ws.ready_state.set(WebSocketRequestState::Open);
 
         // Step 2: Extensions.
         // TODO: Set extensions to extensions in use.
 
@@ -417,39 +417,39 @@ impl Task for ConnectionEstablishedTask 
         ws.upcast().fire_event(atom!("open"));
     }
 }
 
 struct BufferedAmountTask {
     address: Trusted<WebSocket>,
 }
 
-impl Task for BufferedAmountTask {
+impl TaskOnce for BufferedAmountTask {
     // See https://html.spec.whatwg.org/multipage/#dom-websocket-bufferedamount
     //
     // To be compliant with standards, we need to reset bufferedAmount only when the event loop
     // reaches step 1.  In our implementation, the bytes will already have been sent on a background
     // thread.
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         let ws = self.address.root();
 
         ws.buffered_amount.set(0);
         ws.clearing_buffer.set(false);
     }
 }
 
 struct CloseTask {
     address: Trusted<WebSocket>,
     failed: bool,
     code: Option<u16>,
     reason: Option<String>,
 }
 
-impl Task for CloseTask {
-    fn run(self: Box<Self>) {
+impl TaskOnce for CloseTask {
+    fn run_once(self) {
         let ws = self.address.root();
 
         if ws.ready_state.get() == WebSocketRequestState::Closed {
             // Do nothing if already closed.
             return;
         }
 
         // Perform _the WebSocket connection is closed_ steps.
@@ -478,19 +478,19 @@ impl Task for CloseTask {
     }
 }
 
 struct MessageReceivedTask {
     address: Trusted<WebSocket>,
     message: MessageData,
 }
 
-impl Task for MessageReceivedTask {
+impl TaskOnce for MessageReceivedTask {
     #[allow(unsafe_code)]
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         let ws = self.address.root();
         debug!("MessageReceivedTask::handler({:p}): readyState={:?}", &*ws,
                ws.ready_state.get());
 
         // Step 1.
         if ws.ready_state.get() != WebSocketRequestState::Open {
             return;
         }
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -1972,17 +1972,17 @@ fn debug_reflow_events(id: PipelineId, g
 impl Window {
     // https://html.spec.whatwg.org/multipage/#dom-window-postmessage step 7.
     pub fn post_message(
         &self,
         target_origin: Option<ImmutableOrigin>,
         serialize_with_transfer_result: StructuredCloneData,
     ) {
         let this = Trusted::new(self);
-        let task = box task!(post_serialised_message: move || {
+        let task = task!(post_serialised_message: move || {
             let this = this.root();
 
             // Step 7.1.
             if let Some(target_origin) = target_origin {
                 if !target_origin.same_origin(this.Document().origin()) {
                     return;
                 }
             }
@@ -2007,12 +2007,12 @@ impl Window {
                 this.upcast(),
                 message_clone.handle(),
             );
         });
         // FIXME(nox): Why are errors silenced here?
         // TODO(#12718): Use the "posted message task source".
         let _ = self.script_chan.send(CommonScriptMsg::Task(
             ScriptThreadEventCategory::DomEvent,
-            self.task_canceller().wrap_task(task),
+            box self.task_canceller().wrap_task(task),
         ));
     }
 }
--- a/servo/components/script/dom/worker.rs
+++ b/servo/components/script/dom/worker.rs
@@ -23,17 +23,17 @@ use dom_struct::dom_struct;
 use ipc_channel::ipc;
 use js::jsapi::{HandleValue, JSAutoCompartment, JSContext};
 use js::jsval::UndefinedValue;
 use script_traits::WorkerScriptLoadOrigin;
 use std::cell::Cell;
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::mpsc::{Sender, channel};
-use task::Task;
+use task::TaskOnce;
 
 pub type TrustedWorkerAddress = Trusted<Worker>;
 
 // https://html.spec.whatwg.org/multipage/#worker
 #[dom_struct]
 pub struct Worker {
     eventtarget: EventTarget,
     #[ignore_heap_size_of = "Defined in std"]
@@ -170,15 +170,14 @@ impl WorkerMethods for Worker {
 
     // https://html.spec.whatwg.org/multipage/#handler-worker-onmessage
     event_handler!(message, GetOnmessage, SetOnmessage);
 
     // https://html.spec.whatwg.org/multipage/#handler-workerglobalscope-onerror
     event_handler!(error, GetOnerror, SetOnerror);
 }
 
-impl Task for SimpleWorkerErrorHandler<Worker> {
+impl TaskOnce for SimpleWorkerErrorHandler<Worker> {
     #[allow(unrooted_must_root)]
-    fn run(self: Box<Self>) {
-        let this = *self;
-        Worker::dispatch_simple_error(this.addr);
+    fn run_once(self) {
+        Worker::dispatch_simple_error(self.addr);
     }
 }
--- a/servo/components/script/dom/workerglobalscope.rs
+++ b/servo/components/script/dom/workerglobalscope.rs
@@ -383,17 +383,17 @@ impl WorkerGlobalScope {
         } else {
             panic!("need to implement a sender for SharedWorker/ServiceWorker")
         }
     }
 
     pub fn process_event(&self, msg: CommonScriptMsg) {
         match msg {
             CommonScriptMsg::Task(_, task) => {
-                task.run()
+                task.run_box()
             },
             CommonScriptMsg::CollectReports(reports_chan) => {
                 let cx = self.get_cx();
                 let path_seg = format!("url({})", self.get_url());
                 let reports = get_reports(cx, path_seg);
                 reports_chan.send(reports);
             },
         }
--- a/servo/components/script/dom/worklet.rs
+++ b/servo/components/script/dom/worklet.rs
@@ -64,17 +64,17 @@ use std::sync::atomic::AtomicIsize;
 use std::sync::atomic::Ordering;
 use std::sync::mpsc;
 use std::sync::mpsc::Receiver;
 use std::sync::mpsc::Sender;
 use std::thread;
 use style::thread_state;
 use swapper::Swapper;
 use swapper::swapper;
-use task::Task;
+use task::TaskBox;
 use uuid::Uuid;
 
 // Magic numbers
 const WORKLET_THREAD_POOL_SIZE: u32 = 3;
 const MIN_GC_THRESHOLD: u32 = 1_000_000;
 
 #[dom_struct]
 /// https://drafts.css-houdini.org/worklets/#worklet
@@ -640,18 +640,19 @@ impl WorkletThread {
                                                        credentials,
                                                        pending_tasks_struct,
                                                        promise)
             }
         }
     }
 
     /// Run a task in the main script thread.
-    fn run_in_script_thread<T>(&self, task: T) where
-        T: 'static + Send + Task,
+    fn run_in_script_thread<T>(&self, task: T)
+    where
+        T: TaskBox + 'static,
     {
         let msg = CommonScriptMsg::Task(ScriptThreadEventCategory::WorkletEvent, box task);
         let msg = MainThreadScriptMsg::Common(msg);
         self.global_init.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread.");
     }
 }
 
 /// An executor of worklet tasks
--- a/servo/components/script/network_listener.rs
+++ b/servo/components/script/network_listener.rs
@@ -1,29 +1,29 @@
 /* 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/. */
 
 use net_traits::{Action, FetchResponseListener, FetchResponseMsg};
 use std::sync::{Arc, Mutex};
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 use task_source::networking::NetworkingTaskSource;
 
 /// An off-thread sink for async network event tasks. All such events are forwarded to
 /// a target thread, where they are invoked on the provided context object.
 pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
     pub context: Arc<Mutex<Listener>>,
     pub task_source: NetworkingTaskSource,
     pub canceller: Option<TaskCanceller>,
 }
 
 impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
     pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
-        let task = box ListenerTask {
+        let task = ListenerTask {
             context: self.context.clone(),
             action: action,
         };
         let result = if let Some(ref canceller) = self.canceller {
             self.task_source.queue_with_canceller(task, canceller)
         } else {
             self.task_source.queue_unconditionally(task)
         };
@@ -50,21 +50,20 @@ pub trait PreInvoke {
 }
 
 /// A task for moving the async network events between threads.
 struct ListenerTask<A: Action<Listener> + Send + 'static, Listener: PreInvoke + Send> {
     context: Arc<Mutex<Listener>>,
     action: A,
 }
 
-impl<A, Listener> Task for ListenerTask<A, Listener>
+impl<A, Listener> TaskOnce for ListenerTask<A, Listener>
 where
     A: Action<Listener> + Send + 'static,
     Listener: PreInvoke + Send,
 {
-    fn run(self: Box<Self>) {
-        let this = *self;
-        let mut context = this.context.lock().unwrap();
+    fn run_once(self) {
+        let mut context = self.context.lock().unwrap();
         if context.should_invoke() {
-            this.action.process(&mut *context);
+            self.action.process(&mut *context);
         }
     }
 }
--- a/servo/components/script/script_runtime.rs
+++ b/servo/components/script/script_runtime.rs
@@ -30,26 +30,26 @@ use std::cell::Cell;
 use std::fmt;
 use std::io::{Write, stdout};
 use std::marker::PhantomData;
 use std::os;
 use std::os::raw::c_void;
 use std::panic::AssertUnwindSafe;
 use std::ptr;
 use style::thread_state;
-use task::Task;
+use task::TaskBox;
 use time::{Tm, now};
 
 /// Common messages used to control the event loops in both the script and the worker
 pub enum CommonScriptMsg {
     /// Requests that the script thread measure its memory usage. The results are sent back via the
     /// supplied channel.
     CollectReports(ReportsChan),
     /// Generic message that encapsulates event handling.
-    Task(ScriptThreadEventCategory, Box<Task + Send>),
+    Task(ScriptThreadEventCategory, Box<TaskBox>),
 }
 
 impl fmt::Debug for CommonScriptMsg {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             CommonScriptMsg::CollectReports(_) => write!(f, "CollectReports(...)"),
             CommonScriptMsg::Task(ref category, ref task) => {
                 f.debug_tuple("Task").field(category).field(task).finish()
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -1253,17 +1253,17 @@ impl ScriptThread {
         match msg {
             MainThreadScriptMsg::Navigate(parent_pipeline_id, load_data, replace) => {
                 self.handle_navigate(parent_pipeline_id, None, load_data, replace)
             },
             MainThreadScriptMsg::ExitWindow(id) => {
                 self.handle_exit_window_msg(id)
             },
             MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, task)) => {
-                task.run()
+                task.run_box()
             }
             MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(chan)) => {
                 self.collect_reports(chan)
             },
             MainThreadScriptMsg::WorkletLoaded(pipeline_id) => {
                 self.handle_worklet_loaded(pipeline_id)
             },
             MainThreadScriptMsg::RegisterPaintWorklet {
--- a/servo/components/script/serviceworkerjob.rs
+++ b/servo/components/script/serviceworkerjob.rs
@@ -270,17 +270,17 @@ fn settle_job_promise(global: &GlobalSco
 }
 
 #[allow(unrooted_must_root)]
 fn queue_settle_promise_for_job(job: &Job, settle: SettleType, task_source: &DOMManipulationTaskSource) {
     let global = job.client.global();
     let promise = TrustedPromise::new(job.promise.clone());
     // FIXME(nox): Why are errors silenced here?
     let _ = task_source.queue(
-        box task!(settle_promise_for_job: move || {
+        task!(settle_promise_for_job: move || {
             let promise = promise.root();
             settle_job_promise(&promise.global(), &promise, settle)
         }),
         &*global,
     );
 }
 
 // https://w3c.github.io/ServiceWorker/#reject-job-promise-algorithm
--- a/servo/components/script/task.rs
+++ b/servo/components/script/task.rs
@@ -8,87 +8,110 @@ use std::fmt;
 use std::intrinsics;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, Ordering};
 
 macro_rules! task {
     ($name:ident: move || $body:tt) => {{
         #[allow(non_camel_case_types)]
         struct $name<F>(F);
-        impl<F> ::task::Task for $name<F>
+        impl<F> ::task::TaskOnce for $name<F>
         where
-            F: ::std::ops::FnOnce(),
+            F: ::std::ops::FnOnce() + Send,
         {
             fn name(&self) -> &'static str {
                 stringify!($name)
             }
 
-            fn run(self: Box<Self>) {
+            fn run_once(self) {
                 (self.0)();
             }
         }
         $name(move || $body)
     }};
 }
 
 /// A task that can be run. The name method is for profiling purposes.
-pub trait Task {
+pub trait TaskOnce: Send {
     #[allow(unsafe_code)]
-    fn name(&self) -> &'static str { unsafe { intrinsics::type_name::<Self>() } }
-    fn run(self: Box<Self>);
+    fn name(&self) -> &'static str {
+        unsafe { intrinsics::type_name::<Self>() }
+    }
+
+    fn run_once(self);
 }
 
-impl fmt::Debug for Task + Send {
+/// A boxed version of `TaskOnce`.
+pub trait TaskBox: Send {
+    fn name(&self) -> &'static str;
+
+    fn run_box(self: Box<Self>);
+}
+
+impl<T> TaskBox for T
+where
+    T: TaskOnce,
+{
+    fn name(&self) -> &'static str {
+        TaskOnce::name(self)
+    }
+
+    fn run_box(self: Box<Self>) {
+        self.run_once()
+    }
+}
+
+impl fmt::Debug for TaskBox {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt.debug_tuple(self.name()).field(&format_args!("...")).finish()
     }
 }
 
 /// Encapsulated state required to create cancellable tasks from non-script threads.
 pub struct TaskCanceller {
     pub cancelled: Option<Arc<AtomicBool>>,
 }
 
 impl TaskCanceller {
     /// Returns a wrapped `task` that will be cancelled if the `TaskCanceller`
     /// says so.
-    pub fn wrap_task<T>(&self, task: Box<T>) -> Box<Task + Send>
+    pub fn wrap_task<T>(&self, task: T) -> impl TaskOnce
     where
-        T: Send + Task + 'static,
+        T: TaskOnce,
     {
-        box CancellableTask {
+        CancellableTask {
             cancelled: self.cancelled.clone(),
             inner: task,
         }
     }
 }
 
 /// A task that can be cancelled by toggling a shared flag.
-pub struct CancellableTask<T: Send + Task> {
+pub struct CancellableTask<T: TaskOnce> {
     cancelled: Option<Arc<AtomicBool>>,
-    inner: Box<T>,
+    inner: T,
 }
 
 impl<T> CancellableTask<T>
 where
-    T: Send + Task,
+    T: TaskOnce,
 {
     fn is_cancelled(&self) -> bool {
         self.cancelled.as_ref().map_or(false, |cancelled| {
             cancelled.load(Ordering::SeqCst)
         })
     }
 }
 
-impl<T> Task for CancellableTask<T>
+impl<T> TaskOnce for CancellableTask<T>
 where
-    T: Send + Task,
+    T: TaskOnce,
 {
     fn name(&self) -> &'static str {
         self.inner.name()
     }
 
-    fn run(self: Box<Self>) {
+    fn run_once(self) {
         if !self.is_cancelled() {
-            self.inner.run()
+            self.inner.run_once()
         }
     }
 }
--- a/servo/components/script/task_source/dom_manipulation.rs
+++ b/servo/components/script/task_source/dom_manipulation.rs
@@ -8,59 +8,59 @@ use dom::event::{EventBubbles, EventCanc
 use dom::eventtarget::EventTarget;
 use dom::window::Window;
 use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
 use script_thread::MainThreadScriptMsg;
 use servo_atoms::Atom;
 use std::fmt;
 use std::result::Result;
 use std::sync::mpsc::Sender;
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 
 #[derive(Clone, JSTraceable)]
 pub struct DOMManipulationTaskSource(pub Sender<MainThreadScriptMsg>);
 
 impl fmt::Debug for DOMManipulationTaskSource {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "DOMManipulationTaskSource(...)")
     }
 }
 
 impl TaskSource for DOMManipulationTaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Task + Send + 'static,
+        T: TaskOnce + 'static,
     {
         let msg = MainThreadScriptMsg::Common(CommonScriptMsg::Task(
             ScriptThreadEventCategory::ScriptEvent,
-            canceller.wrap_task(msg),
+            box canceller.wrap_task(task),
         ));
         self.0.send(msg).map_err(|_| ())
     }
 }
 
 impl DOMManipulationTaskSource {
     pub fn queue_event(&self,
                        target: &EventTarget,
                        name: Atom,
                        bubbles: EventBubbles,
                        cancelable: EventCancelable,
                        window: &Window) {
         let target = Trusted::new(target);
-        let task = box EventTask {
+        let task = EventTask {
             target: target,
             name: name,
             bubbles: bubbles,
             cancelable: cancelable,
         };
         let _ = self.queue(task, window.upcast());
     }
 
     pub fn queue_simple_event(&self, target: &EventTarget, name: Atom, window: &Window) {
         let target = Trusted::new(target);
-        let _ = self.queue(box SimpleEventTask { target, name }, window.upcast());
+        let _ = self.queue(SimpleEventTask { target, name }, window.upcast());
     }
 }
--- a/servo/components/script/task_source/file_reading.rs
+++ b/servo/components/script/task_source/file_reading.rs
@@ -1,46 +1,46 @@
 /* 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/. */
 
 use dom::domexception::DOMErrorName;
 use dom::filereader::{FileReader, TrustedFileReader, GenerationId, ReadMetaData};
 use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory, ScriptChan};
 use std::sync::Arc;
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 
 #[derive(JSTraceable)]
 pub struct FileReadingTaskSource(pub Box<ScriptChan + Send + 'static>);
 
 impl Clone for FileReadingTaskSource {
     fn clone(&self) -> FileReadingTaskSource {
         FileReadingTaskSource(self.0.clone())
     }
 }
 
 impl TaskSource for FileReadingTaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Send + Task + 'static,
+        T: TaskOnce + 'static,
     {
         self.0.send(CommonScriptMsg::Task(
             ScriptThreadEventCategory::FileRead,
-            canceller.wrap_task(msg),
+            box canceller.wrap_task(task),
         ))
     }
 }
 
-impl Task for FileReadingTask {
-    fn run(self: Box<Self>) {
+impl TaskOnce for FileReadingTask {
+    fn run_once(self) {
         self.handle_task();
     }
 }
 
 #[allow(dead_code)]
 pub enum FileReadingTask {
     ProcessRead(TrustedFileReader, GenerationId),
     ProcessReadData(TrustedFileReader, GenerationId),
--- a/servo/components/script/task_source/mod.rs
+++ b/servo/components/script/task_source/mod.rs
@@ -6,23 +6,26 @@ pub mod dom_manipulation;
 pub mod file_reading;
 pub mod history_traversal;
 pub mod networking;
 pub mod performance_timeline;
 pub mod user_interaction;
 
 use dom::globalscope::GlobalScope;
 use std::result::Result;
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 
 pub trait TaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Send + Task + 'static;
+        T: TaskOnce + 'static;
 
-    fn queue<T: Task + Send + 'static>(&self, msg: Box<T>, global: &GlobalScope) -> Result<(), ()> {
-        self.queue_with_canceller(msg, &global.task_canceller())
+    fn queue<T>(&self, task: T, global: &GlobalScope) -> Result<(), ()>
+    where
+        T: TaskOnce + 'static,
+    {
+        self.queue_with_canceller(task, &global.task_canceller())
     }
 }
--- a/servo/components/script/task_source/networking.rs
+++ b/servo/components/script/task_source/networking.rs
@@ -1,43 +1,46 @@
 /* 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/. */
 
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 
 #[derive(JSTraceable)]
 pub struct NetworkingTaskSource(pub Box<ScriptChan + Send + 'static>);
 
 impl Clone for NetworkingTaskSource {
     fn clone(&self) -> NetworkingTaskSource {
         NetworkingTaskSource(self.0.clone())
     }
 }
 
 impl TaskSource for NetworkingTaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Send + Task + 'static,
+        T: TaskOnce + 'static,
     {
         self.0.send(CommonScriptMsg::Task(
             ScriptThreadEventCategory::NetworkEvent,
-            canceller.wrap_task(msg),
+            box canceller.wrap_task(task),
         ))
     }
 }
 
 impl NetworkingTaskSource {
     /// This queues a task that will not be cancelled when its associated
     /// global scope gets destroyed.
-    pub fn queue_unconditionally<T>(&self, msg: Box<T>) -> Result<(), ()>
+    pub fn queue_unconditionally<T>(&self, task: T) -> Result<(), ()>
     where
-        T: Task + Send + 'static,
+        T: TaskOnce + 'static,
     {
-        self.0.send(CommonScriptMsg::Task(ScriptThreadEventCategory::NetworkEvent, msg))
+        self.0.send(CommonScriptMsg::Task(
+            ScriptThreadEventCategory::NetworkEvent,
+            box task,
+        ))
     }
 }
--- a/servo/components/script/task_source/performance_timeline.rs
+++ b/servo/components/script/task_source/performance_timeline.rs
@@ -6,17 +6,17 @@
 //     a low priority task and it should be processed during idle periods.
 //     We are currently treating this task queue as a normal priority queue.
 
 use dom::bindings::refcounted::Trusted;
 use dom::globalscope::GlobalScope;
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
 use std::fmt;
 use std::result::Result;
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 
 #[derive(JSTraceable)]
 pub struct PerformanceTimelineTaskSource(pub Box<ScriptChan + Send + 'static>);
 
 impl Clone for PerformanceTimelineTaskSource {
     fn clone(&self) -> PerformanceTimelineTaskSource {
         PerformanceTimelineTaskSource(self.0.clone())
@@ -27,34 +27,34 @@ impl fmt::Debug for PerformanceTimelineT
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "PerformanceTimelineTaskSource(...)")
     }
 }
 
 impl TaskSource for PerformanceTimelineTaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Send + Task + 'static,
+        T: TaskOnce + 'static,
     {
         let msg = CommonScriptMsg::Task(
             ScriptThreadEventCategory::PerformanceTimelineTask,
-            canceller.wrap_task(msg)
+            box canceller.wrap_task(task)
         );
         self.0.send(msg).map_err(|_| ())
     }
 }
 
 impl PerformanceTimelineTaskSource {
     pub fn queue_notification(&self, global: &GlobalScope) {
         let owner = Trusted::new(&*global.performance());
         // FIXME(nox): Why are errors silenced here?
         let _ = self.queue(
-            box task!(notify_performance_observers: move || {
+            task!(notify_performance_observers: move || {
                 owner.root().notify_observers();
             }),
             global,
         );
     }
 }
--- a/servo/components/script/task_source/user_interaction.rs
+++ b/servo/components/script/task_source/user_interaction.rs
@@ -8,49 +8,49 @@ use dom::event::{EventBubbles, EventCanc
 use dom::eventtarget::EventTarget;
 use dom::window::Window;
 use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
 use script_thread::MainThreadScriptMsg;
 use servo_atoms::Atom;
 use std::fmt;
 use std::result::Result;
 use std::sync::mpsc::Sender;
-use task::{Task, TaskCanceller};
+use task::{TaskCanceller, TaskOnce};
 use task_source::TaskSource;
 
 #[derive(Clone, JSTraceable)]
 pub struct UserInteractionTaskSource(pub Sender<MainThreadScriptMsg>);
 
 impl fmt::Debug for UserInteractionTaskSource {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "UserInteractionTaskSource(...)")
     }
 }
 
 impl TaskSource for UserInteractionTaskSource {
     fn queue_with_canceller<T>(
         &self,
-        msg: Box<T>,
+        task: T,
         canceller: &TaskCanceller,
     ) -> Result<(), ()>
     where
-        T: Task + Send + 'static,
+        T: TaskOnce + 'static,
     {
         let msg = MainThreadScriptMsg::Common(CommonScriptMsg::Task(
             ScriptThreadEventCategory::InputEvent,
-            canceller.wrap_task(msg),
+            box canceller.wrap_task(task),
         ));
         self.0.send(msg).map_err(|_| ())
     }
 }
 
 impl UserInteractionTaskSource {
     pub fn queue_event(&self,
                        target: &EventTarget,
                        name: Atom,
                        bubbles: EventBubbles,
                        cancelable: EventCancelable,
                        window: &Window) {
         let target = Trusted::new(target);
-        let task = box EventTask { target, name, bubbles, cancelable };
+        let task = EventTask { target, name, bubbles, cancelable };
         let _ = self.queue(task, window.upcast());
     }
 }
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1932,16 +1932,21 @@ extern "C" {
                                                  index: usize)
      -> ServoStyleContextStrong;
 }
 extern "C" {
     pub fn Servo_Element_IsDisplayNone(element: RawGeckoElementBorrowed)
      -> bool;
 }
 extern "C" {
+    pub fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element:
+                                                             RawGeckoElementBorrowed)
+     -> bool;
+}
+extern "C" {
     pub fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
                                           gecko_stylesheet:
                                               *mut ServoStyleSheet,
                                           data: *const u8, data_len: usize,
                                           parsing_mode: SheetParsingMode,
                                           extra_data:
                                               *mut RawGeckoURLExtraData,
                                           line_number_offset: u32,
--- a/servo/components/style/sharing/mod.rs
+++ b/servo/components/style/sharing/mod.rs
@@ -740,21 +740,26 @@ impl<E: TElement> StyleSharingCache<E> {
 
         debug!("Sharing allowed between {:?} and {:?}", target.element, candidate.element);
         Some(candidate.element.borrow_data().unwrap().share_styles())
     }
 
     /// Attempts to find an element in the cache with the given primary rule node and parent.
     pub fn lookup_by_rules(
         &mut self,
+        shared_context: &SharedStyleContext,
         inherited: &ComputedValues,
         rules: &StrongRuleNode,
         visited_rules: Option<&StrongRuleNode>,
         target: E,
     ) -> Option<PrimaryStyle> {
+        if shared_context.options.disable_style_sharing_cache {
+            return None;
+        }
+
         self.cache_mut().lookup(|candidate| {
             debug_assert_ne!(candidate.element, target);
             if !candidate.parent_style_identity().eq(inherited) {
                 return None;
             }
             let data = candidate.element.borrow_data().unwrap();
             let style = data.styles.primary();
             if style.rules.as_ref() != Some(&rules) {
--- a/servo/components/style/style_resolver.rs
+++ b/servo/components/style/style_resolver.rs
@@ -190,16 +190,17 @@ where
         // reuse the style via rule node identity.
         let may_reuse =
             !self.element.is_native_anonymous() &&
             parent_style.is_some() &&
             inputs.rules.is_some();
 
         if may_reuse {
             let cached = self.context.thread_local.sharing_cache.lookup_by_rules(
+                self.context.shared,
                 parent_style.unwrap(),
                 inputs.rules.as_ref().unwrap(),
                 inputs.visited_rules.as_ref(),
                 self.element,
             );
             if let Some(mut primary_style) = cached {
                 self.context.thread_local.statistics.styles_reused += 1;
                 primary_style.reused_via_rule_node |= true;
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -13,17 +13,17 @@ use std::cell::RefCell;
 use std::env;
 use std::fmt::Write;
 use std::iter;
 use std::mem;
 use std::ptr;
 use style::applicable_declarations::ApplicableDeclarationBlock;
 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
 use style::context::ThreadLocalStyleContext;
-use style::data::ElementStyles;
+use style::data::{ElementStyles, self};
 use style::dom::{ShowSubtreeData, TElement, TNode};
 use style::driver;
 use style::element_state::ElementState;
 use style::error_reporting::{NullReporter, ParseErrorReporter};
 use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
 use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
 use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL};
 use style::gecko::restyle_damage::GeckoRestyleDamage;
@@ -178,16 +178,22 @@ pub extern "C" fn Servo_Initialize(dummy
     parser::assert_parsing_mode_match();
     traversal_flags::assert_traversal_flags_match();
 
     // Initialize the dummy url data
     unsafe { DUMMY_URL_DATA = dummy_url_data; }
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_InitializeCooperativeThread() {
+    // Pretend that we're a Servo Layout thread to make some assertions happy.
+    thread_state::initialize(thread_state::LAYOUT);
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_Shutdown() {
     // The dummy url will be released after shutdown, so clear the
     // reference to avoid use-after-free.
     unsafe { DUMMY_URL_DATA = ptr::null_mut(); }
     Stylist::shutdown();
 }
 
 unsafe fn dummy_url_data() -> &'static RefPtr<URLExtraData> {
@@ -831,24 +837,31 @@ pub extern "C" fn Servo_Element_GetPseud
 {
     let element = GeckoElement(element);
     let data = element.borrow_data().expect("Getting CVs that aren't present");
     data.styles.pseudos.as_array()[index].as_ref().expect("Getting CVs that aren't present")
         .clone().into()
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_Element_IsDisplayNone(element: RawGeckoElementBorrowed) -> bool
-{
+pub extern "C" fn Servo_Element_IsDisplayNone(element: RawGeckoElementBorrowed) -> bool {
     let element = GeckoElement(element);
     let data = element.borrow_data().expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
     data.styles.is_display_none()
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: RawGeckoElementBorrowed) -> bool {
+    let element = GeckoElement(element);
+    let data = element.borrow_data()
+                      .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
+    data.flags.contains(data::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetContentsStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let origin = match mode {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
         SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
     };
--- a/taskcluster/ci/artifact-build/kind.yml
+++ b/taskcluster/ci/artifact-build/kind.yml
@@ -4,17 +4,17 @@
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 jobs:
     linux64-artifact/opt:
         description: "Linux64 Opt Artifact Build"
         index:
             product: firefox
--- a/taskcluster/ci/build/kind.yml
+++ b/taskcluster/ci/build/kind.yml
@@ -6,17 +6,17 @@ loader: taskgraph.loader.transform:loade
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.build:transforms
    - taskgraph.transforms.build_attrs:transforms
    - taskgraph.transforms.build_lints:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 jobs-from:
     - android.yml
     - android-stuff.yml
     - linux.yml
     - macosx.yml
--- a/taskcluster/ci/hazard/kind.yml
+++ b/taskcluster/ci/hazard/kind.yml
@@ -4,17 +4,17 @@
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 job-defaults:
     treeherder:
         kind: build
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
--- a/taskcluster/ci/spidermonkey/kind.yml
+++ b/taskcluster/ci/spidermonkey/kind.yml
@@ -5,17 +5,17 @@
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.spidermonkey:transforms
    - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 job-defaults:
     treeherder:
         platform: linux64/opt
         kind: build
         tier: 1
--- a/taskcluster/ci/static-analysis/kind.yml
+++ b/taskcluster/ci/static-analysis/kind.yml
@@ -4,17 +4,17 @@
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 job-defaults:
     index:
         product: firefox
     treeherder:
         symbol: S
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -1846,17 +1846,17 @@ talos-tp5o-stylo-disabled:
 talos-tp6:
     description: "Talos Tp6"
     suite: talos
     try-name: tp6
     treeherder-symbol: tc-T(tp6)
     run-on-projects:
         by-test-platform:
             windows.*: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try', 'date']
-            macosx.*: ['mozilla-beta', 'mozilla-central', 'try']
+            macosx.*: ['mozilla-beta', 'autoland', 'try']
             default: []
     max-run-time: 3600
     mozharness:
         script: talos_script.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 macosx.*:
@@ -1874,17 +1874,17 @@ talos-tp6-stylo-disabled:
     description: "Talos Stylo disabled Tp6"
     suite: talos
     try-name: tp6-stylo-disabled
     treeherder-symbol: tc-Tsd(tp6)
     virtualization: hardware
     run-on-projects:
         by-test-platform:
             windows.*: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
-            macosx.*: ['mozilla-beta', 'mozilla-central', 'try']
+            macosx.*: ['mozilla-beta', 'autoland', 'try']
             default: []
     max-run-time: 3600
     mozharness:
         script: talos_script.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 macosx.*:
@@ -1900,17 +1900,17 @@ talos-tp6-stylo-threads:
     description: "Talos Stylo sequential Tp6"
     suite: talos
     try-name: tp6-stylo-threads
     treeherder-symbol: tc-Tss(tp6)
     virtualization: hardware
     run-on-projects:
         by-test-platform:
             windows.*: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
-            macosx.*: ['mozilla-beta', 'mozilla-central', 'try']
+            macosx.*: ['mozilla-beta', 'autoland', 'try']
             default: []
     max-run-time: 3600
     mozharness:
         script: talos_script.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 macosx.*:
--- a/taskcluster/ci/toolchain/kind.yml
+++ b/taskcluster/ci/toolchain/kind.yml
@@ -1,16 +1,16 @@
 # 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/.
 
 loader: taskgraph.loader.transform:loader
 
 transforms:
    - taskgraph.transforms.try_job:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 jobs-from:
    - linux.yml
    - macosx.yml
    - windows.yml
--- a/taskcluster/ci/valgrind/kind.yml
+++ b/taskcluster/ci/valgrind/kind.yml
@@ -4,17 +4,17 @@
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    - toolchain
 
 transforms:
    - taskgraph.transforms.build_attrs:transforms
-   - taskgraph.transforms.toolchain:transforms
+   - taskgraph.transforms.use_toolchains:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 jobs:
     linux64-valgrind/opt:
         description: "Linux64 Valgrind Opt"
         index:
             product: firefox
rename from taskcluster/taskgraph/transforms/toolchain.py
rename to taskcluster/taskgraph/transforms/use_toolchains.py
--- a/taskcluster/taskgraph/util/partials.py
+++ b/taskcluster/taskgraph/util/partials.py
@@ -17,16 +17,19 @@ PLATFORM_RENAMES = {
     'windows2012-64': 'win64',
     'osx-cross': 'macosx64',
 }
 
 BALROG_PLATFORM_MAP = {
     "linux": [
         "Linux_x86-gcc3"
     ],
+    "linux32": [
+        "Linux_x86-gcc3"
+    ],
     "linux64": [
         "Linux_x86_64-gcc3"
     ],
     "macosx64": [
         "Darwin_x86_64-gcc3-u-i386-x86_64",
         "Darwin_x86-gcc3-u-i386-x86_64",
         "Darwin_x86-gcc3",
         "Darwin_x86_64-gcc3"
--- a/taskcluster/taskgraph/util/verify.py
+++ b/taskcluster/taskgraph/util/verify.py
@@ -4,17 +4,19 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import re
 import os
 import sys
 
-base_path = os.path.join(os.getcwd(), "taskcluster/docs/")
+from .. import GECKO
+
+base_path = os.path.join(GECKO, 'taskcluster', 'docs')
 
 
 class VerificationSequence(object):
     """
     Container for a sequence of verifications over a TaskGraph. Each
     verification is represented as a callable taking (task, taskgraph,
     scratch_pad), called for each task in the taskgraph, and one more
     time with no task but with the taskgraph and the same scratch_pad
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 /* global frame */
 
 const {utils: Cu} = Components;
 
+const {WebElementEventTarget} = Cu.import("chrome://marionette/content/dom.js", {});
 Cu.import("chrome://marionette/content/element.js");
 const {
   NoSuchWindowError,
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/frame.js");
 
 this.EXPORTED_SYMBOLS = ["browser", "WindowState"];
@@ -132,16 +133,20 @@ browser.Context = class {
     } else if (this.tabBrowser &&
         this.driver.isReftestBrowser(this.tabBrowser)) {
       return this.tabBrowser;
     }
 
     return null;
   }
 
+  get messageManager() {
+    return this.contentBrowser.messageManager;
+  }
+
   /**
    * The current frame ID is managed per browser element on desktop in
    * case the ID needs to be refreshed. The currently selected window is
    * identified by a tab.
    */
   get curFrameId() {
     let rv = null;
     if (this.tab || this.driver.isReftestBrowser(this.contentBrowser)) {
@@ -326,16 +331,20 @@ browser.Context = class {
           // Firefox
           this.tabBrowser.selectedTab = this.tab;
 
         } else {
           throw new UnsupportedOperationError("switchToTab() not supported");
         }
       }
     }
+
+    // TODO(ato): Currently tied to curBrowser, but should be moved to
+    // WebElement when introduced by https://bugzil.la/1400256.
+    this.eventObserver = new WebElementEventTarget(this.messageManager);
   }
 
   /**
    * Registers a new frame, and sets its current frame id to this frame
    * if it is not already assigned, and if a) we already have a session
    * or b) we're starting a new session and it is the right start frame.
    *
    * @param {string} uid
new file mode 100644
--- /dev/null
+++ b/testing/marionette/dom.js
@@ -0,0 +1,203 @@
+/* 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/. */
+
+"use strict";
+
+const {utils: Cu} = Components;
+
+this.EXPORTED_SYMBOLS = [
+  "ContentEventObserverService",
+  "WebElementEventTarget",
+];
+
+/**
+ * The {@link EventTarget} for web elements can be used to observe DOM
+ * events in the content document.
+ *
+ * A caveat of the current implementation is that it is only possible
+ * to listen for top-level <code>window</code> global events.
+ *
+ * It needs to be backed by a {@link ContentEventObserverService} in a
+ * content frame script.
+ *
+ * Usage:
+ *
+ * <pre><code>
+ *     let observer = new WebElementEventTarget(messageManager);
+ *     await new Promise(resolve => {
+ *       observer.addEventListener("visibilitychange", resolve, {once: true});
+ *       chromeWindow.minimize();
+ *     });
+ * </code></pre>
+ */
+class WebElementEventTarget {
+  /**
+   * @param {function(): nsIMessageListenerManager} messageManagerFn
+   *     Message manager to the current browser.
+   */
+  constructor(messageManager) {
+    this.mm = messageManager;
+    this.listeners = {};
+    this.mm.addMessageListener("Marionette:DOM:OnEvent", this);
+  }
+
+  /**
+   * Register an event handler of a specific event type from the content
+   * frame.
+   *
+   * @param {string} type
+   *     Event type to listen for.
+   * @param {EventListener} listener
+   *     Object which receives a notification (a {@link BareEvent})
+   *     when an event of the specified type occurs.  This must be
+   *     an object implementing the {@link EventListener} interface,
+   *     or a JavaScript function.
+   * @param {boolean=} once
+   *     Indicates that the <var>listener</var> should be invoked at
+   *     most once after being added.  If true, the <var>listener</var>
+   *     would automatically be removed when invoked.
+   */
+  addEventListener(type, listener, {once = false} = {}) {
+    if (!(type in this.listeners)) {
+      this.listeners[type] = [];
+    }
+
+    if (!this.listeners[type].includes(listener)) {
+      listener.once = once;
+      this.listeners[type].push(listener);
+    }
+
+    this.mm.sendAsyncMessage("Marionette:DOM:AddEventListener", {type});
+  }
+
+  /**
+   * Removes an event listener.
+   *
+   * @param {string} type
+   *     Type of event to cease listening for.
+   * @param {EventListener} listener
+   *     Event handler to remove from the event target.
+   */
+  removeEventListener(type, listener) {
+    if (!(type in this.listeners)) {
+      return;
+    }
+
+    let stack = this.listeners[type];
+    for (let i = stack.length - 1; i >= 0; --i) {
+      if (stack[i] === listener) {
+        stack.splice(i, 1);
+        if (stack.length == 0) {
+          this.mm.sendAsyncMessage("Marionette:DOM:RemoveEventListener", {type});
+        }
+        return;
+      }
+    }
+  }
+
+  dispatchEvent(event) {
+    if (!(event.type in this.listeners)) {
+      return;
+    }
+
+    event.target = this;
+
+    let stack = this.listeners[event.type].slice(0);
+    stack.forEach(listener => {
+      listener.call(this, event);
+
+      if (listener.once) {
+        this.removeEventListener(event.type, listener);
+      }
+    });
+  }
+
+  receiveMessage({target, name, data, objects}) {
+    if (name != "Marionette:DOM:OnEvent") {
+      return;
+    }
+
+    let ev = {
+      type: data.type,
+      target: objects.target,
+    };
+    this.dispatchEvent(ev);
+  }
+}
+this.WebElementEventTarget = WebElementEventTarget;
+
+/**
+ * Provides the frame script backend for the
+ * {@link WebElementEventTarget}.
+ *
+ * This service receives requests for new DOM events to listen for and
+ * to cease listening for, and despatches IPC messages to the browser
+ * when they fire.
+ */
+class ContentEventObserverService {
+  /**
+   * @param {WindowProxy} windowGlobal
+   *     Window.
+   * @param {nsIMessageSender.sendAsyncMessage} sendAsyncMessage
+   *     Function for sending an async message to the parent browser.
+   */
+  constructor(windowGlobal, sendAsyncMessage) {
+    this.window = windowGlobal;
+    this.sendAsyncMessage = sendAsyncMessage;
+    this.events = new Set();
+  }
+
+  /**
+   * Observe a new DOM event.
+   *
+   * When the DOM event of <var>type</var> fires, a message is passed
+   * to the parent browser's event observer.
+   *
+   * If event type is already being observed, only a single message
+   * is sent.  E.g. multiple registration for events will only ever emit
+   * a maximum of one message.
+   *
+   * @param {string} type
+   *     DOM event to listen for.
+   */
+  add(type) {
+    if (this.events.has(type)) {
+      return;
+    }
+    this.window.addEventListener(type, this);
+    this.events.add(type);
+  }
+
+  /**
+   * Ceases observing a DOM event.
+   *
+   * @param {string} type
+   *     DOM event to stop listening for.
+   */
+  remove(type) {
+    if (!this.events.has(type)) {
+      return;
+    }
+    this.window.removeEventListener(type, this);
+    this.events.delete(type);
+  }
+
+  /** Ceases observing all previously registered DOM events. */
+  clear() {
+    for (let ev of this) {
+      this.remove(ev);
+    }
+  }
+
+  * [Symbol.iterator]() {
+    for (let ev of this.events) {
+      yield ev;
+    }
+  }
+
+  handleEvent({type, target}) {
+    this.sendAsyncMessage("Marionette:DOM:OnEvent", {type}, {target});
+  }
+}
+this.ContentEventObserverService = ContentEventObserverService;
--- a/testing/marionette/jar.mn
+++ b/testing/marionette/jar.mn
@@ -30,16 +30,17 @@ marionette.jar:
   content/assert.js (assert.js)
   content/addon.js (addon.js)
   content/session.js (session.js)
   content/transport.js (transport.js)
   content/packets.js (packets.js)
   content/stream-utils.js (stream-utils.js)
   content/reftest.js (reftest.js)
   content/reftest.xul (reftest.xul)
+  content/dom.js (dom.js)
 #ifdef ENABLE_TESTS
   content/test.xul (chrome/test.xul)
   content/test2.xul (chrome/test2.xul)
   content/test_dialog.dtd (chrome/test_dialog.dtd)
   content/test_dialog.properties (chrome/test_dialog.properties)
   content/test_dialog.xul (chrome/test_dialog.xul)
   content/test_nested_iframe.xul (chrome/test_nested_iframe.xul)
   content/test_anonymous_content.xul (chrome/test_anonymous_content.xul)
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -35,16 +35,17 @@ const {
   InvalidSelectorError,
   NoSuchElementError,
   NoSuchFrameError,
   TimeoutError,
   UnknownError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/evaluate.js");
 Cu.import("chrome://marionette/content/event.js");
+const {ContentEventObserverService} = Cu.import("chrome://marionette/content/dom.js", {});
 Cu.import("chrome://marionette/content/interaction.js");
 Cu.import("chrome://marionette/content/legacyaction.js");
 Cu.import("chrome://marionette/content/navigate.js");
 Cu.import("chrome://marionette/content/proxy.js");
 Cu.import("chrome://marionette/content/session.js");
 
 Cu.importGlobalProperties(["URL"]);
 
@@ -110,16 +111,19 @@ const modalHandler = function() {
   }
   curContainer = {frame: content, shadowRoot: null};
 };
 
 // sandbox storage and name of the current sandbox
 const sandboxes = new Sandboxes(() => curContainer.frame);
 let sandboxName = "default";
 
+const eventObservers = new ContentEventObserverService(
+    content, sendAsyncMessage.bind(this));
+
 /**
  * The load listener singleton helps to keep track of active page load
  * activities, and can be used by any command which might cause a navigation
  * to happen. In the specific case of a reload of the frame script it allows
  * to continue observing the current page load.
  */
 const loadListener = {
   commandID: null,
@@ -610,16 +614,18 @@ function startListeners() {
   addMessageListenerId("Marionette:clearElement", clearElementFn);
   addMessageListenerId("Marionette:switchToFrame", switchToFrame);
   addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
   addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
   addMessageListenerId("Marionette:deleteSession", deleteSession);
   addMessageListenerId("Marionette:sleepSession", sleepSession);
   addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
   addMessageListenerId("Marionette:reftestWait", reftestWaitFn);
+  addMessageListener("Marionette:DOM:AddEventListener", domAddEventListener);
+  addMessageListener("Marionette:DOM:RemoveEventListener", domRemoveEventListener);
 }
 
 /**
  * Called when we start a new session. It registers the
  * current environment, and resets all values
  */
 function newSession(msg) {
   capabilities = session.Capabilities.fromJSON(msg.json);
@@ -1901,10 +1907,18 @@ async function reftestWait(url, remote) 
     flushRendering();
   }
 
   if (remote) {
     windowUtils.updateLayerTree();
   }
 }
 
+function domAddEventListener(msg) {
+  eventObservers.add(msg.json.type);
+}
+
+function domRemoveEventListener(msg) {
+  eventObservers.remove(msg.json.type);
+}
+
 // Call register self when we get loaded
 registerSelf();
new file mode 100644
--- /dev/null
+++ b/testing/marionette/test_dom.js
@@ -0,0 +1,278 @@
+const {utils: Cu} = Components;
+
+const {
+  ContentEventObserverService,
+  WebElementEventTarget,
+} = Cu.import("chrome://marionette/content/dom.js", {});
+
+class MessageSender {
+  constructor() {
+    this.listeners = {};
+    this.sent = [];
+  }
+
+  addMessageListener(name, listener) {
+    this.listeners[name] = listener;
+  }
+
+  sendAsyncMessage(name, data, objects) {
+    this.sent.push({name, data, objects});
+  }
+}
+
+class Window {
+  constructor() {
+    this.events = [];
+  }
+
+  addEventListener(type, listener) {
+    this.events.push(type);
+  }
+
+  removeEventListener(type, listener) {
+    for (let i = 0; i < this.events.length; ++i) {
+      if (this.events[i] === type) {
+        this.events.splice(i, 1);
+        return;
+      }
+    }
+  }
+}
+
+add_test(function test_WebElementEventTarget_addEventListener_init() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+  equal(Object.keys(eventTarget.listeners).length, 0);
+  equal(Object.keys(ipc.listeners).length, 1);
+
+  run_next_test();
+});
+
+add_test(function test_addEventListener() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  let listener = () => {};
+  eventTarget.addEventListener("click", listener);
+
+  // click listener was appended
+  equal(Object.keys(eventTarget.listeners).length, 1);
+  ok("click" in eventTarget.listeners);
+  equal(eventTarget.listeners["click"].length, 1);
+  equal(eventTarget.listeners["click"][0], listener);
+
+  // should have sent a registration message
+  deepEqual(
+      ipc.sent[0], {
+        name: "Marionette:DOM:AddEventListener",
+        data: {type: "click"},
+        objects: undefined,
+      });
+
+  run_next_test();
+});
+
+add_test(function test_addEventListener_sameReference() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  let listener = () => {};
+  eventTarget.addEventListener("click", listener);
+  eventTarget.addEventListener("click", listener);
+  equal(eventTarget.listeners["click"].length, 1);
+
+  run_next_test();
+});
+
+add_test(function test_WebElementEventTarget_addEventListener_once() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  eventTarget.addEventListener("click", () => {}, {once: true});
+  equal(eventTarget.listeners["click"][0].once, true);
+
+  eventTarget.dispatchEvent({type: "click"});
+  equal(eventTarget.listeners["click"].length, 0);
+  deepEqual(
+      ipc.sent[1], {
+        name: "Marionette:DOM:RemoveEventListener",
+        data: {type: "click"},
+        objects: undefined,
+      });
+
+  run_next_test();
+});
+
+add_test(function test_WebElementEventTarget_removeEventListener() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  equal(Object.keys(eventTarget.listeners).length, 0);
+  eventTarget.removeEventListener("click", () => {});
+  equal(Object.keys(eventTarget.listeners).length, 0);
+
+  let firstListener = () => {};
+  eventTarget.addEventListener("click", firstListener);
+  equal(eventTarget.listeners["click"].length, 1);
+  ok(eventTarget.listeners["click"][0] === firstListener);
+
+  let secondListener = () => {};
+  eventTarget.addEventListener("click", secondListener);
+  equal(eventTarget.listeners["click"].length, 2);
+  ok(eventTarget.listeners["click"][1] === secondListener);
+
+  ok(eventTarget.listeners["click"][0] !== eventTarget.listeners["click"][1]);
+
+  eventTarget.removeEventListener("click", secondListener);
+  equal(eventTarget.listeners["click"].length, 1);
+  ok(eventTarget.listeners["click"][0] === firstListener);
+
+  // event should not have been unregistered
+  // because there still exists another click event
+  equal(ipc.sent[ipc.sent.length - 1].name, "Marionette:DOM:AddEventListener");
+
+  eventTarget.removeEventListener("click", firstListener);
+  equal(eventTarget.listeners["click"].length, 0);
+  deepEqual(
+      ipc.sent[ipc.sent.length - 1],
+      {
+        name: "Marionette:DOM:RemoveEventListener",
+        data: {type: "click"},
+        objects: undefined,
+      });
+
+  run_next_test();
+});
+
+add_test(function test_WebElementEventTarget_dispatchEvent() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  let listenerCalled = false;
+  let listener = () => listenerCalled = true;
+  eventTarget.addEventListener("click", listener);
+  eventTarget.dispatchEvent({type: "click"});
+  ok(listenerCalled);
+
+  run_next_test();
+});
+
+add_test(function test_WebElementEventTarget_dispatchEvent_multipleListeners() {
+  let ipc = new MessageSender();
+  let eventTarget = new WebElementEventTarget(ipc);
+
+  let clicksA = 0;
+  let clicksB = 0;
+  let listenerA = () => ++clicksA;
+  let listenerB = () => ++clicksB;
+
+  // the same listener should only be added, and consequently fire, once
+  eventTarget.addEventListener("click", listenerA);
+  eventTarget.addEventListener("click", listenerA);
+  eventTarget.addEventListener("click", listenerB);
+  eventTarget.dispatchEvent({type: "click"});
+  equal(clicksA, 1);
+  equal(clicksB, 1);
+
+  run_next_test();
+});
+
+add_test(function test_ContentEventObserverService_add() {
+  let ipc = new MessageSender();
+  let win = new Window();
+  let obs = new ContentEventObserverService(
+      win, ipc.sendAsyncMessage.bind(ipc));
+
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  obs.add("foo");
+  equal(obs.events.size, 1);
+  equal(win.events.length, 1);
+  equal(obs.events.values().next().value, "foo");
+  equal(win.events[0], "foo");
+
+  obs.add("foo");
+  equal(obs.events.size, 1);
+  equal(win.events.length, 1);
+
+  run_next_test();
+});
+
+add_test(function test_ContentEventObserverService_remove() {
+  let ipc = new MessageSender();
+  let win = new Window();
+  let obs = new ContentEventObserverService(
+      win, ipc.sendAsyncMessage.bind(ipc));
+
+  obs.remove("foo");
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  obs.add("bar");
+  equal(obs.events.size, 1);
+  equal(win.events.length, 1);
+
+  obs.remove("bar");
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  obs.add("baz");
+  obs.add("baz");
+  equal(obs.events.size, 1);
+  equal(win.events.length, 1);
+
+  obs.add("bah");
+  equal(obs.events.size, 2);
+  equal(win.events.length, 2);
+
+  obs.remove("baz");
+  equal(obs.events.size, 1);
+  equal(win.events.length, 1);
+
+  obs.remove("bah");
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  run_next_test();
+});
+
+add_test(function test_ContentEventObserverService_clear() {
+  let ipc = new MessageSender();
+  let win = new Window();
+  let obs = new ContentEventObserverService(
+      win, ipc.sendAsyncMessage.bind(ipc));
+
+  obs.clear();
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  obs.add("foo");
+  obs.add("foo");
+  obs.add("bar");
+  equal(obs.events.size, 2);
+  equal(win.events.length, 2);
+
+  obs.clear();
+  equal(obs.events.size, 0);
+  equal(win.events.length, 0);
+
+  run_next_test();
+});
+
+add_test(function test_ContentEventObserverService_handleEvent() {
+  let ipc = new MessageSender();
+  let win = new Window();
+  let obs = new ContentEventObserverService(
+      win, ipc.sendAsyncMessage.bind(ipc));
+
+  obs.handleEvent({type: "click", target: win});
+  deepEqual(
+      ipc.sent[0], {
+        name: "Marionette:DOM:OnEvent",
+        data: {type: "click"},
+        objects: {"target": win},
+      });
+
+  run_next_test();
+});
--- a/testing/marionette/unit.ini
+++ b/testing/marionette/unit.ini
@@ -5,14 +5,15 @@
 # xpcshell unit tests for Marionette
 
 [DEFAULT]
 skip-if = appname == "thunderbird"
 
 [test_action.js]
 [test_assert.js]
 [test_cookie.js]
+[test_dom.js]
 [test_element.js]
 [test_error.js]
 [test_message.js]
 [test_navigate.js]
 [test_session.js]
 [test_wait.js]
--- a/testing/mozharness/scripts/web_platform_tests.py
+++ b/testing/mozharness/scripts/web_platform_tests.py
@@ -181,16 +181,18 @@ class WebPlatformTest(TestingMixin, Merc
         # Make sure that the logging directory exists
         if self.mkdir_p(dirs["abs_blob_upload_dir"]) == -1:
             self.fatal("Could not create blobber upload directory")
             # Exit
 
         cmd += ["--log-raw=-",
                 "--log-raw=%s" % os.path.join(dirs["abs_blob_upload_dir"],
                                               "wpt_raw.log"),
+                "--log-wptreport=%s" % os.path.join(dirs["abs_blob_upload_dir"],
+                                                    "wptreport.json"),
                 "--log-errorsummary=%s" % os.path.join(dirs["abs_blob_upload_dir"],
                                                        "wpt_errorsummary.log"),
                 "--binary=%s" % self.binary_path,
                 "--symbols-path=%s" % self.query_symbols_url(),
                 "--stackwalk-binary=%s" % self.query_minidump_stackwalk(),
                 "--stackfix-dir=%s" % os.path.join(dirs["abs_test_install_dir"], "bin"),
                 "--run-by-dir=3"]
 
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -65,17 +65,17 @@
         "svgr-e10s": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "tsvg_static"]
         },
         "svgr-stylo-disabled-e10s": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "tsvg_static"],
             "talos_options": ["--disable-stylo"]
         },
         "perf-reftest-e10s": {
-            "tests": ["bloom_basic"]
+            "tests": ["perf_reftest"]
         },
         "perf-reftest-stylo-disabled-e10s": {
             "tests": ["bloom_basic"],
             "talos_options": ["--disable-stylo"]
         },
         "perf-reftest-singletons-e10s": {
             "tests": ["perf_reftest_singletons"]
         },
--- a/testing/talos/talos/output.py
+++ b/testing/talos/talos/output.py
@@ -87,34 +87,38 @@ class Output(object):
                     # override the list of page results for each run
                     result.results = results
 
                 for result in tresults:
                     filtered_results = \
                         result.values(suite['name'],
                                       test.test_config['filters'])
                     vals.extend([[i['value'], j] for i, j in filtered_results])
+                    subtest_index = 0
                     for val, page in filtered_results:
                         if page == 'NULL':
                             # no real subtests
                             page = test.name()
                         subtest = {
                             'name': page,
                             'value': val['filtered'],
                             'replicates': replicates[page],
                         }
                         # if results are from a comparison test i.e. perf-reftest, it will also
                         # contain replicates for 'base' and 'reference'; we wish to keep those
                         # to reference; actual results were calculated as the difference of those
-                        base_runs = result.results[0].get('base_runs', None)
-                        ref_runs = result.results[0].get('ref_runs', None)
+                        base_runs = result.results[subtest_index].get('base_runs', None)
+                        ref_runs = result.results[subtest_index].get('ref_runs', None)
                         if base_runs and ref_runs:
                             subtest['base_replicates'] = base_runs
                             subtest['ref_replicates'] = ref_runs
+
                         subtests.append(subtest)
+                        subtest_index += 1
+
                         if test.test_config.get('lower_is_better') is not None:
                             subtest['lowerIsBetter'] = \
                                 test.test_config['lower_is_better']
                         if test.test_config.get('alert_threshold') is not None:
                             subtest['alertThreshold'] = \
                                 test.test_config['alert_threshold']
                         if test.test_config.get('unit'):
                             subtest['unit'] = test.test_config['unit']
--- a/testing/talos/talos/pageloader/chrome/pageloader.js
+++ b/testing/talos/talos/pageloader/chrome/pageloader.js
@@ -46,16 +46,17 @@ var useMozAfterPaint = false;
 var useFNBPaint = false;
 var gPaintWindow = window;
 var gPaintListener = false;
 var loadNoCache = false;
 var scrollTest = false;
 var gDisableE10S = false;
 var gUseE10S = false;
 var profilingInfo = false;
+var baseVsRef = false;
 
 var isIdleCallbackPending = false;
 
 // when TEST_DOES_OWN_TIMING, we need to store the time from the page as MozAfterPaint can be slower than pageload
 var gTime = -1;
 var gStartTime = -1;
 var gReference = -1;
 
@@ -197,17 +198,16 @@ function plInit() {
     if (startIndex > endIndex) {
       dumpLine("tp: error: startIndex >= endIndex");
       plStop(true);
     }
 
     pages = pages.slice(startIndex, endIndex + 1);
     pageUrls = pages.map(function(p) { return p.url.spec.toString(); });
     report = new Report();
-
     if (doRenderTest)
       renderReport = new Report();
 
     pageIndex = 0;
     if (profilingInfo) {
       TalosParentProfiler.beginTest(getCurrentPageShortName());
     }
 
@@ -395,19 +395,17 @@ function plLoadPage() {
     mm.removeMessageListener("PageLoader:LoadEvent", ContentListener);
     mm.removeMessageListener("PageLoader:RecordTime", ContentListener);
     mm.removeMessageListener("PageLoader:IdleCallbackSet", ContentListener);
     mm.removeMessageListener("PageLoader:IdleCallbackReceived", ContentListener);
     if (useFNBPaint) {
       mm.removeMessageListener("PageLoader:FNBPaintError", ContentListener);
     }
   };
-
   failTimeout.register(loadFail, timeout);
-
   // record which page we are about to open
   TalosParentProfiler.mark("Opening " + pages[pageIndex].url.pathQueryRef);
 
   if (reportRSS) {
     collectMemory(startAndLoadURI, pageName);
   } else {
     startAndLoadURI(pageName);
   }
@@ -560,17 +558,25 @@ function plRecordTime(time) {
   var i = pageIndex
   if (i < pages.length - 1) {
     i++;
   } else {
     i = 0;
   }
   var nextName = pages[i].url.spec;
   if (!recordedName) {
-    recordedName = pageUrls[pageIndex];
+    // when doing base vs ref type of test, add pre 'base' or 'ref' to reported page name;
+    // this is necessary so that if multiple subtests use same reference page, results for
+    // each ref page run will be kept separate for each base vs ref run, and not grouped
+    // into just one set of results values for everytime that reference page was loaded
+    if (baseVsRef) {
+      recordedName = pages[pageIndex].pre + pageUrls[pageIndex];
+    } else {
+      recordedName = pageUrls[pageIndex];
+    }
   }
   if (typeof(time) == "string") {
     var times = time.split(",");
     var names = recordedName.split(",");
     for (var t = 0; t < times.length; t++) {
       if (names.length == 1) {
         report.recordTime(names, times[t]);
       } else {
@@ -888,20 +894,21 @@ function plLoadURLsFromURI(manifestUri) 
     fstream.init(uriFile.file, -1, 0, 0);
   } catch (ex) {
       dumpLine("tp: the file %s doesn't exist" % uriFile.file);
       return null;
   }
 
   var lstream = fstream.QueryInterface(Ci.nsILineInputStream);
 
-  var d = [];
+  var url_array = [];
 
   var lineNo = 0;
   var line = {value: null};
+  var baseVsRefIndex = 0;
   var more;
   do {
     lineNo++;
     more = lstream.readLine(line);
     var s = line.value;
 
     // strip comments (only leading ones)
     s = s.replace(/^#.*/, "");
@@ -909,16 +916,17 @@ function plLoadURLsFromURI(manifestUri) 
     // strip leading and trailing whitespace
     s = s.replace(/^\s*/, "").replace(/\s*$/, "");
 
     if (!s)
       continue;
 
     var flags = 0;
     var urlspec = s;
+    baseVsRefIndex += 1;
 
     // split on whitespace, and figure out if we have any flags
     var items = s.split(/\s+/);
     if (items[0] == "include") {
       if (items.length != 2) {
         dumpLine("tp: Error on line " + lineNo + " in " + manifestUri.spec + ": include must be followed by the manifest to include!");
         return null;
       }
@@ -927,17 +935,17 @@ function plLoadURLsFromURI(manifestUri) 
       if (subManifest == null) {
         dumpLine("tp: invalid URI on line " + manifestUri.spec + ":" + lineNo + " : '" + line.value + "'");
         return null;
       }
 
       var subItems = plLoadURLsFromURI(subManifest);
       if (subItems == null)
         return null;
-      d = d.concat(subItems);
+      url_array = url_array.concat(subItems);
     } else {
       // For scrollTest flag, we accept "normal" pages but treat them as TEST_DOES_OWN_TIMING
       // together with EXECUTE_SCROLL_TEST which makes us run the scroll test on load.
       // We do this by artificially "injecting" the TEST_DOES_OWN_TIMING flag ("%") to the item
       // and then let the default flow for this flag run without further modifications
       // (other than calling the scroll test once the page is loaded).
       // Note that if we have the scrollTest flag but the item already has "%", then we do
       // nothing (the scroll test will not execute, and the page will report with its
@@ -947,32 +955,68 @@ function plLoadURLsFromURI(manifestUri) 
         flags |= EXECUTE_SCROLL_TEST;
       }
 
       if (items.length == 2) {
         if (items[0].indexOf("%") != -1)
           flags |= TEST_DOES_OWN_TIMING;
 
         urlspec = items[1];
+      } else if (items.length == 3) {
+        // base vs ref type of talos test
+        // expect each manifest line to be in the format of:
+        // & http://localhost/tests/perf-reftest/base-page.html, http://localhost/tests/perf-reftest/reference-page.html
+        // test will run with the base page, then with the reference page; and ultimately the actual test results will
+        // be the comparison values of those two pages; more than one line will result in base vs ref subtests
+        if (items[0].indexOf("&") != -1) {
+          baseVsRef = true;
+          flags |= TEST_DOES_OWN_TIMING;
+          // for the base, must remove the comma on the end of the actual url
+          var urlspecBase = items[1].slice(0, -1);
+          var urlspecRef = items[2];
+        } else {
+          dumpLine("tp: Error on line " + lineNo + " in " + manifestUri.spec + ": unknown manifest format!");
+          return null;
+        }
       } else if (items.length != 1) {
         dumpLine("tp: Error on line " + lineNo + " in " + manifestUri.spec + ": whitespace must be %-escaped!");
         return null;
       }
 
-      var url = gIOS.newURI(urlspec, null, manifestUri);
+      var url;
+
+      if (!baseVsRef) {
+        url = gIOS.newURI(urlspec, null, manifestUri);
+
+        if (pageFilterRegexp && !pageFilterRegexp.test(url.spec))
+          continue;
 
-      if (pageFilterRegexp && !pageFilterRegexp.test(url.spec))
-        continue;
+        url_array.push({ url, flags });
+      } else {
+        // base vs ref type of talos test
+        // we add a 'pre' prefix here indicating that this particular page is a base page or a reference
+        // page; later on this 'pre' is used when recording the actual time value/result; because in
+        // the results we use the url as the results key; but we might use the same test page as a reference
+        // page in the same test suite, so we need to add a prefix so this results key is always unique
+        url = gIOS.newURI(urlspecBase, null, manifestUri);
+        if (pageFilterRegexp && !pageFilterRegexp.test(url.spec))
+          continue;
+        var pre = "base_page_" + baseVsRefIndex + "_";
+        url_array.push({ url, flags, pre });
 
-      d.push({   url,
-               flags });
+        url = gIOS.newURI(urlspecRef, null, manifestUri);
+        if (pageFilterRegexp && !pageFilterRegexp.test(url.spec))
+          continue;
+        pre = "ref_page_" + baseVsRefIndex + "_";
+        url_array.push({ url, flags, pre });
+      }
     }
   } while (more);
 
-  return d;
+  return url_array;
 }
 
 function dumpLine(str) {
   if (MozillaFileLogger && MozillaFileLogger._foStream)
     MozillaFileLogger.log(str + "\n");
   dump(str);
   dump("\n");
 }
--- a/testing/talos/talos/pageloader/install.rdf
+++ b/testing/talos/talos/pageloader/install.rdf
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>pageloader@mozilla.org</em:id>
-    <em:version>1.0.27</em:version>
+    <em:version>1.0.29</em:version>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
index 2c2526e3c9c8b59b88b649908a88a39ef7584b2a..41d7a39d83fc428b9c3a3e018159cd0345a34430
GIT binary patch
literal 31836
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
--- a/testing/talos/talos/results.py
+++ b/testing/talos/talos/results.py
@@ -248,17 +248,22 @@ class PageloaderResults(Results):
             self.results.append(result)
 
     def format_pagename(self, page):
         """
         fix up the page for reporting
         """
         page = page.rstrip('/')
         if '/' in page:
-            page = page.split('/')[0]
+            if 'base_page' in page or 'ref_page' in page:
+                # for base vs ref type test, the page name is different format, i.e.
+                # base_page_1_http://localhost:53309/tests/perf-reftest/bloom-basic.html
+                page = page.split('/')[-1]
+            else:
+                page = page.split('/')[0]
         return page
 
 
 class BrowserLogResults(object):
     """parse the results from the browser log output"""
 
     # tokens for the report types
     report_tokens = [
--- a/testing/talos/talos/run_tests.py
+++ b/testing/talos/talos/run_tests.py
@@ -336,39 +336,55 @@ def make_comparison_result(base_and_refe
     results object with the comparison results, that will look like traditional single test results
     like this:
 
     PERFHERDER_DATA: {"framework": {"name": "talos"}, "suites": [{"lowerIsBetter": true,
     "subtests": [{"name": "", "lowerIsBetter": true, "alertThreshold": 5.0, "replicates":
     [16.705, ...], "value": 16.705, "unit": "ms"}], "extraOptions": ["e10s"], "name":
     "bloom_basic", "alertThreshold": 5.0}]}
     '''
-    # separate the 'base' and 'reference' result run values
-    base_result_runs = base_and_reference_results.results[0].results[0]['runs']
-    ref_result_runs = base_and_reference_results.results[0].results[1]['runs']
-
     # create a new results object for the comparison result; keep replicates from both pages
     comparison_result = copy.deepcopy(base_and_reference_results)
 
     # remove original results from our copy as they will be replaced by one comparison result
     comparison_result.results[0].results = []
+    comp_results = comparison_result.results[0].results
 
-    # populate our new comparison result with 'base' and 'ref' replicates
-    comparison_result.results[0].results.append({'index': 0,
-                                                 'runs': [],
-                                                 'page': '',
-                                                 'base_runs': base_result_runs,
-                                                 'ref_runs': ref_result_runs})
+    # zero-based count of how many base vs reftest sets we have
+    subtest_index = 0
+
+    # each set of two results is actually a base test followed by the
+    # reference test; we want to go through each set of base vs reference
+    for x in range(0, len(base_and_reference_results.results[0].results), 2):
+
+        # separate the 'base' and 'reference' result run values
+        results = base_and_reference_results.results[0].results
+        base_result_runs = results[x]['runs']
+        ref_result_runs = results[x + 1]['runs']
+
+        # the test/subtest result is the difference between the base vs reference test page
+        # values; for this result use the base test page name for the subtest/test name
+        sub_test_name = base_and_reference_results.results[0].results[x]['page']
 
-    # now step thru each result, compare 'base' vs 'ref', and store the difference in 'runs'
-    _index = 0
-    for next_ref in comparison_result.results[0].results[0]['ref_runs']:
-        diff = abs(next_ref - comparison_result.results[0].results[0]['base_runs'][_index])
-        comparison_result.results[0].results[0]['runs'].append(round(diff, 3))
-        _index += 1
+        # populate our new comparison result with 'base' and 'ref' replicates
+        comp_results.append({'index': 0,
+                             'runs': [],
+                             'page': sub_test_name,
+                             'base_runs': base_result_runs,
+                             'ref_runs': ref_result_runs})
+
+        # now step thru each result, compare 'base' vs 'ref', and store the difference in 'runs'
+        _index = 0
+        for next_ref in comp_results[subtest_index]['ref_runs']:
+            diff = abs(next_ref - comp_results[subtest_index]['base_runs'][_index])
+            comp_results[subtest_index]['runs'].append(round(diff, 3))
+            _index += 1
+
+        # increment our base vs reference subtest index
+        subtest_index += 1
 
     return comparison_result
 
 
 def convert_to_separate_test_results(multi_value_result, test_event_map):
     ''' Receive a test result that actually contains multiple values in a single iteration, and
     parse it out in order to 'fake' three seprate test results.
 
--- a/testing/talos/talos/test.py
+++ b/testing/talos/talos/test.py
@@ -407,18 +407,19 @@ class cart(PageloaderTest):
 class damp(PageloaderTest):
     """
     Devtools At Maximum Performance
     Tests the speed of DevTools toolbox open, close, and page reload
     for each tool, across a very simple and very complicated page.
     """
     tpmanifest = '${talos}/tests/devtools/damp.manifest'
     extensions = '${talos}/tests/devtools/addon/devtools-signed.xpi'
+    cycles = 5
     tpcycles = 1
-    tppagecycles = 25
+    tppagecycles = 5
     tploadnocache = True
     tpmozafterpaint = False
     gecko_profile_interval = 10
     gecko_profile_entries = 1000000
     win_counters = w7_counters = linux_counters = mac_counters = None
     filters = filter.ignore_first.prepare(1) + filter.median.prepare()
     preferences = {'devtools.memory.enabled': True,
                    'addon.test.damp.webserver': '${webserver}'}
@@ -801,24 +802,24 @@ class a11yr(PageloaderTest):
     tpmozafterpaint = True
     tpchrome = False
     preferences = {'dom.send_after_paint_to_content': False}
     unit = 'ms'
     alert_threshold = 5.0
 
 
 @register_test()
-class bloom_basic(PageloaderTest):
+class perf_reftest(PageloaderTest):
     """
-    Stylo bloom_basic: runs bloom_basic and bloom_basic_ref and reports difference
+    Style perf-reftest a set of tests where the result is the difference of base vs ref pages
     """
     base_vs_ref = True  # compare the two test pages with eachother and report comparison
-    tpmanifest = '${talos}/tests/perf-reftest/bloom_basic.manifest'
+    tpmanifest = '${talos}/tests/perf-reftest/perf_reftest.manifest'
     tpcycles = 1
-    tppagecycles = 25
+    tppagecycles = 10
     gecko_profile_interval = 1
     gecko_profile_entries = 2000000
     filters = filter.ignore_first.prepare(5) + filter.median.prepare()
     unit = 'ms'
     lower_is_better = True
     alert_threshold = 5.0
 
 
--- a/testing/talos/talos/tests/devtools/addon/content/damp.js
+++ b/testing/talos/talos/tests/devtools/addon/content/damp.js
@@ -1,16 +1,32 @@
-Components.utils.import("resource://devtools/client/framework/gDevTools.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
+const { Services } = Components.utils.import("resource://gre/modules/Services.jsm", {});
+const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 
-const { devtools } =
-  Components.utils.import("resource://devtools/shared/Loader.jsm", {});
-const ThreadSafeChromeUtils = devtools.require("ThreadSafeChromeUtils");
-const { EVENTS } = devtools.require("devtools/client/netmonitor/src/constants");
-const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+XPCOMUtils.defineLazyGetter(this, "require", function() {
+  let { require } =
+    Components.utils.import("resource://devtools/shared/Loader.jsm", {});
+  return require;
+});
+XPCOMUtils.defineLazyGetter(this, "gDevTools", function() {
+  let { gDevTools } = require("devtools/client/framework/devtools");
+  return gDevTools;
+});
+XPCOMUtils.defineLazyGetter(this, "EVENTS", function() {
+  let { EVENTS } = require("devtools/client/netmonitor/src/constants");
+  return EVENTS;
+});
+XPCOMUtils.defineLazyGetter(this, "TargetFactory", function() {
+  let { TargetFactory } = require("devtools/client/framework/target");
+  return TargetFactory;
+});
+XPCOMUtils.defineLazyGetter(this, "ThreadSafeChromeUtils", function() {
+  return require("ThreadSafeChromeUtils");
+});
 
 const webserver = Services.prefs.getCharPref("addon.test.damp.webserver");
 
 const SIMPLE_URL = webserver + "/tests/devtools/addon/content/pages/simple.html";
 const COMPLICATED_URL = webserver + "/tests/tp5n/bild.de/www.bild.de/index.html";
 
 function getMostRecentBrowserWindow() {
   return Services.wm.getMostRecentWindow("navigator:browser");
@@ -60,44 +76,44 @@ Damp.prototype = {
         });
       }, {capture: true, once: true});
       browser.reload();
     });
   },
 
   openToolbox(tool = "webconsole") {
     let tab = getActiveTab(getMostRecentBrowserWindow());
-    let target = devtools.TargetFactory.forTab(tab);
+    let target = TargetFactory.forTab(tab);
     let startRecordTimestamp = performance.now();
     let showPromise = gDevTools.showToolbox(target, tool);
 
     return showPromise.then(toolbox => {
       let stopRecordTimestamp = performance.now();
       return {
         toolbox,
         time: stopRecordTimestamp - startRecordTimestamp
       };
     });
   },
 
   closeToolbox: Task.async(function* () {
     let tab = getActiveTab(getMostRecentBrowserWindow());
-    let target = devtools.TargetFactory.forTab(tab);
+    let target = TargetFactory.forTab(tab);
     yield target.client.waitForRequestsToSettle();
     let startRecordTimestamp = performance.now();
     yield gDevTools.closeToolbox(target);
     let stopRecordTimestamp = performance.now();
     return {
       time: stopRecordTimestamp - startRecordTimestamp
     };
   }),
 
   saveHeapSnapshot(label) {
     let tab = getActiveTab(getMostRecentBrowserWindow());
-    let target = devtools.TargetFactory.forTab(tab);
+    let target = TargetFactory.forTab(tab);
     let toolbox = gDevTools.getToolbox(target);
     let panel = toolbox.getCurrentPanel();
     let memoryFront = panel.panelWin.gFront;
 
     let start = performance.now();
     return memoryFront.saveHeapSnapshot().then(filePath => {
       this._heapSnapshotFilePath = filePath;
       let end = performance.now();
@@ -258,93 +274,99 @@ Damp.prototype = {
     this._results.push({
       name: label + ".takeCensus",
       value: end - start
     });
 
     return Promise.resolve();
   },
 
-  _getToolLoadingTests(url, label) {
+  async openToolboxAndLog(name, tool) {
+    let {time, toolbox} = await this.openToolbox(tool);
+    this._results.push({name: name + ".open.DAMP", value: time });
+    return toolbox;
+  },
 
-    let openToolboxAndLog = Task.async(function* (name, tool) {
-      let {time, toolbox} = yield this.openToolbox(tool);
-      this._results.push({name: name + ".open.DAMP", value: time });
-      return toolbox;
-    }.bind(this));
+  async closeToolboxAndLog(name) {
+    let {time} = await this.closeToolbox();
+    this._results.push({name: name + ".close.DAMP", value: time });
+  },
 
-    let closeToolboxAndLog = Task.async(function* (name) {
-      let {time} = yield this.closeToolbox();
-      this._results.push({name: name + ".close.DAMP", value: time });
-    }.bind(this));
+  async reloadPageAndLog(name) {
+    let {time} = await this.reloadPage();
+    this._results.push({name: name + ".reload.DAMP", value: time });
+  },
 
-    let reloadPageAndLog = Task.async(function* (name) {
-      let {time} = yield this.reloadPage();
-      this._results.push({name: name + ".reload.DAMP", value: time });
-    }.bind(this));
+  async _coldInspectorOpen(url) {
+    await this.testSetup(url);
+    await this.openToolboxAndLog("cold.inspector", "inspector");
+    await this.closeToolbox();
+    await this.testTeardown();
+  },
 
+  _getToolLoadingTests(url, label) {
     let subtests = {
-      webconsoleOpen: Task.async(function* () {
+      inspectorOpen: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".webconsole", "webconsole");
-        yield reloadPageAndLog(label + ".webconsole");
-        yield closeToolboxAndLog(label + ".webconsole");
+        yield this.openToolboxAndLog(label + ".inspector", "inspector");
+        yield this.reloadPageAndLog(label + ".inspector");
+        yield this.closeToolboxAndLog(label + ".inspector");
         yield this.testTeardown();
       }),
 
-      inspectorOpen: Task.async(function* () {
+      webconsoleOpen: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".inspector", "inspector");
-        yield reloadPageAndLog(label + ".inspector");
-        yield closeToolboxAndLog(label + ".inspector");
+        yield this.openToolboxAndLog(label + ".webconsole", "webconsole");
+        yield this.reloadPageAndLog(label + ".webconsole");
+        yield this.closeToolboxAndLog(label + ".webconsole");
         yield this.testTeardown();
       }),
 
       debuggerOpen: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".jsdebugger", "jsdebugger");
-        yield reloadPageAndLog(label + ".jsdebugger");
-        yield closeToolboxAndLog(label + ".jsdebugger");
+        yield this.openToolboxAndLog(label + ".jsdebugger", "jsdebugger");
+        yield this.reloadPageAndLog(label + ".jsdebugger");
+        yield this.closeToolboxAndLog(label + ".jsdebugger");
         yield this.testTeardown();
       }),
 
       styleEditorOpen: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".styleeditor", "styleeditor");
-        yield reloadPageAndLog(label + ".styleeditor");
-        yield closeToolboxAndLog(label + ".styleeditor");
+        yield this.openToolboxAndLog(label + ".styleeditor", "styleeditor");
+        yield this.reloadPageAndLog(label + ".styleeditor");
+        yield this.closeToolboxAndLog(label + ".styleeditor");
         yield this.testTeardown();
       }),
 
       performanceOpen: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".performance", "performance");
-        yield reloadPageAndLog(label + ".performance");
-        yield closeToolboxAndLog(label + ".performance");
+        yield this.openToolboxAndLog(label + ".performance", "performance");
+        yield this.reloadPageAndLog(label + ".performance");
+        yield this.closeToolboxAndLog(label + ".performance");
         yield this.testTeardown();
       }),
 
       netmonitorOpen: Task.async(function* () {
         yield this.testSetup(url);
-        const toolbox = yield openToolboxAndLog(label + ".netmonitor", "netmonitor");
+        const toolbox = yield this.openToolboxAndLog(label + ".netmonitor", "netmonitor");
         const requestsDone = this.waitForNetworkRequests(label + ".netmonitor", toolbox);
-        yield reloadPageAndLog(label + ".netmonitor");
+        yield this.reloadPageAndLog(label + ".netmonitor");
         yield requestsDone;
-        yield closeToolboxAndLog(label + ".netmonitor");
+        yield this.closeToolboxAndLog(label + ".netmonitor");
         yield this.testTeardown();
       }),
 
       saveAndReadHeapSnapshot: Task.async(function* () {
         yield this.testSetup(url);
-        yield openToolboxAndLog(label + ".memory", "memory");
-        yield reloadPageAndLog(label + ".memory");
+        yield this.openToolboxAndLog(label + ".memory", "memory");
+        yield this.reloadPageAndLog(label + ".memory");
         yield this.saveHeapSnapshot(label);
         yield this.readHeapSnapshot(label);
         yield this.takeCensus(label);
-        yield closeToolboxAndLog(label + ".memory");
+        yield this.closeToolboxAndLog(label + ".memory");
         yield this.testTeardown();
       }),
     };
 
     // Construct the sequence array: config.repeat times config.subtests
     let config = this._config;
     let sequenceArray = [];
     for (var i in config.subtests) {
@@ -460,17 +482,17 @@ Damp.prototype = {
    *   already in mid-flight will be ignored.
    * - the request start and end times are overlapping. If a new request starts a moment
    *   after the previous one was finished, the wait will be ended in the "interim"
    *   period.
    * @returns a promise that resolves when the wait is done.
    */
   waitForAllRequestsFinished() {
     let tab = getActiveTab(getMostRecentBrowserWindow());
-    let target = devtools.TargetFactory.forTab(tab);
+    let target = TargetFactory.forTab(tab);
     let toolbox = gDevTools.getToolbox(target);
     let window = toolbox.getCurrentPanel().panelWin;
 
     return new Promise(resolve => {
       // Key is the request id, value is a boolean - is request finished or not?
       let requests = new Map();
 
       function onRequest(_, id) {
@@ -510,16 +532,26 @@ Damp.prototype = {
     var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
     this._win = wm.getMostRecentWindow("navigator:browser");
     this._dampTab = this._win.gBrowser.selectedTab;
     this._win.gBrowser.selectedBrowser.focus(); // Unfocus the URL bar to avoid caret blink
 
     TalosParentProfiler.resume("DAMP - start");
 
     let tests = [];
+
+    if (config.subtests.indexOf("inspectorOpen") > -1) {
+      // Run cold test only once
+      let topWindow = getMostRecentBrowserWindow();
+      if (!topWindow.coldRunDAMP) {
+        topWindow.coldRunDAMP = true;
+        tests = tests.concat(this._coldInspectorOpen);
+      }
+    }
+
     tests = tests.concat(this._getToolLoadingTests(SIMPLE_URL, "simple"));
     tests = tests.concat(this._getToolLoadingTests(COMPLICATED_URL, "complicated"));
 
     if (config.subtests.indexOf("consoleBulkLogging") > -1) {
       tests = tests.concat(this._consoleBulkLoggingTest);
     }
     if (config.subtests.indexOf("consoleStreamLogging") > -1) {
       tests = tests.concat(this._consoleStreamLoggingTest);
index e286f6ac1dce793a3f02075b9e6e3560a7f5debc..5154fc5b7cd1c6bb9be250503bd914c58e03af77
GIT binary patch
literal 18066
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
Pu=6qW1Fe1Q2;u<%Q>RBX
--- a/testing/talos/talos/tests/devtools/addon/install.rdf
+++ b/testing/talos/talos/tests/devtools/addon/install.rdf
@@ -1,14 +1,14 @@
 <?xml version="1.0"?><RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"     xmlns:em="http://www.mozilla.org/2004/em-rdf#"><Description about="urn:mozilla:install-manifest">
 
 <!-- Required Items -->
 <em:id>bug1150215@mozilla.org</em:id>
 <em:name>DAMP - Devtools At Maximum Performance</em:name>
-<em:version>0.0.13</em:version>
+<em:version>0.0.15</em:version>
 
 <em:targetApplication>
     <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
     </Description>
 </em:targetApplication>
new file mode 100644
--- /dev/null
+++ b/testing/talos/talos/tests/perf-reftest/.eslintrc.json
@@ -0,0 +1,6 @@
+{
+    "rules": {
+        "no-undef": "off"
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/testing/talos/talos/tests/perf-reftest/bloom-basic-2.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <script src="util.js"></script>
+    <script>
+window.onload = function() {
+  /* Use many rules, instead of one rule with many selectors, to test per-rule overhead. */
+  document.head.appendChild(build_rule("caption div, caption span", 1, "{ color: blue; } ", 20000));
+  let dom = build_dom(5000, "div");
+
+  flush_style();
+  perf_start();
+  document.body.appendChild(dom);
+  flush_style(dom);
+  perf_finish();
+}
+    </script>
+  </head>
+  <body>
+  </body>
+</html>
--- a/testing/talos/talos/tests/perf-reftest/bloom-basic-ref.html
+++ b/testing/talos/talos/tests/perf-reftest/bloom-basic-ref.html
@@ -1,34 +1,20 @@
 <!DOCTYPE html>
 <html>
   <head>
     <script src="util.js"></script>
-    <script src="chrome://talos-powers-content/content/TalosContentProfiler.js"></script>
     <script>
-/* import-globals-from util.js */